- name: mingw-check
os: ubuntu-latest-xl
env: {}
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
os: ubuntu-latest-xl
env: {}
- name: x86_64-gnu-tools
- name: install sccache
run: src/ci/scripts/install-sccache.sh
if: success() && !env.SKIP_JOB
- - name: select Xcode
- run: src/ci/scripts/select-xcode.sh
- if: success() && !env.SKIP_JOB
- name: install clang
run: src/ci/scripts/install-clang.sh
if: success() && !env.SKIP_JOB
- name: x86_64-gnu-distcheck
os: ubuntu-latest-xl
env: {}
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
env:
RUST_BACKTRACE: 1
os: ubuntu-latest-xl
os: ubuntu-latest-xl
- name: dist-x86_64-apple
env:
- SCRIPT: "./x.py dist"
+ SCRIPT: "./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended"
RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
os: macos-latest
- name: dist-x86_64-apple-alt
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
os: macos-latest
- name: x86_64-apple
env:
MACOSX_STD_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
os: macos-latest
- name: dist-aarch64-apple
env:
SCRIPT: "./x.py dist --stage 2"
RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- SELECT_XCODE: /Applications/Xcode_12.2.app
USE_XCODE_CLANG: 1
MACOSX_DEPLOYMENT_TARGET: 11.0
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
JEMALLOC_SYS_WITH_LG_PAGE: 14
os: macos-latest
- name: install sccache
run: src/ci/scripts/install-sccache.sh
if: success() && !env.SKIP_JOB
- - name: select Xcode
- run: src/ci/scripts/select-xcode.sh
- if: success() && !env.SKIP_JOB
- name: install clang
run: src/ci/scripts/install-clang.sh
if: success() && !env.SKIP_JOB
- name: install sccache
run: src/ci/scripts/install-sccache.sh
if: success() && !env.SKIP_JOB
- - name: select Xcode
- run: src/ci/scripts/select-xcode.sh
- if: success() && !env.SKIP_JOB
- name: install clang
run: src/ci/scripts/install-clang.sh
if: success() && !env.SKIP_JOB
Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
+Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
Heather <heather@cynede.net> <Cynede@Gentoo.org>
Heather <heather@cynede.net> <Heather@cynede.net>
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
+[[package]]
+name = "camino"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "cargo"
-version = "0.58.0"
+version = "0.59.0"
dependencies = [
"anyhow",
"atty",
"bytesize",
- "cargo-platform",
+ "cargo-platform 0.1.2",
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
"serde",
]
+[[package]]
+name = "cargo-platform"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "cargo-test-macro"
version = "0.1.0"
[[package]]
name = "cargo_metadata"
-version = "0.8.2"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
dependencies = [
- "semver 0.9.0",
+ "semver 0.11.0",
"serde",
- "serde_derive",
"serde_json",
]
[[package]]
name = "cargo_metadata"
-version = "0.12.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
dependencies = [
- "semver 0.11.0",
+ "camino",
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 1.0.3",
"serde",
"serde_json",
]
[[package]]
name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
"clippy_lints",
"clippy_utils",
"compiletest_rs",
"regex",
"rustc-workspace-hack",
"rustc_tools_util 0.2.0",
- "semver 0.11.0",
+ "semver 1.0.3",
"serde",
"syn",
"tempfile",
dependencies = [
"bytecount",
"clap",
+ "indoc",
"itertools 0.10.1",
"opener",
"regex",
[[package]]
name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
"clippy_utils",
"if_chain",
"itertools 0.10.1",
"quine-mc_cluskey",
"regex-syntax",
"rustc-semver",
- "semver 0.11.0",
+ "semver 1.0.3",
"serde",
"serde_json",
"toml",
[[package]]
name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
"if_chain",
"rustc-semver",
[[package]]
name = "compiletest_rs"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca"
+checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83"
dependencies = [
"diff",
"filetime",
[[package]]
name = "env_logger"
-version = "0.6.2"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime 1.3.0",
[[package]]
name = "env_logger"
-version = "0.7.1"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"atty",
- "humantime 1.3.0",
+ "humantime 2.0.1",
"log",
"regex",
"termcolor",
"serde",
]
+[[package]]
+name = "indoc"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
+dependencies = [
+ "unindent",
+]
+
[[package]]
name = "installer"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
-[[package]]
-name = "itertools"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itertools"
version = "0.9.0"
[[package]]
name = "libc"
-version = "0.2.103"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
+checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
dependencies = [
"rustc-std-workspace-core",
]
"smallvec",
]
+[[package]]
+name = "measureme"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd460fad6e55ca82fa0cd9dab0d315294188fd9ec6efbf4105e5635d4872ef9c"
+dependencies = [
+ "log",
+ "memmap2",
+ "parking_lot",
+ "perf-event-open-sys",
+ "rustc-hash",
+ "smallvec",
+]
+
[[package]]
name = "memchr"
version = "2.4.1"
"hex 0.4.2",
"libc",
"log",
- "measureme",
+ "measureme 9.1.2",
"rand 0.8.4",
"rustc-workspace-hack",
"rustc_version 0.4.0",
[[package]]
name = "odht"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2504d29fda40b3f2f9ef525392435ab660e407c188196cb664b116ebcca0142"
+checksum = "5a518809ac14b25b569624d0268eba1e88498f71615893dca57982bed7621abb"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
dependencies = [
"unicode-xid",
]
"indexmap",
"jobserver",
"libc",
- "measureme",
+ "measureme 9.1.2",
"memmap2",
"parking_lot",
"rustc-ap-rustc_graphviz",
"rustc_errors",
"rustc_hir",
"rustc_index",
+ "rustc_query_system",
"rustc_session",
"rustc_span",
"rustc_target",
"bitflags",
"cstr",
"libc",
- "measureme",
+ "measureme 10.0.0",
"rustc-demangle",
"rustc_arena",
"rustc_ast",
"indexmap",
"jobserver",
"libc",
- "measureme",
+ "measureme 10.0.0",
"memmap2",
"parking_lot",
"rustc-hash",
"polonius-engine",
"rand 0.8.4",
"rand_xoshiro 0.6.0",
+ "rustc-rayon",
"rustc-rayon-core",
"rustc_apfloat",
"rustc_arena",
"rustc_span",
"tracing",
"unicode-normalization",
+ "unicode-width",
]
[[package]]
name = "rustc_query_impl"
version = "0.0.0"
dependencies = [
- "measureme",
+ "measureme 10.0.0",
"rustc-rayon-core",
"rustc_ast",
"rustc_data_structures",
"rustc_serialize",
"rustc_session",
"rustc_span",
- "tracing",
]
[[package]]
"rustc_index",
"rustc_metadata",
"rustc_middle",
+ "rustc_query_system",
"rustc_session",
"rustc_span",
"smallvec",
"itertools 0.9.0",
"minifier",
"pulldown-cmark 0.8.0",
+ "rayon",
"regex",
- "rustc-rayon",
"rustdoc-json-types",
"serde",
"serde_json",
[[package]]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
- "cargo_metadata 0.8.2",
+ "cargo_metadata 0.14.0",
"derive-new",
"diff",
"dirs",
- "env_logger 0.6.2",
+ "env_logger 0.8.4",
"getopts",
"ignore",
- "itertools 0.8.2",
+ "itertools 0.9.0",
"lazy_static",
"log",
"regex",
"libc",
]
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser 0.7.0",
- "serde",
-]
-
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
- "semver-parser 0.10.2",
+ "semver-parser",
"serde",
]
"serde",
]
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
[[package]]
name = "semver-parser"
version = "0.10.2"
[[package]]
name = "syn"
-version = "1.0.65"
+version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
+checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
"diff",
]
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+
[[package]]
name = "unstable-book-gen"
version = "0.1.0"
# per-crate configuration isn't specifiable in the environment.
codegen-units = 10000
+[profile.release.package.rustc-rayon-core]
+# The rustc fork of Rayon has deadlock detection code which intermittently
+# causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227)
+# so we turn overflow checks off for now.
+# FIXME: This workaround should be removed once #90227 is fixed.
+overflow-checks = false
+
# These dependencies of the standard library implement symbolication for
# backtraces on most platforms. Their debuginfo causes both linking to be slower
# (more data to chew through) and binaries to be larger without really all that
+Version 1.56.1 (2021-11-01)
+===========================
+
+- New lints to detect the presence of bidirectional-override Unicode
+ codepoints in the compiled source code ([CVE-2021-42574])
+
+[CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574
+
Version 1.56.0 (2021-10-21)
========================
- [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`]
This has no effect at present on dependency version selection.
We encourage crates to specify their minimum supported Rust version, and we encourage CI systems
- that support Rust code to include a crate's specified minimum version in the text matrix for that
+ that support Rust code to include a crate's specified minimum version in the test matrix for that
crate by default.
Compatibility notes
let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
// Change the exponent from 2^e to 10^e.
- #[allow(clippy::comparison_chain)]
if exp == 0 {
// Nothing to do.
} else if exp > 0 {
if *a_sign ^ b_sign {
let (reverse, loss);
- #[allow(clippy::comparison_chain)]
if bits == 0 {
reverse = cmp(a_sig, b_sig) == Ordering::Less;
loss = Loss::ExactlyZero;
The `rustc_ast` crate contains those things concerned purely with syntax
-– that is, the AST ("abstract syntax tree"), parser, pretty-printer,
-lexer, macro expander, and utilities for traversing ASTs.
+– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion).
For more information about how these things work in rustc, see the
rustc dev guide:
self.meta_item().and_then(|meta_item| meta_item.ident())
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
/// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
}
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
pub fn value_str(&self) -> Option<Symbol> {
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
}
pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::invalid).name
+ self.ident().unwrap_or_else(Ident::empty).name
}
// Example:
-//! The Rust parser and macro expander.
+//! The Rust Abstract Syntax Tree (AST).
//!
//! # Note
//!
/// Mutable token visiting only exists for the `macro_rules` token marker and should not be
/// used otherwise. Token visitor would be entirely separate from the regular visitor if
/// the marker didn't have to visit AST fragments in nonterminal tokens.
- fn token_visiting_enabled(&self) -> bool {
- false
- }
+ const VISIT_TOKENS: bool = false;
// Methods in this trait have one of three forms:
//
}
MacArgs::Eq(eq_span, token) => {
vis.visit_span(eq_span);
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
visit_token(token, vis);
} else {
// The value in `#[key = VALUE]` must be visited as an expression for backward
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
}
AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
vis: &mut T,
) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
}
}
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
if let Some(lazy_tts) = lazy_tts {
let mut tts = lazy_tts.create_token_stream();
visit_attr_annotated_tts(&mut tts, vis);
let item_vis =
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
let item = P(Item {
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs,
id: DUMMY_NODE_ID,
vis: item_vis,
for attr in &data.attrs {
match attr.style {
crate::AttrStyle::Outer => {
- assert!(
- inner_attrs.len() == 0,
- "Found outer attribute {:?} after inner attrs {:?}",
- attr,
- inner_attrs
- );
outer_attrs.push(attr);
}
crate::AttrStyle::Inner => {
}
}
-/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
+/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
AssocOp::LAnd.precedence()
}
/// Suppose we have `let _ = e` and the `order` of `e`.
-/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
+/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
rustc_target = { path = "../rustc_target" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }
+rustc_query_system = { path = "../rustc_query_system" }
rustc_span = { path = "../rustc_span" }
rustc_errors = { path = "../rustc_errors" }
rustc_session = { path = "../rustc_session" }
impl<'a, 'hir> LoweringContext<'a, 'hir> {
crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
- // Rustdoc needs to support asm! from foriegn architectures: don't try
- // lowering the register contraints in this case.
+ // Rustdoc needs to support asm! from foreign architectures: don't try
+ // lowering the register constraints in this case.
let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
- if reg_class.is_clobber_only(asm_arch.unwrap())
- && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
- {
+ if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
let msg = format!(
"register class `{}` can only be used as a clobber, \
not as an input or output",
}
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
- let old_attrs = self.attrs.get(&ex.hir_id).map(|la| *la).unwrap_or(&[]);
+ let old_attrs =
+ self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
self.attrs.insert(
- ex.hir_id,
+ ex.hir_id.local_id,
&*self.arena.alloc_from_iter(
e.attrs
.iter()
body: &Block,
opt_label: Option<Label>,
) -> hir::Expr<'hir> {
- let orig_head_span = head.span;
// expand <head>
- let mut head = self.lower_expr_mut(head);
- let desugared_span = self.mark_span_with_reason(
- DesugaringKind::ForLoop(ForLoopLoc::Head),
- orig_head_span,
- None,
- );
- head.span = self.lower_span(desugared_span);
+ let head = self.lower_expr_mut(head);
+ let desugared_span =
+ self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
+ let e_span = self.lower_span(e.span);
let iter = Ident::with_dummy_span(sym::iter);
// `::std::option::Option::Some(val) => __next = val`
let pat_arm = {
let val_ident = Ident::with_dummy_span(sym::val);
- let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
- let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
- let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
+ let pat_span = self.lower_span(pat.span);
+ let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
+ let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
+ let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
let assign = self.arena.alloc(self.expr(
- pat.span,
- hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
+ pat_span,
+ hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
ThinVec::new(),
));
- let some_pat = self.pat_some(pat.span, val_pat);
+ let some_pat = self.pat_some(pat_span, val_pat);
self.arm(some_pat, assign)
};
// `::std::option::Option::None => break`
let break_arm = {
let break_expr =
- self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
- let pat = self.pat_none(e.span);
+ self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
+ let pat = self.pat_none(e_span);
self.arm(pat, break_expr)
};
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
let body_expr = self.expr_block(body_block, ThinVec::new());
- let body_stmt = self.stmt_expr(body.span, body_expr);
+ let body_stmt = self.stmt_expr(body_block.span, body_expr);
let loop_block = self.block_all(
- e.span,
+ e_span,
arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
None,
);
loop_block,
self.lower_label(opt_label),
hir::LoopSource::ForLoop,
- self.lower_span(e.span.with_hi(orig_head_span.hi())),
+ self.lower_span(e_span.with_hi(head.span.hi())),
);
let loop_expr = self.arena.alloc(hir::Expr {
hir_id: self.lower_node_id(e.id),
let into_iter_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
- orig_head_span,
+ head.span,
None,
);
// #82462: to correctly diagnose borrow errors, the block that contains
// the iter expr needs to have a span that covers the loop body.
let desugared_full_span =
- self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
+ self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
let match_expr = self.arena.alloc(self.expr_match(
desugared_full_span,
--- /dev/null
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::definitions;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::*;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_session::Session;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{Span, DUMMY_SP};
+
+use tracing::debug;
+
+/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
+pub(super) struct NodeCollector<'a, 'hir> {
+ /// Source map
+ source_map: &'a SourceMap,
+ bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
+
+ /// Outputs
+ nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
+ parenting: FxHashMap<LocalDefId, ItemLocalId>,
+
+ /// The parent of this node
+ parent_node: hir::ItemLocalId,
+
+ owner: LocalDefId,
+
+ definitions: &'a definitions::Definitions,
+}
+
+pub(super) fn index_hir<'hir>(
+ sess: &Session,
+ definitions: &definitions::Definitions,
+ item: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
+) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
+ let mut nodes = IndexVec::new();
+ // This node's parent should never be accessed: the owner's parent is computed by the
+ // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
+ // used.
+ nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
+ let mut collector = NodeCollector {
+ source_map: sess.source_map(),
+ definitions,
+ owner: item.def_id(),
+ parent_node: ItemLocalId::new(0),
+ nodes,
+ bodies,
+ parenting: FxHashMap::default(),
+ };
+
+ match item {
+ OwnerNode::Crate(citem) => collector.visit_mod(&citem, citem.inner, hir::CRATE_HIR_ID),
+ OwnerNode::Item(item) => collector.visit_item(item),
+ OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
+ OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
+ OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
+ };
+
+ (collector.nodes, collector.parenting)
+}
+
+impl<'a, 'hir> NodeCollector<'a, 'hir> {
+ fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
+ debug_assert_eq!(self.owner, hir_id.owner);
+ debug_assert_ne!(hir_id.local_id.as_u32(), 0);
+
+ // Make sure that the DepNode of some node coincides with the HirId
+ // owner of that node.
+ if cfg!(debug_assertions) {
+ if hir_id.owner != self.owner {
+ panic!(
+ "inconsistent DepNode at `{:?}` for `{:?}`: \
+ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
+ self.source_map.span_to_diagnostic_string(span),
+ node,
+ self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+ self.owner,
+ self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
+ hir_id.owner,
+ )
+ }
+ }
+
+ self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
+ }
+
+ fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
+ debug_assert_eq!(parent_node_id.owner, self.owner);
+ let parent_node = self.parent_node;
+ self.parent_node = parent_node_id.local_id;
+ f(self);
+ self.parent_node = parent_node;
+ }
+
+ fn insert_nested(&mut self, item: LocalDefId) {
+ self.parenting.insert(item, self.parent_node);
+ }
+}
+
+impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
+ type Map = !;
+
+ /// Because we want to track parent items and so forth, enable
+ /// deep walking so that we walk nested items in the context of
+ /// their outer items.
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ panic!("`visit_nested_xxx` must be manually implemented in this visitor");
+ }
+
+ fn visit_nested_item(&mut self, item: ItemId) {
+ debug!("visit_nested_item: {:?}", item);
+ self.insert_nested(item.def_id);
+ }
+
+ fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+ self.insert_nested(item_id.def_id);
+ }
+
+ fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+ self.insert_nested(item_id.def_id);
+ }
+
+ fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+ self.insert_nested(foreign_id.def_id);
+ }
+
+ fn visit_nested_body(&mut self, id: BodyId) {
+ debug_assert_eq!(id.hir_id.owner, self.owner);
+ let body = self.bodies[&id.hir_id.local_id];
+ self.visit_body(body);
+ }
+
+ fn visit_param(&mut self, param: &'hir Param<'hir>) {
+ let node = Node::Param(param);
+ self.insert(param.pat.span, param.hir_id, node);
+ self.with_parent(param.hir_id, |this| {
+ intravisit::walk_param(this, param);
+ });
+ }
+
+ fn visit_item(&mut self, i: &'hir Item<'hir>) {
+ debug!("visit_item: {:?}", i);
+ debug_assert_eq!(i.def_id, self.owner);
+ self.with_parent(i.hir_id(), |this| {
+ if let ItemKind::Struct(ref struct_def, _) = i.kind {
+ // If this is a tuple or unit-like struct, register the constructor.
+ if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+ this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
+ }
+ }
+ intravisit::walk_item(this, i);
+ });
+ }
+
+ fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
+ debug_assert_eq!(fi.def_id, self.owner);
+ self.with_parent(fi.hir_id(), |this| {
+ intravisit::walk_foreign_item(this, fi);
+ });
+ }
+
+ fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
+ self.insert(param.span, param.hir_id, Node::GenericParam(param));
+ intravisit::walk_generic_param(self, param);
+ }
+
+ fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
+ self.with_parent(param, |this| {
+ intravisit::walk_const_param_default(this, ct);
+ })
+ }
+
+ fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
+ debug_assert_eq!(ti.def_id, self.owner);
+ self.with_parent(ti.hir_id(), |this| {
+ intravisit::walk_trait_item(this, ti);
+ });
+ }
+
+ fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
+ debug_assert_eq!(ii.def_id, self.owner);
+ self.with_parent(ii.hir_id(), |this| {
+ intravisit::walk_impl_item(this, ii);
+ });
+ }
+
+ fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
+ let node =
+ if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
+ self.insert(pat.span, pat.hir_id, node);
+
+ self.with_parent(pat.hir_id, |this| {
+ intravisit::walk_pat(this, pat);
+ });
+ }
+
+ fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
+ let node = Node::Arm(arm);
+
+ self.insert(arm.span, arm.hir_id, node);
+
+ self.with_parent(arm.hir_id, |this| {
+ intravisit::walk_arm(this, arm);
+ });
+ }
+
+ fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
+ self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
+
+ self.with_parent(constant.hir_id, |this| {
+ intravisit::walk_anon_const(this, constant);
+ });
+ }
+
+ fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
+ self.insert(expr.span, expr.hir_id, Node::Expr(expr));
+
+ self.with_parent(expr.hir_id, |this| {
+ intravisit::walk_expr(this, expr);
+ });
+ }
+
+ fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
+ self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
+
+ self.with_parent(stmt.hir_id, |this| {
+ intravisit::walk_stmt(this, stmt);
+ });
+ }
+
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
+ if let Some(hir_id) = path_segment.hir_id {
+ self.insert(path_span, hir_id, Node::PathSegment(path_segment));
+ }
+ intravisit::walk_path_segment(self, path_span, path_segment);
+ }
+
+ fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
+ self.insert(ty.span, ty.hir_id, Node::Ty(ty));
+
+ self.with_parent(ty.hir_id, |this| {
+ intravisit::walk_ty(this, ty);
+ });
+ }
+
+ fn visit_infer(&mut self, inf: &'hir InferArg) {
+ self.insert(inf.span, inf.hir_id, Node::Infer(inf));
+
+ self.with_parent(inf.hir_id, |this| {
+ intravisit::walk_inf(this, inf);
+ });
+ }
+
+ fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
+ self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
+
+ self.with_parent(tr.hir_ref_id, |this| {
+ intravisit::walk_trait_ref(this, tr);
+ });
+ }
+
+ fn visit_fn(
+ &mut self,
+ fk: intravisit::FnKind<'hir>,
+ fd: &'hir FnDecl<'hir>,
+ b: BodyId,
+ s: Span,
+ id: HirId,
+ ) {
+ assert_eq!(self.owner, id.owner);
+ assert_eq!(self.parent_node, id.local_id);
+ intravisit::walk_fn(self, fk, fd, b, s, id);
+ }
+
+ fn visit_block(&mut self, block: &'hir Block<'hir>) {
+ self.insert(block.span, block.hir_id, Node::Block(block));
+ self.with_parent(block.hir_id, |this| {
+ intravisit::walk_block(this, block);
+ });
+ }
+
+ fn visit_local(&mut self, l: &'hir Local<'hir>) {
+ self.insert(l.span, l.hir_id, Node::Local(l));
+ self.with_parent(l.hir_id, |this| {
+ intravisit::walk_local(this, l);
+ })
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
+ self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
+ }
+
+ fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
+ match visibility.node {
+ VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
+ VisibilityKind::Restricted { hir_id, .. } => {
+ self.insert(visibility.span, hir_id, Node::Visibility(visibility));
+ self.with_parent(hir_id, |this| {
+ intravisit::walk_vis(this, visibility);
+ });
+ }
+ }
+ }
+
+ fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+ self.insert(v.span, v.id, Node::Variant(v));
+ self.with_parent(v.id, |this| {
+ // Register the constructor of this variant.
+ if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
+ this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
+ }
+ intravisit::walk_variant(this, v, g, item_id);
+ });
+ }
+
+ fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
+ self.insert(field.span, field.hir_id, Node::Field(field));
+ self.with_parent(field.hir_id, |this| {
+ intravisit::walk_field_def(this, field);
+ });
+ }
+
+ fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
+ // Do not visit the duplicate information in TraitItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+
+ self.visit_nested_trait_item(id);
+ }
+
+ fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
+ // Do not visit the duplicate information in ImplItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+
+ self.visit_nested_impl_item(id);
+ }
+
+ fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
+ // Do not visit the duplicate information in ForeignItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let ForeignItemRef { id, ident: _, span: _ } = *fi;
+
+ self.visit_nested_foreign_item(id);
+ }
+}
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::Idx;
use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
) -> T {
let old_len = self.in_scope_lifetimes.len();
- let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind {
- hir::ItemKind::Impl(hir::Impl { ref generics, .. })
- | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
- _ => &[],
- };
+ let parent_generics =
+ match self.owners[parent_hir_id].as_ref().unwrap().node().expect_item().kind {
+ hir::ItemKind::Impl(hir::Impl { ref generics, .. })
+ | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
+ _ => &[],
+ };
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
_ => None,
let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
let vis = this.rebuild_vis(&vis);
if let Some(attrs) = attrs {
- this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
let item = hir::Item {
let kind =
this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
if let Some(attrs) = attrs {
- this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
}
let item = hir::Item {
) -> hir::BodyId {
let body = hir::Body { generator_kind: self.generator_kind, params, value };
let id = body.id();
- self.bodies.insert(id, body);
+ debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
+ self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
id
}
//
// If this is the simple case, this parameter will end up being the same as the
// original parameter, but with a different pattern id.
- let stmt_attrs = this.attrs.get(¶meter.hir_id).copied();
+ let stmt_attrs = this.attrs.get(¶meter.hir_id.local_id).copied();
let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
let new_parameter = hir::Param {
hir_id: parameter.hir_id,
#![feature(crate_visibility_modifier)]
#![feature(box_patterns)]
#![feature(iter_zip)]
+#![feature(never_type)]
#![recursion_limit = "256"]
-use rustc_ast::node_id::NodeMap;
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_ast::visit;
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fingerprint::Fingerprint;
+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::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
-use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
+use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use tracing::{debug, trace};
macro_rules! arena_vec {
mod asm;
mod block;
mod expr;
+mod index;
mod item;
mod pat;
mod path;
arena: &'hir Arena<'hir>,
/// The items being lowered are collected here.
- owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
- bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
+ owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
+ /// Bodies inside the owner being lowered.
+ bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
+ /// Attributes inside the owner being lowered.
+ attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
generator_kind: Option<hir::GeneratorKind>,
- attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
-
/// When inside an `async` context, this is the `HirId` of the
/// `task_context` local bound to the resume argument of the generator.
task_context: Option<hir::HirId>,
item_local_id_counter: hir::ItemLocalId,
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
+ /// NodeIds that are lowered inside the current HIR owner.
+ local_node_ids: Vec<NodeId>,
+
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
}
/// This should only return `None` during testing.
fn definitions(&mut self) -> &mut Definitions;
+ fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
+
fn lint_buffer(&mut self) -> &mut LintBuffer;
fn next_node_id(&mut self) -> NodeId;
- fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
+ fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>;
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
) -> LocalDefId;
}
-struct LoweringHasher<'a> {
- source_map: CachingSourceMapView<'a>,
- resolver: &'a dyn ResolverAstLowering,
-}
-
-impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
- #[inline]
- fn hash_spans(&self) -> bool {
- true
- }
-
- #[inline]
- fn def_span(&self, id: LocalDefId) -> Span {
- self.resolver.def_span(id)
- }
-
- #[inline]
- fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
- self.resolver.def_path_hash(def_id)
- }
-
- #[inline]
- fn span_data_to_lines_and_cols(
- &mut self,
- span: &rustc_span::SpanData,
- ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
- {
- self.source_map.span_data_to_lines_and_cols(span)
- }
-}
-
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
#[derive(Debug)]
) -> &'hir hir::Crate<'hir> {
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
+ let owners = IndexVec::from_fn_n(|_| None, resolver.definitions().def_index_count());
LoweringContext {
sess,
resolver,
nt_to_tokenstream,
arena,
- owners: IndexVec::default(),
- bodies: BTreeMap::new(),
- attrs: BTreeMap::default(),
+ owners,
+ bodies: Vec::new(),
+ attrs: SortedMap::new(),
catch_scope: None,
loop_scope: None,
is_in_loop_condition: false,
current_hir_id_owner: CRATE_DEF_ID,
item_local_id_counter: hir::ItemLocalId::new(0),
node_id_to_hir_id: IndexVec::new(),
+ local_node_ids: Vec::new(),
generator_kind: None,
task_context: None,
current_item: None,
hir::OwnerNode::Crate(lctx.arena.alloc(module))
});
- let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
- for (k, v) in self.resolver.take_trait_map().into_iter() {
- if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
- let map = trait_map.entry(hir_id.owner).or_default();
- map.insert(hir_id.local_id, v.into_boxed_slice());
- }
- }
+ let hir_hash = self.compute_hir_hash();
let mut def_id_to_hir_id = IndexVec::default();
self.resolver.definitions().init_def_id_to_hir_id_mapping(def_id_to_hir_id);
- #[cfg(debug_assertions)]
- for (&id, attrs) in self.attrs.iter() {
- // Verify that we do not store empty slices in the map.
- if attrs.is_empty() {
- panic!("Stored empty attributes for {:?}", id);
- }
- }
-
- let krate =
- hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
+ let krate = hir::Crate { owners: self.owners, hir_hash };
self.arena.alloc(krate)
}
- fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
- LoweringHasher {
- source_map: CachingSourceMapView::new(self.sess.source_map()),
- resolver: self.resolver,
- }
+ /// Compute the hash for the HIR of the full crate.
+ /// This hash will then be part of the crate_hash which is stored in the metadata.
+ fn compute_hir_hash(&mut self) -> Fingerprint {
+ let definitions = self.resolver.definitions();
+ let mut hir_body_nodes: Vec<_> = self
+ .owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let info = info.as_ref()?;
+ let def_path_hash = definitions.def_path_hash(def_id);
+ Some((def_path_hash, info))
+ })
+ .collect();
+ hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+
+ let mut stable_hasher = StableHasher::new();
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
}
fn with_hir_id_owner(
) -> LocalDefId {
let def_id = self.resolver.local_def_id(owner);
- // Always allocate the first `HirId` for the owner itself.
- let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
- debug_assert_eq!(_old, None);
-
+ let current_attrs = std::mem::take(&mut self.attrs);
+ let current_bodies = std::mem::take(&mut self.bodies);
+ let current_node_ids = std::mem::take(&mut self.local_node_ids);
let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
let current_local_counter =
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
+ // Always allocate the first `HirId` for the owner itself.
+ let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
+ debug_assert_eq!(_old, None);
+ self.local_node_ids.push(owner);
+
let item = f(self);
+ debug_assert_eq!(def_id, item.def_id());
+ let info = self.make_owner_info(item);
+ self.attrs = current_attrs;
+ self.bodies = current_bodies;
+ self.local_node_ids = current_node_ids;
self.current_hir_id_owner = current_owner;
self.item_local_id_counter = current_local_counter;
- let _old = self.owners.insert(def_id, item);
+ let _old = self.owners.insert(def_id, info);
debug_assert!(_old.is_none());
def_id
}
+ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
+ let attrs = std::mem::take(&mut self.attrs);
+ let mut bodies = std::mem::take(&mut self.bodies);
+ let local_node_ids = std::mem::take(&mut self.local_node_ids);
+ let trait_map = local_node_ids
+ .into_iter()
+ .filter_map(|node_id| {
+ let hir_id = self.node_id_to_hir_id[node_id]?;
+ let traits = self.resolver.take_trait_map(node_id)?;
+ Some((hir_id.local_id, traits.into_boxed_slice()))
+ })
+ .collect();
+
+ #[cfg(debug_assertions)]
+ for (id, attrs) in attrs.iter() {
+ // Verify that we do not store empty slices in the map.
+ if attrs.is_empty() {
+ panic!("Stored empty attributes for {:?}", id);
+ }
+ }
+
+ bodies.sort_by_key(|(k, _)| *k);
+ let bodies = SortedMap::from_presorted_elements(bodies);
+ let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
+ let (nodes, parenting) =
+ index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
+ let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
+ let attrs = {
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ let mut stable_hasher = StableHasher::new();
+ attrs.hash_stable(&mut hcx, &mut stable_hasher);
+ let hash = stable_hasher.finish();
+ hir::AttributeMap { map: attrs, hash }
+ };
+
+ hir::OwnerInfo { nodes, parenting, attrs, trait_map }
+ }
+
+ /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
+ /// queries which depend on the full HIR tree and those which only depend on the item signature.
+ fn hash_owner(
+ &mut self,
+ node: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
+ ) -> (Fingerprint, Fingerprint) {
+ let mut hcx = self.resolver.create_stable_hashing_context();
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_including_bodies = stable_hasher.finish();
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_without_bodies = stable_hasher.finish();
+ (hash_including_bodies, hash_without_bodies)
+ }
+
/// This method allocates a new `HirId` for the given `NodeId` and stores it in
/// the `LoweringContext`'s `NodeId => HirId` map.
/// Take care not to call this method if the resulting `HirId` is then not
let owner = self.current_hir_id_owner;
let local_id = self.item_local_id_counter;
self.item_local_id_counter.increment_by(1);
+ self.local_node_ids.push(ast_node_id);
hir::HirId { owner, local_id }
})
}
allow_internal_unstable,
reason,
self.sess.edition(),
- self.create_stable_hashing_context(),
+ self.resolver.create_stable_hashing_context(),
)
}
if attrs.is_empty() {
None
} else {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
debug_assert!(!ret.is_empty());
- self.attrs.insert(id, ret);
+ self.attrs.insert(id.local_id, ret);
Some(ret)
}
}
}
fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
- if let Some(&a) = self.attrs.get(&target_id) {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
+ debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
+ if let Some(&a) = self.attrs.get(&target_id.local_id) {
debug_assert!(!a.is_empty());
- self.attrs.insert(id, a);
+ self.attrs.insert(id.local_id, a);
}
}
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
def_id: opaque_ty_id,
- ident: Ident::invalid(),
+ ident: Ident::empty(),
kind: opaque_ty_item_kind,
vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
span: self.lower_span(opaque_ty_span),
let hir_id = self.next_id();
if let Some(a) = attrs {
debug_assert!(!a.is_empty());
- self.attrs.insert(hir_id, a);
+ self.attrs.insert(hir_id.local_id, a);
}
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
if sess.opts.unstable_features.is_nightly_build() {
sess.struct_span_err(expr.span, "`let` expressions are not supported here")
.note("only supported directly in conditions of `if`- and `while`-expressions")
- .note("as well as when nested within `&&` and parenthesis in those conditions")
+ .note("as well as when nested within `&&` and parentheses in those conditions")
.emit();
} else {
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
- // Does `expr` need parenthesis when printed in a condition position?
+ // Does `expr` need parentheses when printed in a condition position?
//
// These cases need parens due to the parse error observed in #26461: `if return {}`
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
/// Valid repr contents: any of the primitive integral type names (see
/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
/// the same discriminant size that the corresponding C enum would or C
-/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
+/// structure layout, `packed` to remove padding, and `transparent` to delegate representation
/// concerns to the only non-ZST field.
pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
use ReprAttr::*;
use std::fmt;
use std::ops::Index;
-crate struct BorrowSet<'tcx> {
+pub struct BorrowSet<'tcx> {
/// The fundamental map relating bitvector indexes to the borrows
/// in the MIR. Each borrow is also uniquely identified in the MIR
/// by the `Location` of the assignment statement in which it
/// appears on the right hand side. Thus the location is the map
/// key, and its position in the map corresponds to `BorrowIndex`.
- crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
+ pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
/// Locations which activate borrows.
/// NOTE: a given location may activate more than one borrow in the future
/// when more general two-phase borrow support is introduced, but for now we
/// only need to store one borrow index.
- crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+ pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
/// Map from local to all the borrows on that local.
- crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+ pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
crate locals_state_at_exit: LocalsStateAtExit,
}
/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-crate enum TwoPhaseActivation {
+pub enum TwoPhaseActivation {
NotTwoPhase,
NotActivated,
ActivatedAt(Location),
}
#[derive(Debug, Clone)]
-crate struct BorrowData<'tcx> {
+pub struct BorrowData<'tcx> {
/// Location where the borrow reservation starts.
/// In many cases, this will be equal to the activation location but not always.
- crate reserve_location: Location,
+ pub reserve_location: Location,
/// Location where the borrow is activated.
- crate activation_location: TwoPhaseActivation,
+ pub activation_location: TwoPhaseActivation,
/// What kind of borrow this is
- crate kind: mir::BorrowKind,
+ pub kind: mir::BorrowKind,
/// The region for which this borrow is live
- crate region: RegionVid,
+ pub region: RegionVid,
/// Place from which we are borrowing
- crate borrowed_place: mir::Place<'tcx>,
+ pub borrowed_place: mir::Place<'tcx>,
/// Place to which the borrow was stored
- crate assigned_place: mir::Place<'tcx>,
+ pub assigned_place: mir::Place<'tcx>,
}
impl<'tcx> fmt::Display for BorrowData<'tcx> {
}
}
-crate enum LocalsStateAtExit {
+pub enum LocalsStateAtExit {
AllAreInvalidated,
SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
}
// TEMP = &foo
//
// so extract `temp`.
- let temp = if let Some(temp) = assigned_place.as_local() {
- temp
- } else {
+ let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(start_location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
place_name, partially_str, loop_message
),
);
+ let sess = self.infcx.tcx.sess;
+ let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+ // If we have a `&mut` ref, we need to reborrow.
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+ // If we are in a loop this will be suggested later.
+ if !is_loop_move {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(
+ || "the mutable reference".to_string()
+ ),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ } else if let Ok(snippet) =
+ sess.source_map().span_to_snippet(move_span)
+ {
+ err.span_suggestion(
+ move_span,
+ "consider borrowing to avoid moving into the for loop",
+ format!("&{}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
} else {
err.span_label(
fn_call_span,
in_pattern = true;
}
}
-
- if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
- let sess = self.infcx.tcx.sess;
- let ty = used_place.ty(self.body, self.infcx.tcx).ty;
- // If we have a `&mut` ref, we need to reborrow.
- if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
- // If we are in a loop this will be suggested later.
- if !is_loop_move {
- err.span_suggestion_verbose(
- move_span.shrink_to_lo(),
- &format!(
- "consider creating a fresh reborrow of {} here",
- self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(|| "the mutable reference".to_string()),
- ),
- "&mut *".to_string(),
- Applicability::MachineApplicable,
- );
- }
- } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
- err.span_suggestion(
- move_span,
- "consider borrowing to avoid moving into the for loop",
- format!("&{}", snippet),
- Applicability::MaybeIncorrect,
- );
- }
- }
}
use_spans.var_span_label_path_only(
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{FnSelfUseKind, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
| ty::Opaque(def_id, _) => def_id,
_ => return err,
};
- let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
- let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
- if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
+ let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
+ if matches!(diag_name, Some(sym::Option | sym::Result))
+ && use_spans.map_or(true, |v| !v.for_closure())
+ {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &format!(
- "consider borrowing the `{}`'s content",
- if is_option { "Option" } else { "Result" }
- ),
+ &format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
".as_ref()".to_string(),
Applicability::MaybeIncorrect,
);
- } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
+ } else if let Some(UseSpans::FnSelfUse {
+ kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+ ..
+ }) = use_spans
+ {
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
type_known_to_meet_bound_modulo_regions(
let item_msg;
let reason;
let mut opt_source = None;
- let access_place_desc = self.describe_place(access_place.as_ref());
+ let access_place_desc = self.describe_any_place(access_place.as_ref());
debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
match the_place_err {
PlaceRef { local, projection: [] } => {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
if access_place.as_local().is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
// If we deref an immutable ref then the suggestion here doesn't help.
return;
} else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_for_guard() =>
{
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
reason = ", as it is immutable for the pattern guard".to_string();
}
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_to_static() =>
{
if access_place.projection.len() == 1 {
- item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
+ item_msg = format!("immutable static item {}", access_place_desc);
reason = String::new();
} else {
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
let local_info = &self.body.local_decls[local].local_info;
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
let static_name = &self.infcx.tcx.item_name(def_id);
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
- item_msg = format!("`{}`", access_place_desc.unwrap());
+ item_msg = access_place_desc;
debug_assert!(
self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
);
});
let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
opt_source = Some(source);
- if let Some(desc) = access_place_desc {
+ if let Some(desc) = self.describe_place(access_place.as_ref()) {
item_msg = format!("`{}`", desc);
reason = match error_access {
AccessKind::Mutate => format!(", which is behind {}", pointer_type),
let mut unified_already = FxHashSet::default();
for (fr, outlived) in &self.constraints_to_add {
- let fr_name = if let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) {
- fr_name
- } else {
+ let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else {
continue;
};
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
use self::path_utils::*;
-mod borrow_set;
+pub mod borrow_set;
mod borrowck_errors;
mod constraint_generation;
mod constraints;
// them down.
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
+ // Convert to the SCC representative: sometimes we have inference
+ // variables in the member constraint that wind up equated with
+ // universal regions. The scc representative is the minimal numbered
+ // one from the corresponding scc so it will be the universal region
+ // if one exists.
+ for c_r in &mut choice_regions {
+ let scc = self.constraint_sccs.scc(*c_r);
+ *c_r = self.scc_representatives[scc];
+ }
+
// The 'member region' in a member constraint is part of the
// hidden type, which must be in the root universe. Therefore,
// it cannot have any placeholders in its value.
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}))),
locations,
category,
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
use rustc_infer::infer::outlives;
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
use crate::{
- nll::ToRegionVid,
type_check::constraint_conversion,
type_check::{Locations, MirTypeckRegionConstraints},
universal_regions::UniversalRegions,
}
}
}
-
-/// This trait is used by the `impl-trait` constraint code to abstract
-/// over the `FreeRegionMap` from lexical regions and
-/// `UniversalRegions` (from NLL)`.
-impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
- fn sub_free_regions(
- &self,
- _tcx: TyCtxt<'tcx>,
- shorter: ty::Region<'tcx>,
- longer: ty::Region<'tcx>,
- ) -> bool {
- let shorter = shorter.to_region_vid();
- assert!(self.universal_regions.is_universal_region(shorter));
- let longer = longer.to_region_vid();
- assert!(self.universal_regions.is_universal_region(longer));
- self.outlives(longer, shorter)
- }
-}
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
®ion_bound_pairs,
implicit_region_bound,
&mut borrowck_context,
- &universal_region_relations,
|mut cx| {
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
}
#[instrument(
- skip(
- infcx,
- body,
- promoted,
- region_bound_pairs,
- borrowck_context,
- universal_region_relations,
- extra
- ),
+ skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra),
level = "debug"
)]
fn type_check_internal<'a, 'tcx, R>(
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
) -> R {
let mut checker = TypeChecker::new(
region_bound_pairs,
implicit_region_bound,
borrowck_context,
- universal_region_relations,
);
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
}
struct BorrowCheckContext<'a, 'tcx> {
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
- universal_region_relations: &'a UniversalRegionRelations<'tcx>,
) -> Self {
let mut checker = Self {
infcx,
implicit_region_bound,
borrowck_context,
reported_errors: Default::default(),
- universal_region_relations,
};
checker.check_user_type_annotations();
checker
),
)?;
- let universal_region_relations = self.universal_region_relations;
-
// Finally, if we instantiated the anon types successfully, we
// have to solve any bounds (e.g., `-> impl Iterator` needs to
// prove that `T: Iterator` where `T` is the type we
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|infcx| {
- infcx.constrain_opaque_type(
- opaque_type_key,
- &opaque_decl,
- GenerateMemberConstraints::IfNoStaticBound,
- universal_region_relations,
- );
+ infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
Ok(InferOk { value: (), obligations: vec![] })
},
|| "opaque_type_map".to_string(),
Ok(args) => {
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
MacEager::items(smallvec![P(ast::Item {
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(inline_asm),
fn dummy_annotatable() -> Annotatable {
Annotatable::GenericParam(ast::GenericParam {
id: ast::DUMMY_NODE_ID,
- ident: Ident::invalid(),
+ ident: Ident::empty(),
attrs: Default::default(),
bounds: Default::default(),
is_placeholder: false,
cx.item(
self.span,
- Ident::invalid(),
+ Ident::empty(),
a,
ast::ItemKind::Impl(Box::new(ast::ImplKind {
unsafety,
let newitem = cx.item(
span,
- Ident::invalid(),
+ Ident::empty(),
attrs,
ItemKind::Impl(Box::new(ImplKind {
unsafety: ast::Unsafe::No,
let use_item = cx.item(
span,
- Ident::invalid(),
+ Ident::empty(),
vec![cx.attribute(cx.meta_word(span, sym::prelude_import))],
ast::ItemKind::Use(ast::UseTree {
prefix: cx.path(span, import_path),
tcx,
(backend_config.clone(), cgu.name()),
module_codegen,
- rustc_middle::dep_graph::hash_result,
+ Some(rustc_middle::dep_graph::hash_result),
);
if let Some((id, product)) = work_product {
true
}
- fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
let start_time = Instant::now();
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
- let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+ let (module, _) = tcx.dep_graph.with_task(
+ dep_node,
+ tcx,
+ cgu_name,
+ module_codegen,
+ Some(dep_graph::hash_result),
+ );
let time_to_codegen = start_time.elapsed();
drop(prof_timer);
// TODO(antoyo)
}
+ fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
+ // Unsupported.
+ }
+
+ fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+
+
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
// TODO(antoyo)
}
+ fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+
fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
}
bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
-measureme = "9.1.0"
+measureme = "10.0.0"
snap = "1"
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, AttributePlace};
-use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
}
fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
- // LLVM prior to version 12 has known miscompiles in the presence of
- // noalias attributes (see #54878). Only enable mutable noalias by
- // default for versions we believe to be safe.
- cx.tcx
- .sess
- .opts
- .debugging_opts
- .mutable_noalias
- .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
+ // LLVM prior to version 12 had known miscompiles in the presence of
+ // noalias attributes (see #54878), but we don't support earlier
+ // versions at all anymore. We now enable mutable noalias by default.
+ cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
}
impl ArgAttributesExt for ArgAttributes {
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty::Instance};
use rustc_span::{Pos, Span, Symbol};
use rustc_target::abi::*;
use rustc_target::asm::*;
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_target_supported = |reg_class: InlineAsmRegClass| {
for &(_, feature) in reg_class.supported_types(asm_arch) {
if let Some(feature) = feature {
- if self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+ let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+ let feature_name = Symbol::intern(feature);
+ if self.tcx.sess.target_features.contains(&feature_name)
+ || codegen_fn_attrs.target_features.contains(&feature_name)
{
return true;
}
let ffunction_sections =
sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
let fdata_sections = ffunction_sections;
+ let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
let code_model = to_llvm_code_model(sess.code_model());
use_softfp,
ffunction_sections,
fdata_sections,
+ funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
let start_time = Instant::now();
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
- let (module, _) =
- tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+ let (module, _) = tcx.dep_graph.with_task(
+ dep_node,
+ tcx,
+ cgu_name,
+ module_codegen,
+ Some(dep_graph::hash_result),
+ );
let time_to_codegen = start_time.elapsed();
// We assume that the cost to run LLVM on a CGU is proportional to
}
}
+ fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
+ let typeid_metadata = self.typeid_metadata(typeid);
+ let v = [self.const_usize(0), typeid_metadata];
+ unsafe {
+ llvm::LLVMGlobalSetMetadata(
+ function,
+ llvm::MD_type as c_uint,
+ llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+ self.cx.llcx,
+ v.as_ptr(),
+ v.len() as c_uint,
+ )),
+ )
+ }
+ }
+
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
+ unsafe {
+ llvm::LLVMMDStringInContext(
+ self.cx.llcx,
+ typeid.as_ptr() as *const c_char,
+ typeid.as_bytes().len() as c_uint,
+ )
+ }
+ }
+
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
}
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ if !self.fptoint_sat_broken_in_llvm() {
let src_ty = self.cx.val_ty(val);
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
}
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ if !self.fptoint_sat_broken_in_llvm() {
let src_ty = self.cx.val_ty(val);
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let mut target_data_layout = sess.target.data_layout.clone();
- if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
- target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
- }
if llvm_util::get_version() < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
}
+ if sess.is_sanitizer_cfi_enabled() {
+ // FIXME(rcvalle): Add support for non canonical jump tables.
+ let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
+ // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
+ // Warning behavior flag. Add support for specifying the behavior flag to
+ // LLVMRustAddModuleFlag.
+ llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+ }
+
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc {
match sess.opts.cg.control_flow_guard {
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
}
+ ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+
if self.sess().opts.debuginfo != DebugInfo::None {
ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
}
}
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
+ // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
+ // optimization pass replaces calls to this intrinsic with code to test type membership.
+ let i8p_ty = self.type_i8p();
+ let bitcast = self.bitcast(pointer, i8p_ty);
+ self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
+ }
+
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
self.call_intrinsic("llvm.va_start", &[va_list])
}
MD_nontemporal = 9,
MD_mem_parallel_loop_access = 10,
MD_nonnull = 11,
+ MD_type = 19,
}
/// LLVMRustAsmDialect
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+ pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+ pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
// Operations on constants of any type
pub fn LLVMConstNull(Ty: &Type) -> &Value;
pub fn LLVMDisposeMessage(message: *mut c_char);
- pub fn LLVMStartMultithreaded() -> Bool;
+ pub fn LLVMIsMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustGetLastError() -> *const c_char;
UseSoftFP: bool,
FunctionSections: bool,
DataSections: bool,
+ UniqueSectionNames: bool,
TrapUnreachable: bool,
Singlethread: bool,
AsmComments: bool,
use std::ptr;
use std::slice;
use std::str;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
-static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();
pub(crate) fn init(sess: &Session) {
unsafe {
// Before we touch LLVM, make sure that multithreading is enabled.
+ if llvm::LLVMIsMultithreaded() != 1 {
+ bug!("LLVM compiled without support for threads");
+ }
INIT.call_once(|| {
- if llvm::LLVMStartMultithreaded() != 1 {
- // use an extra bool to make sure that all future usage of LLVM
- // cannot proceed despite the Once not running more than once.
- POISONED.store(true, Ordering::SeqCst);
- }
-
configure_llvm(sess);
});
-
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
- }
}
}
fn require_inited() {
- INIT.call_once(|| bug!("llvm is not initialized"));
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
+ if !INIT.is_completed() {
+ bug!("LLVM is not initialized");
}
}
// Ref:
// - https://github.com/rust-lang/rust/issues/85351
// - https://reviews.llvm.org/D103167
- let llvm_version = llvm_util::get_version();
- if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
+ if llvm_util::get_version() < (13, 0, 0) {
add("-enable-machine-outliner=never", false);
}
("aarch64", "dpb2") => vec!["ccdp"],
("aarch64", "frintts") => vec!["fptoint"],
("aarch64", "fcma") => vec!["complxnum"],
+ ("aarch64", "pmuv3") => vec!["perfmon"],
(_, s) => vec![s],
}
}
// -Ctarget-features
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
- // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
- if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") {
- features.push("+outline-atomics".to_string());
- }
-
features
}
_ => {}
}
}
- let fmts = match fmts {
- Some(f) => f,
- None => return Err("could not find formats for rlibs".to_string()),
+ let Some(fmts) = fmts else {
+ return Err("could not find formats for rlibs".to_string());
};
for &cnum in crates {
match fmts.get(cnum.as_usize() - 1) {
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{SymbolName, TyCtxt};
providers.wasm_import_module_map = wasm_import_module_map;
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
}
}
if let Some(trait_ref) = trait_ref {
- push_item_name(tcx, trait_ref.skip_binder().def_id, true, &mut vtable_name);
+ let trait_ref =
+ tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
+ push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
visited.clear();
- push_generic_params_internal(
- tcx,
- trait_ref.skip_binder().substs,
- &mut vtable_name,
- &mut visited,
- );
+ push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
} else {
vtable_name.push_str("_");
}
#![feature(box_patterns)]
#![feature(try_blocks)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(once_cell)]
#![feature(nll)]
#![feature(associated_type_bounds)]
use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
crate::target_features::provide(providers);
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
crate::back::symbol_export::provide_extern(providers);
}
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
}
- let fn_ptr = match (llfn, instance) {
- (Some(llfn), _) => llfn,
- (None, Some(instance)) => bx.get_fn_addr(instance),
+ let (is_indirect_call, fn_ptr) = match (llfn, instance) {
+ (Some(llfn), _) => (true, llfn),
+ (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
_ => span_bug!(span, "no llfn for call"),
};
+ // For backends that support CFI using type membership (i.e., testing whether a given
+ // pointer is associated with a type identifier).
+ if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
+ // Emit type metadata and checks.
+ // FIXME(rcvalle): Add support for generalized identifiers.
+ // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
+ let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
+ let typeid_metadata = bx.typeid_metadata(typeid);
+
+ // Test whether the function pointer is associated with the type identifier.
+ let cond = bx.type_test(fn_ptr, typeid_metadata);
+ let mut bx_pass = bx.build_sibling_block("type_test.pass");
+ let mut bx_fail = bx.build_sibling_block("type_test.fail");
+ bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+ helper.do_call(
+ self,
+ &mut bx_pass,
+ fn_abi,
+ fn_ptr,
+ &llargs,
+ destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+ cleanup,
+ );
+
+ bx_fail.abort();
+ bx_fail.unreachable();
+
+ return;
+ }
+
helper.do_call(
self,
&mut bx,
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
) {
let span = terminator.source_info.span;
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans);
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
if let Some(target) = destination {
helper.funclet_br(self, &mut bx, target);
options,
line_spans,
destination,
+ self.instance,
);
}
}
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{FnAbi, PassMode};
use std::iter;
for (bb, _) in traversal::reverse_postorder(&mir) {
fx.codegen_block(bb);
}
+
+ // For backends that support CFI using type membership (i.e., testing whether a given pointer
+ // is associated with a type identifier).
+ if cx.tcx().sess.is_sanitizer_cfi_enabled() {
+ let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
+ bx.type_metadata(llfn, typeid);
+ }
}
/// Produces, for each argument, a `Value` pointing at the
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
.ty;
- let (llptr, llextra) = if let OperandValue::Ref(llptr, Some(llextra), _) = self {
- (llptr, llextra)
- } else {
+ let OperandValue::Ref(llptr, Some(llextra), _) = self else {
bug!("store_unsized called with a sized value")
};
("crypto", Some(sym::arm_target_feature)),
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
+ ("i8mm", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
("thumb-mode", Some(sym::arm_target_feature)),
];
-// Commented features are not available in LLVM 10.0, or have since been renamed
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// FEAT_AdvSimd
("neon", Some(sym::aarch64_target_feature)),
// FEAT_DIT
("dit", Some(sym::aarch64_target_feature)),
// FEAT_FLAGM
- // ("flagm", Some(sym::aarch64_target_feature)),
+ ("flagm", Some(sym::aarch64_target_feature)),
// FEAT_SSBS
("ssbs", Some(sym::aarch64_target_feature)),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
// FEAT_PAUTH
- // ("pauth", Some(sym::aarch64_target_feature)),
+ ("pauth", Some(sym::aarch64_target_feature)),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
// FEAT_DPB2
// FEAT_FRINTTS
("frintts", Some(sym::aarch64_target_feature)),
// FEAT_I8MM
- // ("i8mm", Some(sym::aarch64_target_feature)),
+ ("i8mm", Some(sym::aarch64_target_feature)),
// FEAT_F32MM
- // ("f32mm", Some(sym::aarch64_target_feature)),
+ ("f32mm", Some(sym::aarch64_target_feature)),
// FEAT_F64MM
- // ("f64mm", Some(sym::aarch64_target_feature)),
+ ("f64mm", Some(sym::aarch64_target_feature)),
// FEAT_BF16
- // ("bf16", Some(sym::aarch64_target_feature)),
+ ("bf16", Some(sym::aarch64_target_feature)),
// FEAT_RAND
("rand", Some(sym::aarch64_target_feature)),
// FEAT_BTI
("sha3", Some(sym::aarch64_target_feature)),
// FEAT_SM3 & FEAT_SM4
("sm4", Some(sym::aarch64_target_feature)),
+ // FEAT_PAN
+ ("pan", Some(sym::aarch64_target_feature)),
+ // FEAT_LOR
+ ("lor", Some(sym::aarch64_target_feature)),
+ // FEAT_VHE
+ ("vh", Some(sym::aarch64_target_feature)),
+ // FEAT_PMUv3
+ ("pmuv3", Some(sym::aarch64_target_feature)),
+ // FEAT_SPE
+ ("spe", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
("v8.4a", Some(sym::aarch64_target_feature)),
("v8.5a", Some(sym::aarch64_target_feature)),
- // ("v8.6a", Some(sym::aarch64_target_feature)),
- // ("v8.7a", Some(sym::aarch64_target_feature)),
+ ("v8.6a", Some(sym::aarch64_target_feature)),
+ ("v8.7a", Some(sym::aarch64_target_feature)),
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
);
}
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_session::{
config::{self, OutputFilenames, PrintRequest},
}
fn provide(&self, _providers: &mut Providers) {}
- fn provide_extern(&self, _providers: &mut Providers) {}
+ fn provide_extern(&self, _providers: &mut ExternProviders) {}
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);
+ fn type_metadata(&mut self, function: Self::Function, typeid: String);
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
fn store_with_flags(
///
/// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
fn sideeffect(&mut self);
+ /// Trait method used to test whether a given pointer is associated with a type identifier.
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
/// Rust defined C-variadic functions.
fn va_start(&mut self, val: Self::Value) -> Self::Value;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
} else {
false
}
- } else if let Some(fn_like) = FnLikeNode::from_node(node) {
- if fn_like.constness() == hir::Constness::Const {
+ } else if let Some(fn_kind) = node.fn_kind() {
+ if fn_kind.constness() == hir::Constness::Const {
return true;
}
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
- is_const_fn: bool,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
- // The list of functions we handle here must be in sync with
- // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
+ // All `#[rustc_do_not_const_check]` functions should be hooked here.
let def_id = instance.def_id();
- if is_const_fn {
- if Some(def_id) == self.tcx.lang_items().const_eval_select() {
- // redirect to const_eval_select_ct
- if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
- return Ok(Some(
- ty::Instance::resolve(
- *self.tcx,
- ty::ParamEnv::reveal_all(),
- const_eval_select,
- instance.substs,
- )
- .unwrap()
- .unwrap(),
- ));
- }
+ if Some(def_id) == self.tcx.lang_items().const_eval_select() {
+ // redirect to const_eval_select_ct
+ if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
+ return Ok(Some(
+ ty::Instance::resolve(
+ *self.tcx,
+ ty::ParamEnv::reveal_all(),
+ const_eval_select,
+ instance.substs,
+ )
+ .unwrap()
+ .unwrap(),
+ ));
}
- return Ok(None);
- }
-
- if Some(def_id) == self.tcx.lang_items().panic_fn()
- || Some(def_id) == self.tcx.lang_items().panic_str()
- || Some(def_id) == self.tcx.lang_items().panic_display()
+ } else if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &str or &&str
let span = self.find_closest_untracked_caller_location();
let (file, line, col) = self.location_triple_for_span(span);
return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
- } else if Some(def_id) == self.tcx.lang_items().panic_fmt()
- || Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
- {
+ } else if Some(def_id) == self.tcx.lang_items().panic_fmt() {
// For panic_fmt, call const_panic_fmt instead.
if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
return Ok(Some(
// Only check non-glue functions
if let ty::InstanceDef::Item(def) = instance.def {
- let mut is_const_fn = true;
-
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const
// at all.
if !ecx.tcx.is_const_fn_raw(def.did) {
// allow calling functions marked with #[default_method_body_is_const].
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
- is_const_fn = false;
+ // We certainly do *not* want to actually call the fn
+ // though, so be sure we return here.
+ throw_unsup_format!("calling non-const function `{}`", instance)
}
}
- // Some functions we support even if they are non-const -- but avoid testing
- // that for const fn!
- // `const_eval_select` is a const fn because it must use const trait bounds.
- if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
+ if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
// We call another const fn instead.
return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
}
-
- if !is_const_fn {
- // We certainly do *not* want to actually call the fn
- // though, so be sure we return here.
- throw_unsup_format!("calling non-const function `{}`", instance)
- }
}
// This is a const fn. Call it.
Ok(Some(ecx.load_mir(instance.def, None)?))
line: u32,
col: u32,
) -> MPlaceTy<'tcx, M::PointerTag> {
- let file =
- self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
- let line = Scalar::from_u32(line);
- let col = Scalar::from_u32(col);
+ let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
+ let file = if loc_details.file {
+ self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ } else {
+ // FIXME: This creates a new allocation each time. It might be preferable to
+ // perform this allocation only once, and re-use the `MPlaceTy`.
+ // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ };
+ let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
+ let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
// Allocate memory for `CallerLocation` struct.
let loc_ty = self
ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, ..)
| ty::FnDef(def_id, substs) => {
- let unused_params = self.tcx.unused_generic_params(def_id);
+ let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+ let unused_params = self.tcx.unused_generic_params(instance);
for (index, subst) in substs.into_iter().enumerate() {
let index = index
.try_into()
#![feature(exact_size_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(slice_ptr_get)]
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use std::ops::Deref;
use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
+use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
- rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
#[derive(Default)]
pub struct Qualifs<'mir, 'tcx> {
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
- needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
- indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
+ needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+ needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
}
impl Qualifs<'mir, 'tcx> {
- pub fn indirectly_mutable(
+ /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+ ///
+ /// Only updates the cursor if absolutely necessary
+ pub fn needs_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
- let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
- let ConstCx { tcx, body, param_env, .. } = *ccx;
-
- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
- // allowed in a const.
- //
- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
- // without breaking stable code?
- MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
- .unsound_ignore_borrow_on_drop()
+ let ty = ccx.body.local_decls[local].ty;
+ if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+ return false;
+ }
+
+ let needs_drop = self.needs_drop.get_or_insert_with(|| {
+ let ConstCx { tcx, body, .. } = *ccx;
+
+ FlowSensitiveAnalysis::new(NeedsDrop, ccx)
.into_engine(tcx, &body)
- .pass_name("const_qualification")
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
- indirectly_mutable.seek_before_primary_effect(location);
- indirectly_mutable.get().contains(local)
+ needs_drop.seek_before_primary_effect(location);
+ needs_drop.get().contains(local)
}
- /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+ /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
- pub fn needs_drop(
+ pub fn needs_non_const_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
return false;
}
- let needs_drop = self.needs_drop.get_or_insert_with(|| {
+ let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;
FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
.into_results_cursor(&body)
});
- needs_drop.seek_before_primary_effect(location);
- needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ needs_non_const_drop.seek_before_primary_effect(location);
+ needs_non_const_drop.get().contains(local)
}
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
});
has_mut_interior.seek_before_primary_effect(location);
- has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ has_mut_interior.get().contains(local)
}
fn in_return_place(
.into_results_cursor(&ccx.body);
cursor.seek_after_primary_effect(return_loc);
- cursor.contains(RETURN_PLACE)
+ cursor.get().contains(RETURN_PLACE)
}
};
ConstQualifs {
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
+ needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
custom_eq,
error_occured,
Binder::dummy(TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
}
// At this point, we are calling a function, `callee`, whose `DefId` is known...
- if is_lang_special_const_fn(tcx, callee) {
- // `begin_panic` and `panic_display` are generic functions that accept
- // types other than str. Check to enforce that only str can be used in
- // const-eval.
-
- // const-eval of the `begin_panic` fn assumes the argument is `&str`
- if Some(callee) == tcx.lang_items().begin_panic_fn() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if ty.is_str() => (),
- _ => self.check_op(ops::PanicNonStr),
- }
- }
- // const-eval of the `panic_display` fn assumes the argument is `&&str`
- if Some(callee) == tcx.lang_items().panic_display() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
- {}
- _ => self.check_op(ops::PanicNonStr),
- }
+ // `begin_panic` and `panic_display` are generic functions that accept
+ // types other than str. Check to enforce that only str can be used in
+ // const-eval.
+
+ // const-eval of the `begin_panic` fn assumes the argument is `&str`
+ if Some(callee) == tcx.lang_items().begin_panic_fn() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if ty.is_str() => return,
+ _ => self.check_op(ops::PanicNonStr),
}
+ }
- if is_lang_panic_fn(tcx, callee) {
- // run stability check on non-panic special const fns.
- return;
+ // const-eval of the `panic_display` fn assumes the argument is `&&str`
+ if Some(callee) == tcx.lang_items().panic_display() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+ {
+ return;
+ }
+ _ => self.check_op(ops::PanicNonStr),
}
}
}
// Forbid all `Drop` terminators unless the place being dropped is a local with no
- // projections that cannot be `NeedsDrop`.
+ // projections that cannot be `NeedsNonConstDrop`.
TerminatorKind::Drop { place: dropped_place, .. }
| TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
return;
}
- let needs_drop = if let Some(local) = dropped_place.as_local() {
+ let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
- self.qualifs.needs_drop(self.ccx, local, location)
+ self.qualifs.needs_non_const_drop(self.ccx, local, location)
} else {
true
};
- if needs_drop {
+ if needs_non_const_drop {
self.check_op_spanned(
ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
err_span,
}
}
-/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
-pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- Some(def_id) == tcx.lang_items().panic_fn()
- || Some(def_id) == tcx.lang_items().panic_str()
- || Some(def_id) == tcx.lang_items().panic_display()
- || Some(def_id) == tcx.lang_items().begin_panic_fn()
- || Some(def_id) == tcx.lang_items().panic_fmt()
- || Some(def_id) == tcx.lang_items().begin_panic_fmt()
-}
-
-/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently
-/// in const_eval.
-pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- // We can allow calls to these functions because `hook_special_const_fn` in
- // `const_eval/machine.rs` ensures the calls are handled specially.
- // Keep in sync with what that function handles!
- is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select()
-}
-
pub fn rustc_allow_const_fn_unstable(
tcx: TyCtxt<'tcx>,
def_id: DefId,
// `src/test/ui/consts/control-flow/drop-pass.rs`; e.g., when an `Option<Vec<T>>` is
// initialized with `None` and never changed, it still emits drop glue.
// Hence we additionally check the qualifs here to allow more code to pass.
- if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
+ if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
self.check_live_drop(span);
) -> ConstQualifs {
ConstQualifs {
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
- needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
+ needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
+ needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
error_occured,
}
/// Whether this `Qualif` is cleared when a local is moved from.
const IS_CLEARED_ON_MOVE: bool = false;
+ /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted.
+ const ALLOW_PROMOTED: bool = false;
+
/// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
fn in_qualifs(qualifs: &ConstQualifs) -> bool;
}
/// Constant containing an ADT that implements `Drop`.
-/// This must be ruled out (a) because we cannot run `Drop` during compile-time
-/// as that might not be a `const fn`, and (b) because implicit promotion would
-/// remove side-effects that occur as part of dropping that value.
+/// This must be ruled out because implicit promotion would remove side-effects
+/// that occur as part of dropping that value. N.B., the implicit promotion has
+/// to reject const Drop implementations because even if side-effects are ruled
+/// out through other means, the execution of the drop could diverge.
+pub struct NeedsDrop;
+
+impl Qualif for NeedsDrop {
+ const ANALYSIS_NAME: &'static str = "flow_needs_drop";
+ const IS_CLEARED_ON_MOVE: bool = true;
+
+ fn in_qualifs(qualifs: &ConstQualifs) -> bool {
+ qualifs.needs_drop
+ }
+
+ fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ ty.needs_drop(cx.tcx, cx.param_env)
+ }
+
+ fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+ adt.has_dtor(cx.tcx)
+ }
+}
+
+/// Constant containing an ADT that implements non-const `Drop`.
+/// This must be ruled out because we cannot run `Drop` during compile-time.
pub struct NeedsNonConstDrop;
impl Qualif for NeedsNonConstDrop {
const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
const IS_CLEARED_ON_MOVE: bool = true;
+ const ALLOW_PROMOTED: bool = true;
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
- qualifs.needs_drop
+ qualifs.needs_non_const_drop
}
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
Ok([..]) => {}
}
- let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() {
- did
- } else {
+ let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
// there is no way to define a type that needs non-const drop
// without having the lang item present.
return false;
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
if Q::in_adt_inherently(cx, def, substs) {
return true;
}
+ if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
+ return true;
+ }
}
// Otherwise, proceed structurally...
// Check the qualifs of the value of `const` items.
if let Some(ct) = constant.literal.const_for_ty() {
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val {
- assert!(promoted.is_none());
+ // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
+ // only for `NeedsNonConstDrop` with precise drop checking. This is the only const
+ // check performed after the promotion. Verify that with an assertion.
+ assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
- if cx.tcx.trait_of_item(def.did).is_none() {
+ if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
} else {
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
+use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
+use rustc_mir_dataflow::fmt::DebugWithContext;
+use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_span::DUMMY_SP;
+use std::fmt;
use std::marker::PhantomData;
use super::{qualifs, ConstCx, Qualif};
/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis`.
///
-/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
-/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via
-/// an indirect assignment or function call.
+/// To account for indirect assignments, data flow conservatively assumes that local becomes
+/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
+/// mutation, which includes shared borrows of places with interior mutability. The type of
+/// borrowed place must contain the qualif.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
ccx: &'a ConstCx<'mir, 'tcx>,
- qualifs_per_local: &'a mut BitSet<Local>,
-
+ state: &'a mut State,
_qualif: PhantomData<Q>,
}
where
Q: Qualif,
{
- fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet<Local>) -> Self {
- TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData }
+ fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
+ TransferFunction { ccx, state, _qualif: PhantomData }
}
fn initialize_state(&mut self) {
- self.qualifs_per_local.clear();
+ self.state.qualif.clear();
+ self.state.borrow.clear();
for arg in self.ccx.body.args_iter() {
let arg_ty = self.ccx.body.local_decls[arg].ty;
if Q::in_any_value_of_ty(self.ccx, arg_ty) {
- self.qualifs_per_local.insert(arg);
+ self.state.qualif.insert(arg);
}
}
}
- fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
+ fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
debug_assert!(!place.is_indirect());
+ if !value {
+ for (base, _elem) in place.iter_projections() {
+ let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
+ if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
+ value = true;
+ break;
+ }
+ }
+ }
+
match (value, place.as_ref()) {
(true, mir::PlaceRef { local, .. }) => {
- self.qualifs_per_local.insert(local);
+ self.state.qualif.insert(local);
}
// For now, we do not clear the qualif if a local is overwritten in full by
// with aggregates where we overwrite all fields with assignments, which would not
// get this feature.
(false, mir::PlaceRef { local: _, projection: &[] }) => {
- // self.qualifs_per_local.remove(*local);
+ // self.state.qualif.remove(*local);
}
_ => {}
self.assign_qualif_direct(&return_place, qualif);
}
}
+
+ fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+ // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
+ // it might allow mutation until resolution of #56604.
+ true
+ }
+
+ fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
+ match kind {
+ mir::BorrowKind::Mut { .. } => true,
+ mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
+ self.shared_borrow_allows_mutation(place)
+ }
+ }
+ }
+
+ /// `&` only allow mutation if the borrowed place is `!Freeze`.
+ ///
+ /// This assumes that it is UB to take the address of a struct field whose type is
+ /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
+ /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
+ /// have to check the type of the borrowed **local** instead of the borrowed **place**
+ /// below. See [rust-lang/unsafe-code-guidelines#134].
+ ///
+ /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
+ fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
+ !place
+ .ty(self.ccx.body, self.ccx.tcx)
+ .ty
+ .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ }
}
impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
// it no longer needs to be dropped.
if let mir::Operand::Move(place) = operand {
if let Some(local) = place.as_local() {
- self.qualifs_per_local.remove(local);
+ // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
+ // implementation we retain qualif if a local had been borrowed before. This might
+ // not be strictly necessary since the local is no longer initialized.
+ if !self.state.borrow.contains(local) {
+ self.state.qualif.remove(local);
+ }
}
}
}
rvalue: &mir::Rvalue<'tcx>,
location: Location,
) {
- let qualif = qualifs::in_rvalue::<Q, _>(
- self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
- rvalue,
- );
+ let qualif =
+ qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
if !place.is_indirect() {
self.assign_qualif_direct(place, qualif);
}
self.super_assign(place, rvalue, location);
}
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
+
+ match rvalue {
+ mir::Rvalue::AddressOf(mt, borrowed_place) => {
+ if !borrowed_place.is_indirect()
+ && self.address_of_allows_mutation(*mt, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Ref(_, kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Cast(..)
+ | mir::Rvalue::ShallowInitBox(..)
+ | mir::Rvalue::Use(..)
+ | mir::Rvalue::ThreadLocalRef(..)
+ | mir::Rvalue::Repeat(..)
+ | mir::Rvalue::Len(..)
+ | mir::Rvalue::BinaryOp(..)
+ | mir::Rvalue::CheckedBinaryOp(..)
+ | mir::Rvalue::NullaryOp(..)
+ | mir::Rvalue::UnaryOp(..)
+ | mir::Rvalue::Discriminant(..)
+ | mir::Rvalue::Aggregate(..) => {}
+ }
+ }
+
+ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+ match statement.kind {
+ StatementKind::StorageDead(local) => {
+ self.state.qualif.remove(local);
+ self.state.borrow.remove(local);
+ }
+ _ => self.super_statement(statement, location),
+ }
+ }
+
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
let qualif = qualifs::in_operand::<Q, _>(
self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
+ &mut |l| self.state.qualif.contains(l),
value,
);
}
}
+ // We ignore borrow on drop because custom drop impls are not allowed in consts.
+ // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
+
// We need to assign qualifs to the dropped location before visiting the operand that
// replaces it since qualifs can be cleared on move.
self.super_terminator(terminator, location);
FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
}
- fn transfer_function(
- &self,
- state: &'a mut BitSet<Local>,
- ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
+ fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
TransferFunction::<Q>::new(self.ccx, state)
}
}
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(super) struct State {
+ /// Describes whether a local contains qualif.
+ pub qualif: BitSet<Local>,
+ /// Describes whether a local's address escaped and it might become qualified as a result an
+ /// indirect mutation.
+ pub borrow: BitSet<Local>,
+}
+
+impl State {
+ #[inline]
+ pub(super) fn contains(&self, local: Local) -> bool {
+ self.qualif.contains(local)
+ }
+}
+
+impl<C> DebugWithContext<C> for State {
+ fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_with(ctxt, f)?;
+ f.write_str(" borrow: ")?;
+ self.borrow.fmt_with(ctxt, f)?;
+ Ok(())
+ }
+
+ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self == old {
+ return Ok(());
+ }
+
+ if self.qualif != old.qualif {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ if self.borrow != old.borrow {
+ f.write_str("borrow: ")?;
+ self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl JoinSemiLattice for State {
+ fn join(&mut self, other: &Self) -> bool {
+ self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
+ }
+}
+
impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
- type Domain = BitSet<Local>;
+ type Domain = State;
const NAME: &'static str = Q::ANALYSIS_NAME;
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
- BitSet::new_empty(body.local_decls.len())
+ State {
+ qualif: BitSet::new_empty(body.local_decls.len()),
+ borrow: BitSet::new_empty(body.local_decls.len()),
+ }
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
use std::cell::Cell;
use std::{cmp, iter, mem};
-use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx};
+use crate::transform::check_consts::{qualifs, ConstCx};
use crate::transform::MirPass;
/// A `MirPass` for promotion.
// We cannot promote things that need dropping, since the promoted value
// would not get dropped.
- if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) {
+ if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
}
let is_const_fn = match *fn_ty.kind() {
- ty::FnDef(def_id, _) => {
- self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id)
- }
+ ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
_ => false,
};
if !is_const_fn {
new_temp
}
- fn promote_candidate(
- mut self,
- candidate: Candidate,
- next_promoted_id: usize,
- ) -> Option<Body<'tcx>> {
+ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
let def = self.source.source.with_opt_param();
let mut rvalue = {
let promoted = &mut self.promoted;
let span = self.promoted.span;
self.assign(RETURN_PLACE, rvalue, span);
- Some(self.promoted)
+ self.promoted
}
}
keep_original: false,
};
- //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
- if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) {
- promoted.source.promoted = Some(promotions.next_index());
- promotions.push(promoted);
- }
+ let mut promoted = promoter.promote_candidate(candidate, promotions.len());
+ promoted.source.promoted = Some(promotions.next_index());
+ promotions.push(promoted);
}
// Insert each of `extra_statements` before its indicated location, which
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
bitflags = "1.2.1"
-measureme = "9.1.0"
+measureme = "10.0.0"
libc = "0.2"
stacker = "0.1.14"
tempfile = "3.2"
#[inline]
pub fn push_str(mut n: u128, base: usize, output: &mut String) {
- debug_assert!((2..=MAX_BASE).contains(&base));
+ debug_assert!(base >= 2 && base <= MAX_BASE);
let mut s = [0u8; 128];
let mut index = 0;
AdjacentEdges { graph: self, direction, next: first_edge }
}
- pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+ pub fn successor_nodes<'a>(
+ &'a self,
+ source: NodeIndex,
+ ) -> impl Iterator<Item = NodeIndex> + 'a {
self.outgoing_edges(source).targets()
}
- pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
+ pub fn predecessor_nodes<'a>(
+ &'a self,
+ target: NodeIndex,
+ ) -> impl Iterator<Item = NodeIndex> + 'a {
self.incoming_edges(target).sources()
}
let node = frame.node;
visited[node] = true;
- for successor in frame.iter.by_ref() {
+ while let Some(successor) = frame.iter.next() {
if !visited[successor] {
stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
continue 'recurse;
/// This is equivalent to just invoke `next` repeatedly until
/// you get a `None` result.
pub fn complete_search(&mut self) {
- for _ in self {}
+ while let Some(_) = self.next() {}
}
/// Returns true if node has been visited thus far.
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(bool_to_option)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
.map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
.collect();
- self.compress(|_| unreachable!());
+ self.compress(|_| assert!(false));
errors
}
fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
let orig_nodes_len = self.nodes.len();
let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
- assert!(node_rewrites.is_empty());
+ debug_assert!(node_rewrites.is_empty());
node_rewrites.extend(0..orig_nodes_len);
let mut dead_nodes = 0;
// self.nodes[0..index - dead_nodes] are the first remaining nodes
// self.nodes[index - dead_nodes..index] are all dead
// self.nodes[index..] are unchanged
- for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() {
+ for index in 0..orig_nodes_len {
let node = &self.nodes[index];
match node.state.get() {
NodeState::Pending | NodeState::Waiting => {
if dead_nodes > 0 {
self.nodes.swap(index, index - dead_nodes);
- *node_rewrite -= dead_nodes;
+ node_rewrites[index] -= dead_nodes;
}
}
NodeState::Done => {
}
// Extract the success stories.
outcome_cb(&node.obligation);
- *node_rewrite = orig_nodes_len;
+ node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Error => {
// check against.
self.active_cache.remove(&node.obligation.as_cache_key());
self.insert_into_error_cache(index);
- *node_rewrite = orig_nodes_len;
+ node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Success => unreachable!(),
const FUNCTION_ARGS = 1 << 6;
const LLVM = 1 << 7;
const INCR_RESULT_HASHING = 1 << 8;
+ const ARTIFACT_SIZES = 1 << 9;
const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
Self::QUERY_PROVIDERS.bits |
Self::QUERY_BLOCKED.bits |
Self::INCR_CACHE_LOADS.bits |
- Self::INCR_RESULT_HASHING.bits;
+ Self::INCR_RESULT_HASHING.bits |
+ Self::ARTIFACT_SIZES.bits;
const ARGS = Self::QUERY_KEYS.bits | Self::FUNCTION_ARGS.bits;
}
("args", EventFilter::ARGS),
("llvm", EventFilter::LLVM),
("incr-result-hashing", EventFilter::INCR_RESULT_HASHING),
+ ("artifact-sizes", EventFilter::ARTIFACT_SIZES),
];
/// Something that uniquely identifies a query invocation.
})
}
+ /// Record the size of an artifact that the compiler produces
+ ///
+ /// `artifact_kind` is the class of artifact (e.g., query_cache, object_file, etc.)
+ /// `artifact_name` is an identifier to the specific artifact being stored (usually a filename)
+ #[inline(always)]
+ pub fn artifact_size<A>(&self, artifact_kind: &str, artifact_name: A, size: u64)
+ where
+ A: Borrow<str> + Into<String>,
+ {
+ drop(self.exec(EventFilter::ARTIFACT_SIZES, |profiler| {
+ let builder = EventIdBuilder::new(&profiler.profiler);
+ let event_label = profiler.get_or_alloc_cached_string(artifact_kind);
+ let event_arg = profiler.get_or_alloc_cached_string(artifact_name);
+ let event_id = builder.from_label_and_arg(event_label, event_arg);
+ let thread_id = get_thread_id();
+
+ profiler.profiler.record_integer_event(
+ profiler.artifact_size_event_kind,
+ event_id,
+ thread_id,
+ size,
+ );
+
+ TimingGuard::none()
+ }))
+ }
+
#[inline(always)]
pub fn generic_activity_with_args(
&self,
) {
drop(self.exec(event_filter, |profiler| {
let event_id = StringId::new_virtual(query_invocation_id.0);
- let thread_id = std::thread::current().id().as_u64().get() as u32;
+ let thread_id = get_thread_id();
profiler.profiler.record_instant_event(
event_kind(profiler),
incremental_result_hashing_event_kind: StringId,
query_blocked_event_kind: StringId,
query_cache_hit_event_kind: StringId,
+ artifact_size_event_kind: StringId,
}
impl SelfProfiler {
profiler.alloc_string("IncrementalResultHashing");
let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
+ let artifact_size_event_kind = profiler.alloc_string("ArtifactSize");
let mut event_filter_mask = EventFilter::empty();
incremental_result_hashing_event_kind,
query_blocked_event_kind,
query_cache_hit_event_kind,
+ artifact_size_event_kind,
})
}
event_kind: StringId,
event_id: EventId,
) -> TimingGuard<'a> {
- let thread_id = std::thread::current().id().as_u64().get() as u32;
+ let thread_id = get_thread_id();
let raw_profiler = &profiler.profiler;
let timing_guard =
raw_profiler.start_recording_interval_event(event_kind, event_id, thread_id);
format!("{:.3}", dur.as_secs_f64())
}
+fn get_thread_id() -> u32 {
+ std::thread::current().id().as_u64().get() as u32
+}
+
// Memory reporting
cfg_if! {
if #[cfg(windows)] {
+use crate::stable_hasher::{HashStable, StableHasher};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::iter::FromIterator;
/// stores data in a more compact way. It also supports accessing contiguous
/// ranges of elements as a slice, and slices of already sorted elements can be
/// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
-pub struct SortedMap<K: Ord, V> {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+pub struct SortedMap<K, V> {
data: Vec<(K, V)>,
}
-impl<K: Ord, V> SortedMap<K, V> {
+impl<K, V> Default for SortedMap<K, V> {
+ #[inline]
+ fn default() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
+ }
+}
+
+impl<K, V> SortedMap<K, V> {
#[inline]
- pub fn new() -> SortedMap<K, V> {
- SortedMap { data: vec![] }
+ pub const fn new() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
}
+}
+impl<K: Ord, V> SortedMap<K, V> {
/// Construct a `SortedMap` from a presorted set of elements. This is faster
/// than creating an empty map and then inserting the elements individually.
///
R: RangeBounds<K>,
{
let start = match range.start_bound() {
- Bound::Included(k) => match self.lookup_index_for(k) {
+ Bound::Included(ref k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
- Bound::Excluded(k) => match self.lookup_index_for(k) {
+ Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
};
let end = match range.end_bound() {
- Bound::Included(k) => match self.lookup_index_for(k) {
+ Bound::Included(ref k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
- Bound::Excluded(k) => match self.lookup_index_for(k) {
+ Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
Bound::Unbounded => self.data.len(),
}
}
+impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+ #[inline]
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.data.hash_stable(ctx, hasher);
+ }
+}
+
#[cfg(test)]
mod tests;
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
+ pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
self.get_by_key_enumerated(key).map(|(_, v)| v)
}
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
- pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> {
+ pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
let (k, v) = &self.items[i];
pub fn remove(&mut self, key: &K) -> Option<V> {
match self {
SsoHashMap::Array(array) => {
- array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
+ if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+ Some(array.swap_remove(index).1)
+ } else {
+ None
+ }
}
SsoHashMap::Map(map) => map.remove(key),
}
pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
match self {
SsoHashMap::Array(array) => {
- array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index))
+ if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+ Some(array.swap_remove(index))
+ } else {
+ None
+ }
}
SsoHashMap::Map(map) => map.remove_entry(key),
}
/// adapts Item of array reference iterator to Item of hashmap reference iterator.
#[inline(always)]
-fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
+fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
let (a, b) = pair;
(a, b)
}
/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
#[inline(always)]
-fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
+fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
let (a, b) = pair;
(a, b)
}
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a T`.
#[inline]
- pub fn iter(&self) -> impl Iterator<Item = &T> {
+ pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
self.into_iter()
}
impl<CTX> HashStable<CTX> for f32 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- let val: u32 = self.to_bits();
+ let val: u32 = unsafe { ::std::mem::transmute(*self) };
val.hash_stable(ctx, hasher);
}
}
impl<CTX> HashStable<CTX> for f64 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- let val: u64 = self.to_bits();
+ let val: u64 = unsafe { ::std::mem::transmute(*self) };
val.hash_stable(ctx, hasher);
}
}
}
}
+impl<CTX> HashStable<CTX> for [u8] {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.len().hash_stable(ctx, hasher);
+ hasher.write(self);
+ }
+}
+
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
// on. This flag has performance relevant characteristics. Don't set it too high.
-#[allow(clippy::identity_op)]
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
#[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
let borrow = self.value.borrow();
- if borrow.is_none() {
+ if let None = &*borrow {
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
}
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
#[inline]
pub fn contains(&self, data: &T) -> bool {
let mut elem = self.head.as_ref();
- while let Some(e) = elem {
+ while let Some(ref e) = elem {
if &e.data == data {
return true;
}
pub fn iter<Ls>(
first: Option<Ls::LinkIndex>,
- links: &Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + '_
+ links: &'a Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + 'a
where
Ls: Links,
{
}
fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
where
- F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate<'_>) -> A,
+ F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
{
match *ppmode {
PpHirMode::Normal => {
let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
- f(&annotation, tcx.hir().krate())
+ f(&annotation, tcx.hir())
}
PpHirMode::Identified => {
let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
- f(&annotation, tcx.hir().krate())
+ f(&annotation, tcx.hir())
}
PpHirMode::Typed => {
abort_on_err(tcx.analysis(()), tcx.sess);
let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
- tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir().krate()))
+ tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
}
}
}
format!("{:#?}", krate)
}
- Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
+ Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
debug!("pretty printing HIR {:?}", s);
let sess = annotation.sess();
let sm = sess.source_map();
- pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann())
+ let attrs = |id| hir_map.attrs(id);
+ pprust_hir::print_crate(
+ sm,
+ hir_map.root_module(),
+ src_name,
+ src,
+ &attrs,
+ annotation.pp_ann(),
+ )
}),
- HirTree => call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, krate| {
- debug!("pretty printing HIR tree");
- format!("{:#?}", krate)
- }),
+ HirTree => {
+ call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
+ debug!("pretty printing HIR tree");
+ format!("{:#?}", hir_map.krate())
+ })
+ }
_ => unreachable!(),
};
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
-// E0019, merged into E0015
-// E0035, merged into E0087/E0089
-// E0036, merged into E0087/E0089
+// E0019, // merged into E0015
+// E0035, // merged into E0087/E0089
+// E0036, // merged into E0087/E0089
// E0068,
// E0085,
// E0086,
// E0134,
// E0135,
// E0141,
-// E0153, unused error code
-// E0157, unused error code
+// E0153, // unused error code
+// E0157, // unused error code
// E0159, // use of trait `{}` as struct constructor
// E0163, // merged into E0071
// E0167,
// between structures with the same definition
// E0385, // {} in an aliasable location
// E0402, // cannot use an outer type parameter in this context
-// E0406, merged into 420
-// E0410, merged into 408
-// E0413, merged into 530
-// E0414, merged into 530
-// E0417, merged into 532
-// E0418, merged into 532
-// E0419, merged into 531
-// E0420, merged into 532
-// E0421, merged into 531
-// E0427, merged into 530
+// E0406, // merged into 420
+// E0410, // merged into 408
+// E0413, // merged into 530
+// E0414, // merged into 530
+// E0417, // merged into 532
+// E0418, // merged into 532
+// E0419, // merged into 531
+// E0420, // merged into 532
+// E0421, // merged into 531
+// E0427, // merged into 530
// E0456, // plugin `..` is not available for triple `..`
E0457, // plugin `..` only found in rlib format, but must be available...
E0460, // found possibly newer version of crate `..`
E0461, // couldn't find crate `..` with expected target triple ..
E0462, // found staticlib `..` instead of rlib or dylib
E0465, // multiple .. candidates for `..` found
-// E0467, removed
-// E0470, removed
+// E0467, // removed
+// E0470, // removed
// E0471, // constant evaluation error (in pattern)
E0472, // llvm_asm! is unsupported on this target
// E0473, // dereference of reference outside its lifetime
E0490, // a value of type `..` is borrowed for too long
E0514, // metadata version mismatch
E0519, // local crate and dependency have same (crate-name, disambiguator)
- // two dependencies have same (crate-name, disambiguator) but different SVH
- E0523,
+ E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
// E0548, // replaced with a generic attribute input check
E0711, // a feature has been declared with conflicting stability attributes
E0717, // rustc_promotable without stability attribute
// E0721, // `await` keyword
-// E0723, unstable feature in `const` context
+// E0723, // unstable feature in `const` context
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
+#### Note: this error code is no longer emitted by the compiler.
+
A lifetime of a returned value does not outlive the function call.
Erroneous code example:
-```compile_fail,E0482
+```compile_fail,E0700
fn prefix<'a>(
words: impl Iterator<Item = &'a str>
) -> impl Iterator<Item = String> { // error!
A similar lifetime problem might arise when returning closures:
-```compile_fail,E0482
+```compile_fail,E0700
fn foo(
x: &mut Vec<i32>
) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
-An underscore `_` character has been used as the identifier for a lifetime.
+`'_` lifetime name or `&T` without an explicit lifetime name has been used
+on illegal place.
Erroneous code example:
```compile_fail,E0106,E0637
-fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
- //^^ `'_` is a reserved lifetime name
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ //^^ `'_` is a reserved lifetime name
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<T>()
+where
+ T: Into<&u32>,
+ //^ `&` without an explicit lifetime name
+{
+}
```
-`'_`, cannot be used as a lifetime identifier because it is a reserved for the
-anonymous lifetime. To fix this, use a lowercase letter such as 'a, or a series
-of lowercase letters such as `'foo`. For more information, see [the
-book][bk-no]. For more information on using the anonymous lifetime in rust
-nightly, see [the nightly book][bk-al].
+First, `'_` cannot be used as a lifetime identifier in some places
+because it is a reserved for the anonymous lifetime. Second, `&T`
+without an explicit lifetime name cannot also be used in some places.
+To fix them, use a lowercase letter such as `'a`, or a series
+of lowercase letters such as `'foo`. For more information about lifetime
+identifier, see [the book][bk-no]. For more information on using
+the anonymous lifetime in Rust 2018, see [the Rust 2018 blog post][blog-al].
Corrected example:
```
-fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
+fn underscore_lifetime<'a>(str1: &'a str, str2: &'a str) -> &'a str {
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<'foo, T>()
+where
+ T: Into<&'foo u32>,
+{
+}
```
[bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols
-[bk-al]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.html
+[blog-al]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#more-lifetime-elision-rules
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
+ let mut suggestions: Vec<_> = suggestions.collect();
+ suggestions.sort();
+ let substitutions = suggestions
+ .into_iter()
+ .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
+ .collect();
self.suggestions.push(CodeSuggestion {
- substitutions: suggestions
- .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
- .collect(),
+ substitutions,
msg: msg.to_owned(),
style: SuggestionStyle::ShowCode,
applicability,
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+ CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
};
span: &mut MultiSpan,
children: &mut Vec<SubDiagnostic>,
) {
- let source_map = if let Some(ref sm) = source_map {
- sm
- } else {
- return;
- };
+ let Some(source_map) = source_map else { return };
debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children);
self.fix_multispan_in_extern_macros(source_map, span);
for child in children.iter_mut() {
}
}
-/// An emitter that does nothing when emitting a diagnostic.
-pub struct SilentEmitter;
+/// An emitter that does nothing when emitting a non-fatal diagnostic.
+/// Fatal diagnostics are forwarded to `fatal_handler` to avoid silent
+/// failures of rustc, as witnessed e.g. in issue #89358.
+pub struct SilentEmitter {
+ pub fatal_handler: Handler,
+ pub fatal_note: Option<String>,
+}
impl Emitter for SilentEmitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
- fn emit_diagnostic(&mut self, _: &Diagnostic) {}
+ fn emit_diagnostic(&mut self, d: &Diagnostic) {
+ if d.level == Level::Fatal {
+ let mut d = d.clone();
+ if let Some(ref note) = self.fatal_note {
+ d.note(note);
+ }
+ self.fatal_handler.emit_diagnostic(&d);
+ }
+ }
}
/// Maximum number of lines we will print for a multiline suggestion; arbitrary.
MAX_DIGITS
}
+// We replace some characters so the CLI output is always consistent and underlines aligned.
+const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
+ ('\t', " "), // We do our own tab replacement
+ ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
+ ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+ ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
+ ('\u{202E}', ""),
+ ('\u{2066}', ""),
+ ('\u{2067}', ""),
+ ('\u{2068}', ""),
+ ('\u{202C}', ""),
+ ('\u{2069}', ""),
+];
+
fn replace_tabs(str: &str) -> String {
- str.replace('\t', " ")
+ let mut s = str.to_string();
+ for (c, replacement) in OUTPUT_REPLACEMENTS {
+ s = s.replace(*c, replacement);
+ }
+ s
}
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
#![feature(if_let_guard)]
#![feature(format_args_capture)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(nll)]
#[macro_use]
}
if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() {
- if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
+ if allowed.iter().all(|f| name.as_str() != *f) {
struct_span_err!(
span_handler,
mi.span(),
Unsafe::No,
ModKind::Loaded(krate.items, Inline::Yes, krate.span)
),
- ident: Ident::invalid(),
+ ident: Ident::empty(),
id: ast::DUMMY_NODE_ID,
vis: ast::Visibility {
span: krate.span.shrink_to_lo(),
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
- let (invoc, ext) = if let Some(invoc) = invocations.pop() {
- invoc
- } else {
+ let Some((invoc, ext)) = invocations.pop() else {
self.resolve_imports();
if undetermined_invocations.is_empty() {
break;
_ => unreachable!(),
})
}
- ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
+ 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.
_ => {
item.attrs = attrs;
// The crate root is special - don't assign an ID to it.
- if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::invalid()) {
+ 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)
#![feature(format_args_capture)]
#![feature(if_let_guard)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
pprust::token_to_string(&token),
);
sess.span_diagnostic.span_err(token.span, &msg);
- TokenTree::MetaVar(token.span, Ident::invalid())
+ TokenTree::MetaVar(token.span, Ident::empty())
}
// There are no more tokens. Just return the `$` we already have.
struct Marker(LocalExpnId, Transparency);
impl MutVisitor for Marker {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
fn visit_span(&mut self, span: &mut Span) {
*span = span.apply_mark(self.0.to_expn_id(), self.1)
loop {
// Look at the last frame on the stack.
- let tree = if let Some(tree) = stack.last_mut().unwrap().next() {
- // If it still has a TokenTree we have not looked at yet, use that tree.
- tree
- } else {
+ // If it still has a TokenTree we have not looked at yet, use that tree.
+ let Some(tree) = stack.last_mut().unwrap().next() else {
// This else-case never produces a value for `tree` (it `continue`s or `return`s).
// Otherwise, if we have just reached the end of a sequence and we can keep repeating,
LockstepIterSize::Constraint(len, _) => {
// We do this to avoid an extra clone above. We know that this is a
// sequence already.
- let (sp, seq) = if let mbe::TokenTree::Sequence(sp, seq) = seq {
- (sp, seq)
- } else {
+ let mbe::TokenTree::Sequence(sp, seq) = seq else {
unreachable!()
};
struct ToZzIdentMutVisitor;
impl MutVisitor for ToZzIdentMutVisitor {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
+
fn visit_ident(&mut self, ident: &mut Ident) {
*ident = Ident::from_str("zz");
}
}
}
- let ident = Ident::invalid();
+ let ident = Ident::empty();
let attrs = Vec::new();
let vis = vis.unwrap_or(ast::Visibility {
span: DUMMY_SP,
(accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
/// Allows panicking during const eval (producing compile-time errors).
(accepted, const_panic, "1.57.0", Some(51999), None),
+ /// Lessens the requirements for structs to implement `Unsize`.
+ (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
}
}
+// See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more
+// documentation about handling feature gates.
+//
// If you change this, please modify `src/doc/unstable-book` as well.
//
-// Don't ever remove anything from this list; move them to `removed.rs`.
+// Don't ever remove anything from this list; move them to `accepted.rs` if
+// accepted or `removed.rs` if removed.
//
// The version numbers here correspond to the version in which the current status
// was set. This is most important for knowing when a particular feature became
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
(active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
- /// Lessens the requirements for structs to implement `Unsize`.
- (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
-
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
+ /// Allows creation of instances of a struct by moving fields that have
+ /// not changed from prior instances of the same struct (RFC #2528)
+ (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+
+ /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
+ (active, doc_auto_cfg, "1.58.0", Some(43781), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
pub fn to_dot_string(&self) -> String {
match *self {
LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
- EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
+ EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
HtmlStr(ref s) => format!("<{}>", s),
}
}
rustc_ast = { path = "../rustc_ast" }
tracing = "0.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
[] attribute: rustc_ast::Attribute,
[] block: rustc_hir::Block<$tcx>,
[] bare_fn_ty: rustc_hir::BareFnTy<$tcx>,
+ [] body: rustc_hir::Body<$tcx>,
[] generic_arg: rustc_hir::GenericArg<$tcx>,
[] generic_args: rustc_hir::GenericArgs<$tcx>,
[] generic_bound: rustc_hir::GenericBound<$tcx>,
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
[] local: rustc_hir::Local<$tcx>,
[few] mod_: rustc_hir::Mod<$tcx>,
+ [] owner_info: rustc_hir::OwnerInfo<$tcx>,
[] param: rustc_hir::Param<$tcx>,
[] pat: rustc_hir::Pat<$tcx>,
[] path: rustc_hir::Path<$tcx>,
use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::{DefId, CRATE_DEF_ID};
+use crate::def_id::DefId;
crate use crate::hir_id::{HirId, ItemLocalId};
+use crate::intravisit::FnKind;
use crate::LangItem;
use rustc_ast::util::parser::ExprPrecedence;
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use std::fmt;
#[derive(Copy, Clone, Encodable, HashStable_Generic)]
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Implicit
- | LifetimeName::Error => Ident::invalid(),
+ | LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
LifetimeName::Param(param_name) => param_name.ident(),
}
pub fn invalid() -> Self {
- Self::from_ident(Ident::invalid())
+ Self::from_ident(Ident::empty())
}
pub fn args(&self) -> &GenericArgs<'hir> {
}
pub fn is_synthetic(&self) -> bool {
- matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::invalid())
+ matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
}
pub fn descr(&self) -> &'static str {
pub rhs_ty: &'hir Ty<'hir>,
}
-/// The top-level data structure that stores the entire contents of
-/// the crate currently being compiled.
-///
-/// For more details, see the [rustc dev guide].
+/// HIR node coupled with its parent's id in the same HIR owner.
///
-/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-#[derive(Debug)]
-pub struct Crate<'hir> {
- pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
- pub bodies: BTreeMap<BodyId, Body<'hir>>,
-
- /// Map indicating what traits are in scope for places where this
- /// is relevant; generated by resolve.
- pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
-
- /// Collected attributes from HIR nodes.
- pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
+/// The parent is trash when the node is a HIR owner.
+#[derive(Clone, Debug)]
+pub struct ParentedNode<'tcx> {
+ pub parent: ItemLocalId,
+ pub node: Node<'tcx>,
}
-impl Crate<'hir> {
- pub fn module(&self) -> &'hir Mod<'hir> {
- if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() }
- }
+/// Attributes owned by a HIR owner.
+#[derive(Debug)]
+pub struct AttributeMap<'tcx> {
+ pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
+ pub hash: Fingerprint,
+}
- pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_item()
- }
+impl<'tcx> AttributeMap<'tcx> {
+ pub const EMPTY: &'static AttributeMap<'static> =
+ &AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO };
- pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_trait_item()
+ #[inline]
+ pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
+ self.map.get(&id).copied().unwrap_or(&[])
}
+}
- pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_impl_item()
- }
+/// Map of all HIR nodes inside the current owner.
+/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node.
+/// The HIR tree, including bodies, is pre-hashed.
+#[derive(Debug)]
+pub struct OwnerNodes<'tcx> {
+ /// Pre-computed hash of the full HIR.
+ pub hash_including_bodies: Fingerprint,
+ /// Pre-computed hash of the item signature, sithout recursing into the body.
+ pub hash_without_bodies: Fingerprint,
+ /// Full HIR for the current owner.
+ // The zeroth node's parent should never be accessed: the owner's parent is computed by the
+ // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
+ // used.
+ pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+ /// Content of local bodies.
+ pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
+}
+
+/// Full information resulting from lowering an AST node.
+#[derive(Debug, HashStable_Generic)]
+pub struct OwnerInfo<'hir> {
+ /// Contents of the HIR.
+ pub nodes: OwnerNodes<'hir>,
+ /// Map from each nested owner to its parent's local id.
+ pub parenting: FxHashMap<LocalDefId, ItemLocalId>,
+ /// Collected attributes of the HIR nodes.
+ pub attrs: AttributeMap<'hir>,
+ /// Map indicating what traits are in scope for places where this
+ /// is relevant; generated by resolve.
+ pub trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
+}
- pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.owners[id.def_id].as_ref().unwrap().expect_foreign_item()
+impl<'tcx> OwnerInfo<'tcx> {
+ #[inline]
+ pub fn node(&self) -> OwnerNode<'tcx> {
+ use rustc_index::vec::Idx;
+ let node = self.nodes.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
+ let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
+ node
}
+}
- pub fn body(&self, id: BodyId) -> &Body<'hir> {
- &self.bodies[&id]
- }
+/// The top-level data structure that stores the entire contents of
+/// the crate currently being compiled.
+///
+/// For more details, see the [rustc dev guide].
+///
+/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#[derive(Debug)]
+pub struct Crate<'hir> {
+ pub owners: IndexVec<LocalDefId, Option<OwnerInfo<'hir>>>,
+ pub hir_hash: Fingerprint,
}
/// A block of statements `{ .. }`, which may have a label (in this case the
_ => None,
}
}
+
+ pub fn fn_kind(self) -> Option<FnKind<'hir>> {
+ match self {
+ Node::Item(i) => match i.kind {
+ ItemKind::Fn(ref sig, ref generics, _) => {
+ Some(FnKind::ItemFn(i.ident, generics, sig.header, &i.vis))
+ }
+ _ => None,
+ },
+ Node::TraitItem(ti) => match ti.kind {
+ TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
+ Some(FnKind::Method(ti.ident, sig, None))
+ }
+ _ => None,
+ },
+ Node::ImplItem(ii) => match ii.kind {
+ ImplItemKind::Fn(ref sig, _) => Some(FnKind::Method(ii.ident, sig, Some(&ii.vis))),
+ _ => None,
+ },
+ Node::Expr(e) => match e.kind {
+ ExprKind::Closure(..) => Some(FnKind::Closure),
+ _ => None,
+ },
+ _ => None,
+ }
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
-use rustc_index::vec::IndexVec;
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
pub struct ItemLocalId { .. }
}
rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+impl ItemLocalId {
+ /// Signal local id which should never be used.
+ pub const INVALID: ItemLocalId = ItemLocalId::MAX;
+}
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
pub const CRATE_HIR_ID: HirId = HirId {
owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
local_id: ItemLocalId::from_u32(0),
};
-
-/// N.B. This collection is currently unused, but will be used by #72015 and future PRs.
-#[derive(Clone, Default, Debug, Encodable, Decodable)]
-pub struct HirIdVec<T> {
- map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>,
-}
-
-impl<T> HirIdVec<T> {
- pub fn push_owner(&mut self, id: LocalDefId) {
- self.map.ensure_contains_elem(id, IndexVec::new);
- }
-
- pub fn push(&mut self, id: HirId, value: T) {
- if id.local_id == ItemLocalId::from_u32(0) {
- self.push_owner(id.owner);
- }
- let submap = &mut self.map[id.owner];
- let _ret_id = submap.push(value);
- debug_assert_eq!(_ret_id, id.local_id);
- }
-
- pub fn push_sparse(&mut self, id: HirId, value: T)
- where
- T: Default,
- {
- self.map.ensure_contains_elem(id.owner, IndexVec::new);
- let submap = &mut self.map[id.owner];
- let i = id.local_id.index();
- let len = submap.len();
- if i >= len {
- submap.extend(std::iter::repeat_with(T::default).take(i - len + 1));
- }
- submap[id.local_id] = value;
- }
-
- pub fn get(&self, id: HirId) -> Option<&T> {
- self.map.get(id.owner)?.get(id.local_id)
- }
-
- pub fn get_owner(&self, id: LocalDefId) -> &IndexVec<ItemLocalId, T> {
- &self.map[id]
- }
-
- pub fn iter(&self) -> impl Iterator<Item = &T> {
- self.map.iter().flat_map(|la| la.iter())
- }
-
- pub fn iter_enumerated(&self) -> impl Iterator<Item = (HirId, &T)> {
- self.map.iter_enumerated().flat_map(|(owner, la)| {
- la.iter_enumerated().map(move |(local_id, attr)| (HirId { owner, local_id }, attr))
- })
- }
-}
-
-impl<T> std::ops::Index<HirId> for HirIdVec<T> {
- type Output = T;
-
- fn index(&self, id: HirId) -> &T {
- &self.map[id.owner][id.local_id]
- }
-}
-
-impl<T> std::ops::IndexMut<HirId> for HirIdVec<T> {
- fn index_mut(&mut self, id: HirId) -> &mut T {
- &mut self.map[id.owner][id.local_id]
- }
-}
FnKind::Closure => None,
}
}
+
+ pub fn constness(self) -> Constness {
+ self.header().map_or(Constness::NotConst, |header| header.constness)
+ }
+
+ pub fn asyncness(self) -> IsAsync {
+ self.header().map_or(IsAsync::NotAsync, |header| header.asyncness)
+ }
}
/// An abstract representation of the HIR `rustc_middle::hir::map::Map`.
fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
}
+// Used when no map is actually available, forcing manual implementation of nested visitors.
+impl Map<'hir> for ! {
+ fn find(&self, _: HirId) -> Option<Node<'hir>> {
+ unreachable!()
+ }
+ fn body(&self, _: BodyId) -> &'hir Body<'hir> {
+ unreachable!()
+ }
+ fn item(&self, _: ItemId) -> &'hir Item<'hir> {
+ unreachable!()
+ }
+ fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
+ unreachable!()
+ }
+ fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
+ unreachable!()
+ }
+ fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ unreachable!()
+ }
+}
+
/// An erased version of `Map<'hir>`, using dynamic dispatch.
/// NOTE: This type is effectively only usable with `NestedVisitorMap::None`.
pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>);
// in the sense that a crate is not required to have it defined to use it, but a final product
// is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined.
- Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None;
+ Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
- PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None;
+ PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
/// libstd panic entry point. Necessary for const eval to be able to catch it
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
- BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn, GenericRequirement::None;
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
+#![feature(const_btree_new)]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(once_cell)]
#![feature(min_specialization)]
+#![feature(never_type)]
#![recursion_limit = "256"]
#[macro_use]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use crate::hir::{
- BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem,
- TraitItemId, Ty, VisibilityKind,
+ AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
+ ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
use rustc_span::def_id::DefPathHash;
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
+ fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher);
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
});
}
}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ // We ignore the `nodes` and `bodies` fields since these refer to information included in
+ // `hash` which is hashed in the collector and used for the crate hash.
+ let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } =
+ *self;
+ hash_including_bodies.hash_stable(hcx, hasher);
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ // We ignore the `map` since it refers to information included in `hash` which is hashed in
+ // the collector and used for the crate hash.
+ let AttributeMap { hash, map: _ } = *self;
+ hash.hash_stable(hcx, hasher);
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ let Crate { owners: _, hir_hash } = self;
+ hir_hash.hash_stable(hcx, hasher)
+ }
+}
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitCandidate {
+ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+ hcx.hash_hir_trait_candidate(self, hasher)
+ }
+}
use std::borrow::Cow;
use std::cell::Cell;
-use std::collections::BTreeMap;
use std::vec;
pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String {
pub struct State<'a> {
pub s: pp::Printer,
comments: Option<Comments<'a>>,
- attrs: &'a BTreeMap<hir::HirId, &'a [ast::Attribute]>,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a (dyn PpAnn + 'a),
}
/// it can scan the input text for comments to copy forward.
pub fn print_crate<'a>(
sm: &'a SourceMap,
- krate: &hir::Crate<'_>,
+ krate: &hir::Mod<'_>,
filename: FileName,
input: String,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> String {
- let mut s = State::new_from_input(sm, filename, input, &krate.attrs, ann);
+ let mut s = State::new_from_input(sm, filename, input, attrs, ann);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
- s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID));
+ s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID));
s.print_remaining_comments();
s.s.eof()
}
sm: &'a SourceMap,
filename: FileName,
input: String,
- attrs: &'a BTreeMap<hir::HirId, &[ast::Attribute]>,
+ attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> State<'a> {
State {
}
fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
- self.attrs.get(&id).map_or(&[], |la| *la)
+ (self.attrs)(id)
}
}
where
F: FnOnce(&mut State<'_>),
{
- let mut printer =
- State { s: pp::mk_printer(), comments: None, attrs: &BTreeMap::default(), ann };
+ let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
f(&mut printer);
printer.s.eof()
}
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
}
- // Does `expr` need parenthesis when printed in a condition position?
+ // Does `expr` need parentheses when printed in a condition position?
//
// These cases need parens due to the parse error observed in #26461: `if return {}`
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
if attr.has_name(sym::rustc_if_this_changed) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
- None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
- Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
- Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
+ None => {
+ DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
+ }
+ Some(n) => {
+ match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+ Ok(n) => n,
+ Err(()) => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unrecognized DepNode variant {:?}", n),
+ );
+ }
}
- },
+ }
};
self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
} else if attr.has_name(sym::rustc_then_this_would_need) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
- Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
- Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
+ Some(n) => {
+ match DepNode::from_label_string(self.tcx, &n.as_str(), def_path_hash) {
+ Ok(n) => n,
+ Err(()) => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unrecognized DepNode variant {:?}", n),
+ );
+ }
}
- },
+ }
None => {
self.tcx.sess.span_fatal(attr.span, "missing DepNode variant");
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![recursion_limit = "256"]
use rustc_ast::{self as ast, Attribute, NestedMetaItem};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::Node as HirNode;
out
}
- fn dep_nodes<'l>(
- &self,
- labels: &'l Labels,
- def_id: DefId,
- ) -> impl Iterator<Item = DepNode> + 'l {
- let def_path_hash = self.tcx.def_path_hash(def_id);
- labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) {
- Ok(dep_node) => dep_node,
- Err(()) => unreachable!("label: {}", label),
- })
- }
-
fn dep_node_str(&self, dep_node: &DepNode) -> String {
if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
}
fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
+ let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
let assertion = match self.assertion_maybe(item_id, attr) {
Some(a) => a,
None => continue,
};
self.checked_attrs.insert(attr.id);
- for dep_node in self.dep_nodes(&assertion.clean, item_id.to_def_id()) {
+ for label in assertion.clean {
+ let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
self.assert_clean(item_span, dep_node);
}
- for dep_node in self.dep_nodes(&assertion.dirty, item_id.to_def_id()) {
+ for label in assertion.dirty {
+ let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
self.assert_dirty(item_span, dep_node);
}
}
return;
}
+ sess.prof.artifact_size(
+ &name.replace(' ', "_"),
+ path_buf.file_name().unwrap().to_string_lossy(),
+ encoder.position() as u64,
+ );
+
debug!("save: data written to disk successfully");
}
// have already tried before.
let source_directory = find_source_directory(&crate_dir, &source_directories_already_tried);
- let source_directory = if let Some(dir) = source_directory {
- dir
- } else {
+ let Some(source_directory) = source_directory else {
// There's nowhere to copy from, we're done
debug!(
"no source directory found. Continuing with empty session \
// We acquire a shared lock on the lock file of the directory, so that
// nobody deletes it out from under us while we are reading from it.
let lock_file_path = lock_file_path(source_dir);
- let _lock = if let Ok(lock) = flock::Lock::new(
+
+ // not exclusive
+ let Ok(_lock) = flock::Lock::new(
&lock_file_path,
false, // don't wait,
false, // don't create
false,
- ) {
- // not exclusive
- lock
- } else {
+ ) else {
// Could not acquire the lock, don't try to copy from here
return Err(());
};
pub fn insert_all_into_row(&mut self, row: R) {
assert!(row.index() < self.num_rows);
let (start, end) = self.range(row);
- for word in self.words[start..end].iter_mut() {
- *word = !0;
+ let words = &mut self.words[..];
+ for index in start..end {
+ words[index] = !0;
}
self.clear_excess_bits(row);
}
/// Iterates through all the columns set to true in a given row of
/// the matrix.
- pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ {
+ pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
self.row(row).into_iter().flat_map(|r| r.iter())
}
#[inline]
$v const fn from_usize(value: usize) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= ($max as usize));
- #[cfg(bootstrap)]
- [()][(value > ($max as usize)) as usize];
unsafe {
Self::from_u32_unchecked(value as u32)
}
#[inline]
$v const fn from_u32(value: u32) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= $max);
- #[cfg(bootstrap)]
- [()][(value > $max) as usize];
unsafe {
Self::from_u32_unchecked(value)
}
}
#[inline]
- pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ {
+ pub fn drain<'a, R: RangeBounds<usize>>(
+ &'a mut self,
+ range: R,
+ ) -> impl Iterator<Item = T> + 'a {
self.raw.drain(range)
}
#[inline]
- pub fn drain_enumerated<R: RangeBounds<usize>>(
- &mut self,
+ pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
+ &'a mut self,
range: R,
- ) -> impl Iterator<Item = (I, T)> + '_ {
+ ) -> impl Iterator<Item = (I, T)> + 'a {
self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
}
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug_assert_eq!(t, _t);
debug!("ConstInferUnifier: t={:?}", t);
}
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn consts(
&mut self,
c: &'tcx ty::Const<'tcx>,
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let variable_table = &mut inner.const_unification_table();
-
// Check if the current unification would end up
// unifying `target_vid` with a const which contains
// an inference variable which is unioned with `target_vid`.
//
// Not doing so can easily result in stack overflows.
- if variable_table.unioned(self.target_vid, vid) {
+ if self
+ .infcx
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .unioned(self.target_vid, vid)
+ {
return Err(TypeError::CyclicConst(c));
}
- let var_value = variable_table.probe_value(vid);
+ let var_value =
+ self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
match var_value.val {
ConstVariableValue::Known { value: u } => self.consts(u, u),
ConstVariableValue::Unknown { universe } => {
if self.for_universe.can_name(universe) {
Ok(c)
} else {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.for_universe },
- });
+ let new_var_id =
+ self.infcx.inner.borrow_mut().const_unification_table().new_key(
+ ConstVarValue {
+ origin: var_value.origin,
+ val: ConstVariableValue::Unknown {
+ universe: self.for_universe,
+ },
+ },
+ );
Ok(self.tcx().mk_const_var(new_var_id, c.ty))
}
}
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
}
-
- RegionResolutionError::MemberConstraintFailure {
- hidden_ty,
- member_region,
- span,
- } => {
- let hidden_ty = self.resolve_vars_if_possible(hidden_ty);
- unexpected_hidden_region_diagnostic(
- self.tcx,
- span,
- hidden_ty,
- member_region,
- )
- .emit();
- }
}
}
}
RegionResolutionError::GenericBoundFailure(..) => true,
RegionResolutionError::ConcreteFailure(..)
| RegionResolutionError::SubSupConflict(..)
- | RegionResolutionError::UpperBoundUniverseConflict(..)
- | RegionResolutionError::MemberConstraintFailure { .. } => false,
+ | RegionResolutionError::UpperBoundUniverseConflict(..) => false,
};
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
- RegionResolutionError::MemberConstraintFailure { span, .. } => span,
});
errors
}
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
-use rustc_errors::{struct_span_err, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::{GenericParamKind, Ty};
+use rustc_middle::ty::Region;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
}
};
- let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
+ let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
- e.span_label(span_1, main_label);
- e.span_label(span_2, String::new());
- e.span_label(span, span_label);
+ err.span_label(span_1, main_label);
+ err.span_label(span_2, String::new());
+ err.span_label(span, span_label);
+
+ self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
if let Some(t) = future_return_type {
let snip = self
(_, "") => None,
_ => Some(s),
})
- .unwrap_or("{unnamed_type}".to_string());
+ .unwrap_or_else(|| "{unnamed_type}".to_string());
- e.span_label(
+ err.span_label(
t.span,
&format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
);
}
- e.emit();
+ err.emit();
Some(ErrorReported)
}
+
+ fn suggest_adding_lifetime_params(
+ &self,
+ sub: Region<'tcx>,
+ ty_sup: &Ty<'_>,
+ ty_sub: &Ty<'_>,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ if let (
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ ) = (ty_sub, ty_sup)
+ {
+ if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
+ if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
+ let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
+ if let hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Fn(_, ref generics, ..),
+ ..
+ }) = self.tcx().hir().get(hir_id)
+ {
+ let (suggestion_param_name, introduce_new) = generics
+ .params
+ .iter()
+ .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
+ .map(|name| (name, false))
+ .unwrap_or_else(|| ("'a".to_string(), true));
+
+ let mut suggestions = vec![
+ if let hir::LifetimeName::Underscore = lifetime_sub.name {
+ (lifetime_sub.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sub.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ if let hir::LifetimeName::Underscore = lifetime_sup.name {
+ (lifetime_sup.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sup.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ ];
+
+ if introduce_new {
+ let new_param_suggestion = match &generics.params {
+ [] => (generics.span, format!("<{}>", suggestion_param_name)),
+ [first, ..] => (
+ first.span.shrink_to_lo(),
+ format!("{}, ", suggestion_param_name),
+ ),
+ };
+
+ suggestions.push(new_param_suggestion);
+ }
+
+ err.multipart_suggestion(
+ "consider introducing a named lifetime parameter",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ err.note(
+ "each elided lifetime in input position becomes a distinct lifetime",
+ );
+ }
+ }
+ }
+ }
+ }
}
match fn_return.kind {
TyKind::OpaqueDef(item_id, _) => {
let item = tcx.hir().item(item_id);
- let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
- opaque
- } else {
+ let ItemKind::OpaqueTy(opaque) = &item.kind else {
return;
};
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::print::RegionHighlightMode;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+
use rustc_span::{MultiSpan, Span, Symbol};
+use std::ops::ControlFlow;
+
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
.tcx()
.sess
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
+
+ // Mark all unnamed regions in the type with a number.
+ // This diagnostic is called in response to lifetime errors, so be informative.
+ struct HighlightBuilder<'tcx> {
+ highlight: RegionHighlightMode,
+ tcx: TyCtxt<'tcx>,
+ counter: usize,
+ }
+
+ impl HighlightBuilder<'tcx> {
+ fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+ let mut builder =
+ HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+ builder.visit_ty(ty);
+ builder.highlight
+ }
+ }
+
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if !r.has_name() && self.counter <= 3 {
+ self.highlight.highlighting_region(r, self.counter);
+ self.counter += 1;
+ }
+ r.super_visit_with(self)
+ }
+ }
+
+ let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+ let expected = self
+ .infcx
+ .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
+ .name;
+ let found_highlight = HighlightBuilder::build(self.tcx(), found);
+ let found =
+ self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
);
}
- if let Some((expected, found)) =
- self.infcx.expected_found_str_ty(ExpectedFound { expected, found })
- {
- // Highlighted the differences when showing the "expected/found" note.
- err.note_expected_found(&"", expected, &"", found);
- } else {
- // This fallback shouldn't be necessary, but let's keep it in just in case.
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
- }
+ err.note(&format!("expected `{}`\n found `{}`", expected, found));
+
err.span_help(
type_param_span,
"the lifetime requirements from the `impl` do not correspond to the requirements in \
// similar to the asyncness fn in rustc_ty_utils::ty
let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
let node = self.tcx().hir().get(hir_id);
- let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?;
-
- Some(fn_like.asyncness())
+ let fn_kind = node.fn_kind()?;
+ Some(fn_kind.asyncness())
}
// Here, we check for the case where the anonymous region
infer::RelateObjectBound(span) => {
label_or_note(span, "...so that it can be closed over into an object");
}
- infer::CallReturn(span) => {
- label_or_note(span, "...so that return value is valid for the call");
- }
infer::DataBorrowed(ty, span) => {
label_or_note(
span,
);
err
}
- infer::CallReturn(span) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0482,
- "lifetime of return value does not outlive the function call"
- );
- note_and_explain_region(
- self.tcx,
- &mut err,
- "the return value is only valid for ",
- sup,
- "",
- None,
- );
- err
- }
infer::DataBorrowed(ty, span) => {
let mut err = struct_span_err!(
self.tcx.sess,
/// follows. If we know that `r_b: 'static`, then this function
/// will return true, even though we don't know anything that
/// directly relates `r_a` and `r_b`.
- ///
- /// Also available through the `FreeRegionRelations` trait below.
pub fn sub_free_regions(
&self,
tcx: TyCtxt<'tcx>,
}
}
-/// The NLL region handling code represents free region relations in a
-/// slightly different way; this trait allows functions to be abstract
-/// over which version is in use.
-pub trait FreeRegionRelations<'tcx> {
- /// Tests whether `r_a <= r_b`. Both must be free regions or
- /// `'static`.
- fn sub_free_regions(
- &self,
- tcx: TyCtxt<'tcx>,
- shorter: ty::Region<'tcx>,
- longer: ty::Region<'tcx>,
- ) -> bool;
-}
-
-impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
- fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
- // invoke the "inherent method"
- self.sub_free_regions(tcx, r_a, r_b)
- }
-}
-
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
type Lifted = FreeRegionMap<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::GenericKind;
-use crate::infer::region_constraints::MemberConstraint;
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
-use rustc_span::Span;
use std::fmt;
/// This function performs lexical region resolution given a complete
/// iteration to find region values which satisfy all constraints,
/// assuming such values can be found. It returns the final values of
/// all the variables as well as a set of errors that must be reported.
+#[instrument(level = "debug", skip(region_rels, var_infos, data))]
pub fn resolve<'tcx>(
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
mode: RegionckMode,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
- debug!("RegionConstraintData: resolve_regions()");
let mut errors = vec![];
let mut resolver = LexicalResolver { region_rels, var_infos, data };
match mode {
SubregionOrigin<'tcx>, // cause of the constraint
Region<'tcx>, // the placeholder `'b`
),
-
- /// Indicates a failure of a `MemberConstraint`. These arise during
- /// impl trait processing explicitly -- basically, the impl trait's hidden type
- /// included some region that it was not supposed to.
- MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
}
struct RegionAndOrigin<'tcx> {
let graph = self.construct_graph();
self.expand_givens(&graph);
- loop {
- self.expansion(&mut var_data);
- if !self.enforce_member_constraints(&graph, &mut var_data) {
- break;
- }
- }
+ self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
var_data
}
}
- /// Enforce all member constraints and return true if anything
- /// changed. See `enforce_member_constraint` for more details.
- fn enforce_member_constraints(
- &self,
- graph: &RegionGraph<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- // Note: we don't use the `any` combinator because we don't
- // want to stop at the first constraint that makes a change.
- let mut any_changed = false;
- for member_constraint in &self.data.member_constraints {
- any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
- }
- any_changed
- }
-
- /// Enforce a constraint like
- ///
- /// ```
- /// 'r member of ['c...]
- /// ```
- ///
- /// We look for all choice regions from the list `'c...` that:
- ///
- /// (a) are greater than the current value of `'r` (which is a lower bound)
- ///
- /// and
- ///
- /// (b) are compatible with the upper bounds of `'r` that we can
- /// find by traversing the graph.
- ///
- /// From that list, we look for a *minimal* option `'c_min`. If we
- /// find one, then we can enforce that `'r: 'c_min`.
- fn enforce_member_constraint(
- &self,
- graph: &RegionGraph<'tcx>,
- member_constraint: &MemberConstraint<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
-
- // The constraint is some inference variable (`vid`) which
- // must be equal to one of the options.
- let member_vid = match member_constraint.member_region {
- ty::ReVar(vid) => *vid,
- _ => return false,
- };
-
- // The current value of `vid` is a lower bound LB -- i.e., we
- // know that `LB <= vid` must be true.
- let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
- VarValue::ErrorValue => return false,
- VarValue::Value(r) => r,
- };
-
- // Find all the "upper bounds" -- that is, each region `b` such that
- // `r0 <= b` must hold.
- let (member_upper_bounds, ..) =
- self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
-
- // Get an iterator over the *available choice* -- that is,
- // each choice region `c` where `lb <= c` and `c <= ub` for all the
- // upper bounds `ub`.
- debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
- let mut options = member_constraint.choice_regions.iter().filter(|option| {
- self.sub_concrete_regions(member_lower_bound, option)
- && member_upper_bounds
- .iter()
- .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
- });
-
- // If there is more than one option, we only make a choice if
- // there is a single *least* choice -- i.e., some available
- // region that is `<=` all the others.
- let mut least_choice: ty::Region<'tcx> = match options.next() {
- Some(&r) => r,
- None => return false,
- };
- debug!("enforce_member_constraint: least_choice={:?}", least_choice);
- for &option in options {
- debug!("enforce_member_constraint: option={:?}", option);
- if !self.sub_concrete_regions(least_choice, option) {
- if self.sub_concrete_regions(option, least_choice) {
- debug!("enforce_member_constraint: new least choice");
- least_choice = option;
- } else {
- debug!("enforce_member_constraint: no least choice");
- return false;
- }
- }
- }
-
- // (#72087) Different `ty::Regions` can be known to be equal, for
- // example, we know that `'a` and `'static` are equal in a function
- // with a parameter of type `&'static &'a ()`.
- //
- // When we have two equal regions like this `expansion` will use
- // `lub_concrete_regions` to pick a canonical representative. The same
- // choice is needed here so that we don't end up in a cycle of
- // `expansion` changing the region one way and the code here changing
- // it back.
- let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
- debug!(
- "enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
- least_choice, lub
- );
- if lub != member_lower_bound {
- *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
- true
- } else {
- false
- }
- }
-
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
let mut changes = Vec::new();
}
/// True if `a <= b`, but not defined over inference variables.
+ #[instrument(level = "trace", skip(self))]
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
let tcx = self.tcx();
let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
///
/// Neither `a` nor `b` may be an inference variable (hence the
/// term "concrete regions").
+ #[instrument(level = "trace", skip(self))]
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let r = match (a, b) {
(&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
/// After expansion is complete, go and check upper bounds (i.e.,
/// cases where the region cannot grow larger than a fixed point)
/// and check that they are satisfied.
+ #[instrument(skip(self, var_data, errors))]
fn collect_errors(
&self,
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
for (constraint, origin) in &self.data.constraints {
- debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
+ debug!(?constraint, ?origin);
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
// Expansion will ensure that these constraints hold. Ignore.
}
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?} <= {:?}",
origin, sub, sup
);
// collect them later.
if !self.sub_concrete_regions(a_region, b_region) {
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?}={:?} <= {:?}",
origin, a_vid, a_region, b_region
);
}
}
- // Check that all member constraints are satisfied.
- for member_constraint in &self.data.member_constraints {
- let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
- let choice_regions = member_constraint
- .choice_regions
- .iter()
- .map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
- if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
- let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
- errors.push(RegionResolutionError::MemberConstraintFailure {
- span,
- hidden_ty: member_constraint.hidden_ty,
- member_region,
- });
- }
- }
-
for verify in &self.data.verifys {
debug!("collect_errors: verify={:?}", verify);
let sub = var_data.normalize(self.tcx(), verify.region);
/// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
- /// Region in return type of invoked fn must enclose call
- CallReturn(Span),
-
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
CompareImplMethodObligation {
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
- CallReturn(a) => a,
CompareImplMethodObligation { span, .. } => span,
CompareImplTypeObligation { span, .. } => span,
}
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits;
+use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
-use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
+use std::ops::ControlFlow;
+
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
/// Information about the opaque types whose values we
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
}
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+ /// Replaces all opaque types in `value` with fresh inference variables
+ /// and creates appropriate obligations. For example, given the input:
+ ///
+ /// impl Iterator<Item = impl Debug>
+ ///
+ /// this method would create two type variables, `?0` and `?1`. It would
+ /// return the type `?0` but also the obligations:
+ ///
+ /// ?0: Iterator<Item = ?1>
+ /// ?1: Debug
+ ///
+ /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
+ /// info about the `impl Iterator<..>` type and `?1` to info about
+ /// the `impl Debug` type.
+ ///
+ /// # Parameters
+ ///
+ /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
+ /// is defined
+ /// - `body_id` -- the body-id with which the resulting obligations should
+ /// be associated
+ /// - `param_env` -- the in-scope parameter environment to be used for
+ /// obligations
+ /// - `value` -- the value within which we are instantiating opaque types
+ /// - `value_span` -- the span where the value came from, used in error reporting
+ pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+ &self,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ value_span: Span,
+ ) -> InferOk<'tcx, T> {
+ debug!(
+ "instantiate_opaque_types(value={:?}, body_id={:?}, \
+ param_env={:?}, value_span={:?})",
+ value, body_id, param_env, value_span,
+ );
+ let mut instantiator =
+ Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
+ let value = instantiator.instantiate_opaque_types_in_map(value);
+ InferOk { value, obligations: instantiator.obligations }
+ }
+
+ /// Given the map `opaque_types` containing the opaque
+ /// `impl Trait` types whose underlying, hidden types are being
+ /// inferred, this method adds constraints to the regions
+ /// appearing in those underlying hidden types to ensure that they
+ /// at least do not refer to random scopes within the current
+ /// function. These constraints are not (quite) sufficient to
+ /// guarantee that the regions are actually legal values; that
+ /// final condition is imposed after region inference is done.
+ ///
+ /// # The Problem
+ ///
+ /// Let's work through an example to explain how it works. Assume
+ /// the current function is as follows:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
+ /// ```
+ ///
+ /// Here, we have two `impl Trait` types whose values are being
+ /// inferred (the `impl Bar<'a>` and the `impl
+ /// Bar<'b>`). Conceptually, this is sugar for a setup where we
+ /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
+ /// the return type of `foo`, we *reference* those definitions:
+ ///
+ /// ```text
+ /// type Foo1<'x> = impl Bar<'x>;
+ /// type Foo2<'x> = impl Bar<'x>;
+ /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+ /// // ^^^^ ^^
+ /// // | |
+ /// // | substs
+ /// // def_id
+ /// ```
+ ///
+ /// As indicating in the comments above, each of those references
+ /// is (in the compiler) basically a substitution (`substs`)
+ /// applied to the type of a suitable `def_id` (which identifies
+ /// `Foo1` or `Foo2`).
+ ///
+ /// Now, at this point in compilation, what we have done is to
+ /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
+ /// fresh inference variables C1 and C2. We wish to use the values
+ /// of these variables to infer the underlying types of `Foo1` and
+ /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
+ /// constraints like:
+ ///
+ /// ```text
+ /// for<'a> (Foo1<'a> = C1)
+ /// for<'b> (Foo1<'b> = C2)
+ /// ```
+ ///
+ /// For these equation to be satisfiable, the types `C1` and `C2`
+ /// can only refer to a limited set of regions. For example, `C1`
+ /// can only refer to `'static` and `'a`, and `C2` can only refer
+ /// to `'static` and `'b`. The job of this function is to impose that
+ /// constraint.
+ ///
+ /// Up to this point, C1 and C2 are basically just random type
+ /// inference variables, and hence they may contain arbitrary
+ /// regions. In fact, it is fairly likely that they do! Consider
+ /// this possible definition of `foo`:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
+ /// (&*x, &*y)
+ /// }
+ /// ```
+ ///
+ /// Here, the values for the concrete types of the two impl
+ /// traits will include inference variables:
+ ///
+ /// ```text
+ /// &'0 i32
+ /// &'1 i32
+ /// ```
+ ///
+ /// Ordinarily, the subtyping rules would ensure that these are
+ /// sufficiently large. But since `impl Bar<'a>` isn't a specific
+ /// type per se, we don't get such constraints by default. This
+ /// is where this function comes into play. It adds extra
+ /// constraints to ensure that all the regions which appear in the
+ /// inferred type are regions that could validly appear.
+ ///
+ /// This is actually a bit of a tricky constraint in general. We
+ /// want to say that each variable (e.g., `'0`) can only take on
+ /// values that were supplied as arguments to the opaque type
+ /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
+ /// scope. We don't have a constraint quite of this kind in the current
+ /// region checker.
+ ///
+ /// # The Solution
+ ///
+ /// We generally prefer to make `<=` constraints, since they
+ /// integrate best into the region solver. To do that, we find the
+ /// "minimum" of all the arguments that appear in the substs: that
+ /// is, some region which is less than all the others. In the case
+ /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
+ /// all). Then we apply that as a least bound to the variables
+ /// (e.g., `'a <= '0`).
+ ///
+ /// In some cases, there is no minimum. Consider this example:
+ ///
+ /// ```text
+ /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
+ /// ```
+ ///
+ /// Here we would report a more complex "in constraint", like `'r
+ /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
+ /// the hidden type).
+ ///
+ /// # Constrain regions, not the hidden concrete type
+ ///
+ /// Note that generating constraints on each region `Rc` is *not*
+ /// the same as generating an outlives constraint on `Tc` iself.
+ /// For example, if we had a function like this:
+ ///
+ /// ```rust
+ /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
+ /// (x, y)
+ /// }
+ ///
+ /// // Equivalent to:
+ /// type FooReturn<'a, T> = impl Foo<'a>;
+ /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
+ /// ```
+ ///
+ /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
+ /// is an inference variable). If we generated a constraint that
+ /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
+ /// but this is not necessary, because the opaque type we
+ /// create will be allowed to reference `T`. So we only generate a
+ /// constraint that `'0: 'a`.
+ ///
+ /// # The `free_region_relations` parameter
+ ///
+ /// The `free_region_relations` argument is used to find the
+ /// "minimum" of the regions supplied to a given opaque type.
+ /// It must be a relation that can answer whether `'a <= 'b`,
+ /// where `'a` and `'b` are regions that appear in the "substs"
+ /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
+ ///
+ /// Note that we do not impose the constraints based on the
+ /// generic regions from the `Foo1` definition (e.g., `'x`). This
+ /// is because the constraints we are imposing here is basically
+ /// the concern of the one generating the constraining type C1,
+ /// which is the current function. It also means that we can
+ /// take "implied bounds" into account in some cases:
+ ///
+ /// ```text
+ /// trait SomeTrait<'a, 'b> { }
+ /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
+ /// ```
+ ///
+ /// Here, the fact that `'b: 'a` is known only because of the
+ /// implied bounds from the `&'a &'b u32` parameter, and is not
+ /// "inherent" to the opaque type definition.
+ ///
+ /// # Parameters
+ ///
+ /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
+ /// - `free_region_relations` -- something that can be used to relate
+ /// the free regions (`'a`) that appear in the impl trait.
+ #[instrument(level = "debug", skip(self))]
+ pub fn constrain_opaque_type(
+ &self,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ opaque_defn: &OpaqueTypeDecl<'tcx>,
+ ) {
+ let def_id = opaque_type_key.def_id;
+
+ let tcx = self.tcx;
+
+ let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+
+ debug!(?concrete_ty);
+
+ let first_own_region = match opaque_defn.origin {
+ hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+ // We lower
+ //
+ // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+ //
+ // into
+ //
+ // type foo::<'p0..'pn>::Foo<'q0..'qm>
+ // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+ //
+ // For these types we only iterate over `'l0..lm` below.
+ tcx.generics_of(def_id).parent_count
+ }
+ // These opaque type inherit all lifetime parameters from their
+ // parent, so we have to check them all.
+ hir::OpaqueTyOrigin::TyAlias => 0,
+ };
+
+ // For a case like `impl Foo<'a, 'b>`, we would generate a constraint
+ // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
+ // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`).
+ //
+ // `conflict1` and `conflict2` are the two region bounds that we
+ // detected which were unrelated. They are used for diagnostics.
+
+ // Create the set of choice regions: each region in the hidden
+ // type can be equal to any of the region parameters of the
+ // opaque type definition.
+ let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
+ opaque_type_key.substs[first_own_region..]
+ .iter()
+ .filter_map(|arg| match arg.unpack() {
+ GenericArgKind::Lifetime(r) => Some(r),
+ GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
+ })
+ .chain(std::iter::once(self.tcx.lifetimes.re_static))
+ .collect(),
+ );
+
+ concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx: self.tcx,
+ op: |r| {
+ self.member_constraint(
+ opaque_type_key.def_id,
+ opaque_defn.definition_span,
+ concrete_ty,
+ r,
+ &choice_regions,
+ )
+ },
+ });
+ }
+}
+
+// Visitor that requires that (almost) all regions in the type visited outlive
+// `least_region`. We cannot use `push_outlives_components` because regions in
+// closure signatures are not included in their outlives components. We need to
+// ensure all regions outlive the given bound so that we don't end up with,
+// say, `ReVar` appearing in a return type and causing ICEs when other
+// functions end up with region constraints involving regions from other
+// functions.
+//
+// We also cannot use `for_each_free_region` because for closures it includes
+// the regions parameters from the enclosing item.
+//
+// We ignore any type parameters because impl trait values are assumed to
+// capture all the in-scope type parameters.
+struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
+ tcx: TyCtxt<'tcx>,
+ op: OP,
+}
+
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+where
+ OP: FnMut(ty::Region<'tcx>),
+{
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ t.as_ref().skip_binder().visit_with(self);
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ // ignore bound regions, keep visiting
+ ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+ _ => {
+ (self.op)(r);
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // We're only interested in types involving regions
+ if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+ return ControlFlow::CONTINUE;
+ }
+
+ match ty.kind() {
+ ty::Closure(_, ref substs) => {
+ // Skip lifetime parameters of the enclosing item(s)
+
+ substs.as_closure().tupled_upvars_ty().visit_with(self);
+ substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+ }
+
+ ty::Generator(_, ref substs, _) => {
+ // Skip lifetime parameters of the enclosing item(s)
+ // Also skip the witness type, because that has no free regions.
+
+ substs.as_generator().tupled_upvars_ty().visit_with(self);
+ substs.as_generator().return_ty().visit_with(self);
+ substs.as_generator().yield_ty().visit_with(self);
+ substs.as_generator().resume_ty().visit_with(self);
+ }
+ _ => {
+ ty.super_visit_with(self);
+ }
+ }
+
+ ControlFlow::CONTINUE
+ }
+}
+
+struct Instantiator<'a, 'tcx> {
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value_span: Span,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+impl<'a, 'tcx> Instantiator<'a, 'tcx> {
+ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ let tcx = self.infcx.tcx;
+ value.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| {
+ if ty.references_error() {
+ return tcx.ty_error();
+ } else if let ty::Opaque(def_id, substs) = ty.kind() {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ if let Some(def_id) = def_id.as_local() {
+ let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let parent_def_id = self.infcx.defining_use_anchor;
+ let def_scope_default = || {
+ let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+ parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
+ };
+ let (in_definition_scope, origin) =
+ match tcx.hir().expect_item(opaque_hir_id).kind {
+ // Anonymous `impl Trait`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: Some(parent),
+ origin,
+ ..
+ }) => (parent == parent_def_id.to_def_id(), origin),
+ // Named `type Foo = impl Bar;`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: None,
+ origin,
+ ..
+ }) => (
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+ origin,
+ ),
+ _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ };
+ if in_definition_scope {
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ }
+
+ debug!(
+ "instantiate_opaque_types_in_map: \
+ encountered opaque outside its definition scope \
+ def_id={:?}",
+ def_id,
+ );
+ }
+ }
+
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_opaque_ty(
+ &mut self,
+ ty: Ty<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ origin: hir::OpaqueTyOrigin,
+ ) -> Ty<'tcx> {
+ let infcx = self.infcx;
+ let tcx = infcx.tcx;
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+ // Use the same type variable if the exact same opaque type appears more
+ // than once in the return type (e.g., if it's passed to a type alias).
+ if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
+ debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
+ return opaque_defn.concrete_ty;
+ }
+
+ let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span: self.value_span,
+ });
+
+ // Ideally, we'd get the span where *this specific `ty` came
+ // from*, but right now we just use the span from the overall
+ // value being folded. In simple cases like `-> impl Foo`,
+ // these are the same span, but not in cases like `-> (impl
+ // Foo, impl Bar)`.
+ let definition_span = self.value_span;
+
+ {
+ let mut infcx = self.infcx.inner.borrow_mut();
+ infcx.opaque_types.insert(
+ OpaqueTypeKey { def_id, substs },
+ OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+ );
+ infcx.opaque_types_vars.insert(ty_var, ty);
+ }
+
+ debug!("generated new type inference var {:?}", ty_var.kind());
+
+ let item_bounds = tcx.explicit_item_bounds(def_id);
+
+ self.obligations.reserve(item_bounds.len());
+ for (predicate, _) in item_bounds {
+ debug!(?predicate);
+ let predicate = predicate.subst(tcx, substs);
+ debug!(?predicate);
+
+ // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
+ let predicate = predicate.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| match ty.kind() {
+ ty::Projection(projection_ty) => infcx.infer_projection(
+ self.param_env,
+ *projection_ty,
+ traits::ObligationCause::misc(self.value_span, self.body_id),
+ 0,
+ &mut self.obligations,
+ ),
+ _ => ty,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ });
+ debug!(?predicate);
+
+ if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
+ if projection.ty.references_error() {
+ // No point on adding these obligations since there's a type error involved.
+ return tcx.ty_error();
+ }
+ }
+ // Change the predicate to refer to the type variable,
+ // which will be the concrete type instead of the opaque type.
+ // This also instantiates nested instances of `impl Trait`.
+ let predicate = self.instantiate_opaque_types_in_map(predicate);
+
+ let cause =
+ traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
+
+ // Require that the predicate holds for the concrete type.
+ debug!(?predicate);
+ self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+ }
+
+ ty_var
+ }
+}
+
+/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
+///
+/// Example:
+/// ```rust
+/// pub mod foo {
+/// pub mod bar {
+/// pub trait Bar { .. }
+///
+/// pub type Baz = impl Bar;
+///
+/// fn f1() -> Baz { .. }
+/// }
+///
+/// fn f2() -> bar::Baz { .. }
+/// }
+/// ```
+///
+/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
+/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
+/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
+fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
+ let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ // Named opaque types can be defined by any siblings or children of siblings.
+ let scope = tcx.hir().get_defining_scope(opaque_hir_id);
+ // We walk up the node tree until we hit the root or the scope of the opaque type.
+ while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
+ hir_id = tcx.hir().get_parent_item(hir_id);
+ }
+ // Syntactically, we are allowed to define the concrete type if:
+ let res = hir_id == scope;
+ trace!(
+ "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
+ tcx.hir().find(hir_id),
+ tcx.hir().get(opaque_hir_id),
+ res
+ );
+ res
+}
#![feature(box_patterns)]
#![feature(extend_one)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_span::Span;
pub use self::FulfillmentErrorCode::*;
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
+impl PredicateObligation<'tcx> {
+ /// Flips the polarity of the inner predicate.
+ ///
+ /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
+ Some(PredicateObligation {
+ cause: self.cause.clone(),
+ param_env: self.param_env,
+ predicate: self.predicate.flip_polarity(tcx)?,
+ recursion_depth: self.recursion_depth,
+ })
+ }
+}
+
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateObligation<'_>, 32);
}
impl<'tcx> TraitObligation<'tcx> {
+ pub fn polarity(&self) -> ty::ImplPolarity {
+ self.predicate.skip_binder().polarity
+ }
+
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
self.predicate.map_bound(|p| p.self_ty())
}
pub(crate) output_file: Option<PathBuf>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
}
impl Compiler {
let cfg = cfgspecs
.into_iter()
.map(|s| {
- let sess = ParseSess::with_silent_emitter();
+ let sess = ParseSess::with_silent_emitter(Some(format!(
+ "this error occurred on the command line: `--cfg={}`",
+ s
+ )));
let filename = FileName::cfg_spec_source_code(&s);
let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
///
/// The second parameter is local providers and the third parameter is external providers.
pub override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
/// This is a callback from the driver that is called to create a codegen backend.
pub make_codegen_backend:
use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
*providers
});
-pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
- let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
+ let mut extern_providers = ExternProviders::default();
rustc_metadata::provide_extern(&mut extern_providers);
rustc_codegen_ssa::provide_extern(&mut extern_providers);
extern_providers
codegen_backend.provide(&mut local_providers);
let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
- codegen_backend.provide(&mut extern_providers);
codegen_backend.provide_extern(&mut extern_providers);
if let Some(callback) = compiler.override_queries {
dep_graph,
queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
queries.as_dyn(),
+ rustc_query_impl::query_callbacks(arena),
crate_name,
outputs,
)
use rustc_session::config::InstrumentCoverage;
use rustc_session::config::Strip;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
+use rustc_session::config::{
+ rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
+};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
use rustc_session::config::{
Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
tracked!(instrument_mcount, true);
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
+ tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_opt_level, Some(4));
tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
+ tracked!(no_unique_section_names, true);
tracked!(no_profiler_runtime, true);
tracked!(osx_rpath_install_name, true);
tracked!(panic_abort_tests, true);
impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
- !matches!(
- self,
- EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
- )
+ match self {
+ EscapeError::UnskippedWhitespaceWarning => false,
+ EscapeError::MultipleSkippedLinesWarning => false,
+ _ => true,
+ }
}
}
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
}
let tail = &tail[first_non_space..];
- if let Some(c) = tail.chars().next() {
+ if let Some(c) = tail.chars().nth(0) {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
let end = start + first_non_space + c.len_utf8() + 1;
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
- let expr_span = expr.span.ctxt().outer_expn_data().call_site;
diag.span_suggestion(
- receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
+ receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
"or remove `.into_iter()` to iterate by value",
String::new(),
Applicability::MaybeIncorrect,
return;
}
+ // If the method is an impl for an item with docs_hidden, don't doc.
+ if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let impl_ty = cx.tcx.type_of(parent);
+ let outerdef = match impl_ty.kind() {
+ ty::Adt(def, _) => Some(def.did),
+ ty::Foreign(def_id) => Some(*def_id),
+ _ => None,
+ };
+ let is_hidden = match outerdef {
+ Some(id) => cx.tcx.is_doc_hidden(id),
+ None => false,
+ };
+ if is_hidden {
+ return;
+ }
+ }
+
let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
}
use self::TargetLint::*;
+use crate::hidden_unicode_codepoints::UNICODE_TEXT_FLOW_CHARS;
use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use rustc_ast as ast;
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi;
use tracing::debug;
// Now, set up surrounding context.
let sess = self.sess();
match diagnostic {
+ BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => {
+ let spans: Vec<_> = content
+ .char_indices()
+ .filter_map(|(i, c)| {
+ UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+ let lo = span.lo() + BytePos(2 + i as u32);
+ (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+ })
+ })
+ .collect();
+ let (an, s) = match spans.len() {
+ 1 => ("an ", ""),
+ _ => ("", "s"),
+ };
+ db.span_label(span, &format!(
+ "this comment contains {}invisible unicode text flow control codepoint{}",
+ an,
+ s,
+ ));
+ for (c, span) in &spans {
+ db.span_label(*span, format!("{:?}", c));
+ }
+ db.note(
+ "these kind of unicode codepoints change the way text flows on \
+ applications that support them, but can cause confusion because they \
+ change the order of characters on the screen",
+ );
+ if !spans.is_empty() {
+ db.multipart_suggestion_with_style(
+ "if their presence wasn't intentional, you can remove them",
+ spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
+ }
+ },
BuiltinLintDiagnostics::Normal => (),
BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
let (sugg, app) = match sess.source_map().span_to_snippet(span) {
--- /dev/null
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_ast as ast;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_span::{BytePos, Span, Symbol};
+
+declare_lint! {
+ /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the
+ /// visual representation of text on screen in a way that does not correspond to their on
+ /// memory representation.
+ ///
+ /// ### Explanation
+ ///
+ /// The unicode characters `\u{202A}`, `\u{202B}`, `\u{202D}`, `\u{202E}`, `\u{2066}`,
+ /// `\u{2067}`, `\u{2068}`, `\u{202C}` and `\u{2069}` make the flow of text on screen change
+ /// its direction on software that supports these codepoints. This makes the text "abc" display
+ /// as "cba" on screen. By leveraging software that supports these, people can write specially
+ /// crafted literals that make the surrounding code seem like it's performing one action, when
+ /// in reality it is performing another. Because of this, we proactively lint against their
+ /// presence to avoid surprises.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(text_direction_codepoint_in_literal)]
+ /// fn main() {
+ /// println!("{:?}", '');
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ pub TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
+ Deny,
+ "detect special Unicode codepoints that affect the visual representation of text on screen, \
+ changing the direction in which text flows",
+}
+
+declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]);
+
+crate const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
+ '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
+ '\u{2069}',
+];
+
+impl HiddenUnicodeCodepoints {
+ fn lint_text_direction_codepoint(
+ &self,
+ cx: &EarlyContext<'_>,
+ text: Symbol,
+ span: Span,
+ padding: u32,
+ point_at_inner_spans: bool,
+ label: &str,
+ ) {
+ // Obtain the `Span`s for each of the forbidden chars.
+ let spans: Vec<_> = text
+ .as_str()
+ .char_indices()
+ .filter_map(|(i, c)| {
+ UNICODE_TEXT_FLOW_CHARS.contains(&c).then(|| {
+ let lo = span.lo() + BytePos(i as u32 + padding);
+ (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+ })
+ })
+ .collect();
+
+ cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
+ let mut err = lint.build(&format!(
+ "unicode codepoint changing visible direction of text present in {}",
+ label
+ ));
+ let (an, s) = match spans.len() {
+ 1 => ("an ", ""),
+ _ => ("", "s"),
+ };
+ err.span_label(
+ span,
+ &format!(
+ "this {} contains {}invisible unicode text flow control codepoint{}",
+ label, an, s,
+ ),
+ );
+ if point_at_inner_spans {
+ for (c, span) in &spans {
+ err.span_label(*span, format!("{:?}", c));
+ }
+ }
+ err.note(
+ "these kind of unicode codepoints change the way text flows on applications that \
+ support them, but can cause confusion because they change the order of \
+ characters on the screen",
+ );
+ if point_at_inner_spans && !spans.is_empty() {
+ err.multipart_suggestion_with_style(
+ "if their presence wasn't intentional, you can remove them",
+ spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
+ err.multipart_suggestion(
+ "if you want to keep them but make them visible in your source code, you can \
+ escape them",
+ spans
+ .into_iter()
+ .map(|(c, span)| {
+ let c = format!("{:?}", c);
+ (span, c[1..c.len() - 1].to_string())
+ })
+ .collect(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+ // should do the same here to provide the same good suggestions as we do for
+ // literals above.
+ err.note("if their presence wasn't intentional, you can remove them");
+ err.note(&format!(
+ "if you want to keep them but make them visible in your source code, you can \
+ escape them: {}",
+ spans
+ .into_iter()
+ .map(|(c, _)| { format!("{:?}", c) })
+ .collect::<Vec<String>>()
+ .join(", "),
+ ));
+ }
+ err.emit();
+ });
+ }
+}
+impl EarlyLintPass for HiddenUnicodeCodepoints {
+ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
+ if let ast::AttrKind::DocComment(_, comment) = attr.kind {
+ if comment.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+ self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment");
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+ // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
+ let (text, span, padding) = match &expr.kind {
+ ast::ExprKind::Lit(ast::Lit { token, kind, span }) => {
+ let text = token.symbol;
+ if !text.as_str().contains(UNICODE_TEXT_FLOW_CHARS) {
+ return;
+ }
+ let padding = match kind {
+ // account for `"` or `'`
+ ast::LitKind::Str(_, ast::StrStyle::Cooked) | ast::LitKind::Char(_) => 1,
+ // account for `r###"`
+ ast::LitKind::Str(_, ast::StrStyle::Raw(val)) => *val as u32 + 2,
+ _ => return,
+ };
+ (text, span, padding)
+ }
+ _ => return,
+ };
+ self.lint_text_direction_codepoint(cx, text, *span, padding, true, "literal");
+ }
+}
mod context;
mod early;
mod enum_intrinsics_non_enums;
+pub mod hidden_unicode_codepoints;
mod internal;
mod late;
mod levels;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
+use hidden_unicode_codepoints::*;
use internal::*;
use methods::*;
use non_ascii_idents::*;
DeprecatedAttr: DeprecatedAttr::new(),
WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents,
+ HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
IncompleteFeatures: IncompleteFeatures,
RedundantSemicolons: RedundantSemicolons,
UnusedDocComment: UnusedDocComment,
UNUSED_LABELS,
UNUSED_PARENS,
UNUSED_BRACES,
- MUST_NOT_SUSPEND,
REDUNDANT_SEMICOLONS
);
///
/// ### Explanation
///
- /// The parenthesis are not needed, and should be removed. This is the
+ /// The parentheses are not needed, and should be removed. This is the
/// preferred style for writing these expressions.
pub(super) UNUSED_PARENS,
Warn,
///
/// ```rust
/// #![feature(must_not_suspend)]
+ /// #![warn(must_not_suspend)]
///
/// #[must_not_suspend]
/// struct SyncThing {}
/// `MutexGuard`'s)
///
pub MUST_NOT_SUSPEND,
- Warn,
+ Allow,
"use of a `#[must_not_suspend]` value across a yield point",
+ @feature_gate = rustc_span::symbol::sym::must_not_suspend;
}
declare_lint! {
/// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- Warn,
+ Deny,
"detects proc macro derives using inaccessible names from parent modules",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
BREAK_WITH_LABEL_AND_LOOP,
UNUSED_ATTRIBUTES,
NON_EXHAUSTIVE_OMITTED_PATTERNS,
+ TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
DEREF_INTO_DYN_SUPERTRAIT,
]
}
/// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_BACK_COMPAT,
- Warn,
+ Deny,
"detects usage of old versions of certain proc-macro crates",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
@feature_gate = sym::non_exhaustive_omitted_patterns_lint;
}
+declare_lint! {
+ /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that
+ /// change the visual representation of text on screen in a way that does not correspond to
+ /// their on memory representation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(text_direction_codepoint_in_comment)]
+ /// fn main() {
+ /// println!("{:?}"); // '');
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unicode allows changing the visual flow of text on screen in order to support scripts that
+ /// are written right-to-left, but a specially crafted comment can make code that will be
+ /// compiled appear to be part of a comment, depending on the software used to read the code.
+ /// To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny
+ /// their use.
+ pub TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ Deny,
+ "invisible directionality-changing codepoints in comment"
+}
+
declare_lint! {
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
TrailingMacro(bool, Ident),
BreakWithLabelAndLoop(Span),
NamedAsmLabel(String),
+ UnicodeTextFlow(Span, String),
}
/// Lints that are buffered up early on in the `Session` before the
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
- println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
+ println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
} else {
println!("cargo:rustc-link-lib=static={}", stdcppname);
}
// Libstdc++ depends on pthread which Rust doesn't link on MinGW
// since nothing else requires it.
if target.contains("windows-gnu") {
- println!("cargo:rustc-link-lib=static-nobundle=pthread");
+ println!("cargo:rustc-link-lib=static:-bundle=pthread");
}
}
extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
-#if LLVM_VERSION_GE(11, 0)
WriteSectionNameToString(M, IPSK_covfun, Str);
-// else do nothing; the `Version` check will abort codegen on the Rust side
-#endif
}
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-#if LLVM_VERSION_GE(11, 0)
return coverage::CovMapVersion::Version4;
-#else
- return coverage::CovMapVersion::Version3;
-#endif
}
#include "llvm/Support/Host.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
+#if LLVM_VERSION_LT(14, 0)
+#include "llvm/Support/TargetRegistry.h"
+#else
+#include "llvm/MC/TargetRegistry.h"
+#endif
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
-#if LLVM_VERSION_LT(11, 0)
-DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
- LLVMPassManagerBuilderRef)
-#endif
extern "C" void LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
bool FunctionSections,
bool DataSections,
+ bool UniqueSectionNames,
bool TrapUnreachable,
bool Singlethread,
bool AsmComments,
}
Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections;
+ Options.UniqueSectionNames = UniqueSectionNames;
Options.MCOptions.AsmVerbose = AsmComments;
Options.MCOptions.PreserveAsmComments = AsmComments;
Options.MCOptions.ABIName = ABIStr;
PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
-#if LLVM_VERSION_GE(12, 0)
PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
std::string PassName = Pass.str();
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) {
AfterPassCallback(LlvmSelfProfiler);
});
-#else
- PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
- StringRef Pass, llvm::Any Ir) {
- std::string PassName = Pass.str();
- std::string IrName = LLVMRustwrappedIrGetName(Ir);
- BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
- return true;
- });
-
- PIC.registerAfterPassCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-
- PIC.registerAfterPassInvalidatedCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-#endif
PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
PTO.LoopInterleaving = UnrollLoops;
PTO.LoopVectorization = LoopVectorize;
PTO.SLPVectorization = SLPVectorize;
-#if LLVM_VERSION_GE(12, 0)
PTO.MergeFunctions = MergeFunctions;
-#else
- // MergeFunctions is not supported by NewPM in older LLVM versions.
- (void) MergeFunctions;
-#endif
// FIXME: We may want to expose this as an option.
bool DebugPassManager = false;
PassInstrumentationCallbacks PIC;
-#if LLVM_VERSION_GE(12, 0)
StandardInstrumentations SI(DebugPassManager);
-#else
- StandardInstrumentations SI;
-#endif
SI.registerCallbacks(PIC);
if (LlvmSelfProfiler){
PGOOptions::NoCSAction, DebugInfoForProfiling);
}
-#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
- PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
-#else
- PassBuilder PB(TM, PTO, PGOOpt, &PIC);
-#endif
-
#if LLVM_VERSION_GE(13, 0)
+ PassBuilder PB(TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
#else
+ PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM(DebugPassManager);
FunctionAnalysisManager FAM(DebugPassManager);
CGSCCAnalysisManager CGAM(DebugPassManager);
// PassBuilder does not create a pipeline.
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(11, 0)
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
OptimizerLastEPCallbacks;
-#else
- std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
- OptimizerLastEPCallbacks;
-#endif
if (VerifyIR) {
PipelineStartEPCallbacks.push_back(
SanitizerOptions->SanitizeMemoryTrackOrigins,
SanitizerOptions->SanitizeMemoryRecover,
/*CompileKernel=*/false);
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [Options](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(MemorySanitizerPass(Options));
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(MemorySanitizerPass(Options));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeThread) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ThreadSanitizerPass());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(ThreadSanitizerPass());
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [&](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(AddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
- /*UseAfterScope=*/true));
- }
- );
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ModuleAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeHWAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(HWAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
- }
- );
-#endif
}
}
// At the same time, the LTO pipelines do support O0 and using them is required.
bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
for (const auto &C : OptimizerLastEPCallbacks)
// Pass false as we manually schedule ThinLTOBufferPasses below.
MPM = PB.buildO0DefaultPipeline(OptLevel, /* PreLinkLTO */ false);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- C(MPM, OptLevel);
-
-# if LLVM_VERSION_GE(11, 0)
- for (const auto &C : OptimizerLastEPCallbacks)
- C(MPM, OptLevel);
-# else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-# endif
-
- MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
-
- if (PGOOpt) {
- PB.addPGOInstrPassesForO0(
- MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
- /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
- }
-#endif
} else {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- PB.registerPipelineStartEPCallback([C, OptLevel](ModulePassManager &MPM) {
- C(MPM, OptLevel);
- });
-#endif
if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
for (const auto &C : OptimizerLastEPCallbacks)
PB.registerOptimizerLastEPCallback(C);
MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
break;
case LLVMRustOptStage::PreLinkThinLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
// The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
// passes may still run afterwards. This means we need to run the buffer passes again.
// before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
if (OptimizerLastEPCallbacks.empty())
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
-#if LLVM_VERSION_GE(11, 0)
for (const auto &C : OptimizerLastEPCallbacks)
C(MPM, OptLevel);
-#else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-#endif
break;
case LLVMRustOptStage::PreLinkFatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
break;
case LLVMRustOptStage::ThinLTO:
// FIXME: Does it make sense to pass the ModuleSummaryIndex?
// It only seems to be needed for C++ specific optimizations.
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
case LLVMRustOptStage::FatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
}
}
// `ProcessThinLTOModule` function. Here they're split up into separate steps
// so rustc can save off the intermediate bytecode between each step.
-#if LLVM_VERSION_GE(11, 0)
static bool
clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
// When linking an ELF shared object, dso_local should be dropped. We
Mod.getPIELevel() == PIELevel::Default;
return ClearDSOLocalOnDeclarations;
}
-#endif
extern "C" bool
LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
Module &Mod = *unwrap(M);
TargetMachine &Target = *unwrap(TM);
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
-#else
- bool error = renameModuleForThinLTO(Mod, Data->Index);
-#endif
if (error) {
LLVMRustSetLastError("renameModuleForThinLTO failed");
return MOrErr;
};
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
-#else
- FunctionImporter Importer(Data->Index, Loader);
-#endif
Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
if (!Result) {
LLVMRustSetLastError(toString(Result.takeError()).c_str());
extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
LLVMTypeRef Ty) {
CallBase *Call = unwrap<CallBase>(Instr);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(Call->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
-#endif
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
LLVMTypeRef Ty) {
Function *F = unwrap<Function>(Fn);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(F->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
-#endif
AddAttribute(F, Index, Attr);
}
return DIFile::ChecksumKind::CSK_MD5;
case LLVMRustChecksumKind::SHA1:
return DIFile::ChecksumKind::CSK_SHA1;
-#if (LLVM_VERSION_MAJOR >= 11)
case LLVMRustChecksumKind::SHA256:
return DIFile::ChecksumKind::CSK_SHA256;
-#endif
default:
report_fatal_error("bad ChecksumKind.");
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
-#if LLVM_VERSION_GE(11, 0)
bool IsDefault = false; // FIXME: should we ever set this true?
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
-#else
- return wrap(Builder->createTemplateTypeParameter(
- unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
-#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
LLVMMetadataRef ScopeRef,
LLVMMetadataRef InlinedAt) {
-#if LLVM_VERSION_GE(12, 0)
MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef);
DILocation *Loc = DILocation::get(
Scope->getContext(), Line, Column, Scope,
unwrapDIPtr<MDNode>(InlinedAt));
return wrap(Loc);
-#else
- DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(ScopeRef),
- unwrapDIPtr<MDNode>(InlinedAt));
- return wrap(debug_loc.getAsMDNode());
-#endif
}
extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
return LLVMArrayTypeKind;
case Type::PointerTyID:
return LLVMPointerTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::FixedVectorTyID:
return LLVMVectorTypeKind;
-#else
- case Type::VectorTyID:
- return LLVMVectorTypeKind;
-#endif
case Type::X86_MMXTyID:
return LLVMX86_MMXTypeKind;
case Type::TokenTyID:
return LLVMTokenTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::ScalableVectorTyID:
return LLVMScalableVectorTypeKind;
case Type::BFloatTyID:
return LLVMBFloatTypeKind;
-#endif
-#if LLVM_VERSION_GE(12, 0)
case Type::X86_AMXTyID:
return LLVMX86_AMXTypeKind;
-#endif
}
report_fatal_error("Unhandled TypeID.");
}
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMinReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMaxReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
#![feature(nll)]
-#![feature(static_nobundle)]
+#![feature(native_link_modifiers)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
// NOTE: This crate only exists to allow linking on mingw targets.
}
if meta.path().is_ident("project") {
if let Meta::List(list) = meta {
- if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
- attrs.project = meta.path().get_ident().cloned();
- any_attr = true;
+ if let Some(nested) = list.nested.iter().next() {
+ if let NestedMeta::Meta(meta) = nested {
+ attrs.project = meta.path().get_ident().cloned();
+ any_attr = true;
+ }
}
}
}
Storage(Type),
/// Cache the query to disk if the `Expr` returns true.
- Cache(Option<(IdentOrWild, IdentOrWild)>, Block),
+ Cache(Option<IdentOrWild>, Block),
/// Custom code to load the query from disk.
LoadCached(Ident, Ident, Block),
/// Always evaluate the query, ignoring its dependencies
EvalAlways(Ident),
+
+ /// Use a separate query provider for local and extern crates
+ SeparateProvideExtern(Ident),
}
impl Parse for QueryModifier {
let args;
parenthesized!(args in input);
let tcx = args.parse()?;
- args.parse::<Token![,]>()?;
- let value = args.parse()?;
- Some((tcx, value))
+ Some(tcx)
} else {
None
};
Ok(QueryModifier::Anon(modifier))
} else if modifier == "eval_always" {
Ok(QueryModifier::EvalAlways(modifier))
+ } else if modifier == "separate_provide_extern" {
+ Ok(QueryModifier::SeparateProvideExtern(modifier))
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
storage: Option<Type>,
/// Cache the query to disk if the `Block` returns true.
- cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>,
+ cache: Option<(Option<IdentOrWild>, Block)>,
/// Custom code to load the query from disk.
load_cached: Option<(Ident, Ident, Block)>,
// Always evaluate the query, ignoring its dependencies
eval_always: Option<Ident>,
+
+ /// Use a separate query provider for local and extern crates
+ separate_provide_extern: Option<Ident>,
}
/// Process query modifiers into a struct, erroring on duplicates
let mut no_hash = None;
let mut anon = None;
let mut eval_always = None;
+ let mut separate_provide_extern = None;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
}
eval_always = Some(ident);
}
+ QueryModifier::SeparateProvideExtern(ident) => {
+ if separate_provide_extern.is_some() {
+ panic!(
+ "duplicate modifier `separate_provide_extern` for query `{}`",
+ query.name
+ );
+ }
+ separate_provide_extern = Some(ident);
+ }
}
}
let desc = desc.unwrap_or_else(|| {
no_hash,
anon,
eval_always,
+ separate_provide_extern,
}
}
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
// Use custom code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- #tcx: QueryCtxt<'tcx>,
- #id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- #block
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|#tcx, #id| { #block });
}
} else {
// Use the default code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- tcx: QueryCtxt<'tcx>,
- id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id));
}
};
let tcx = args
.as_ref()
.map(|t| {
- let t = &(t.0).0;
- quote! { #t }
- })
- .unwrap_or_else(|| quote! { _ });
- let value = args
- .as_ref()
- .map(|t| {
- let t = &(t.1).0;
+ let t = &t.0;
quote! { #t }
})
.unwrap_or_else(|| quote! { _ });
// expr is a `Block`, meaning that `{ #expr }` gets expanded
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
quote! {
- #[inline]
#[allow(unused_variables, unused_braces)]
- fn cache_on_disk(
- #tcx: QueryCtxt<'tcx>,
- #key: &Self::Key,
- #value: Option<&Self::Value>
- ) -> bool {
+ #[inline]
+ fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
#expr
}
if modifiers.load_cached.is_some() {
panic!("load_cached modifier on query `{}` without a cache modifier", name);
}
- quote! {}
+ quote! {
+ #[inline]
+ fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+ false
+ }
+
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> = None;
+ }
};
let (tcx, desc) = modifiers.desc;
let desc = quote! {
#[allow(unused_variables)]
- fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
+ fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String {
let (#tcx, #key) = (*tcx, key);
::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
}
};
impls.extend(quote! {
- impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::#name<'tcx> {
+ (#name<$tcx:tt>) => {
#desc
#cache
- }
+ };
});
}
if let Some(eval_always) = &modifiers.eval_always {
attributes.push(quote! { (#eval_always) });
};
+ // Pass on the separate_provide_extern modifier
+ if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
+ attributes.push(quote! { (#separate_provide_extern) });
+ }
// This uses the span of the query definition for the commas,
// which can be important if we later encounter any ambiguity
}
#[macro_export]
macro_rules! rustc_query_description {
- () => { #query_description_stream }
+ #query_description_stream
}
})
}
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
let field_binding = &info.binding.binding;
- let option_ty = option_inner_ty(info.ty);
+ let option_ty = option_inner_ty(&info.ty);
let generated_code = self.generate_non_option_field_code(
attr,
FieldInfo {
vis: info.vis,
binding: info.binding,
- ty: option_ty.unwrap_or(info.ty),
+ ty: option_ty.unwrap_or(&info.ty),
span: info.span,
},
)?;
let formatted_str = self.build_format(&s.value(), attr.span());
match name {
"message" => {
- if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+ if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.set_span(*#field_binding);
#diag.set_primary_message(#formatted_str);
}
}
"label" => {
- if type_matches_path(info.ty, &["rustc_span", "Span"]) {
+ if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.span_label(*#field_binding, #formatted_str);
}
[dependencies]
libc = "0.2"
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
snap = "1"
tracing = "0.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(proc_macro_internals)]
use std::io::{Read, Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::{cmp, fmt, fs};
-use tracing::{debug, info, warn};
+use tracing::{debug, info};
#[derive(Clone)]
crate struct CrateLocator<'a> {
let mut err_data: Option<Vec<PathBuf>> = None;
for (lib, kind) in m {
info!("{} reading metadata from: {}", flavor, lib.display());
+ if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) {
+ // Empty files will cause get_metadata_section to fail. Rmeta
+ // files can be empty, for example with binaries (which can
+ // often appear with `cargo check` when checking a library as
+ // a unittest). We don't want to emit a user-visible warning
+ // in this case as it is not a real problem.
+ debug!("skipping empty file");
+ continue;
+ }
let (hash, metadata) =
match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
Ok(blob) => {
}
}
Err(err) => {
- warn!("no metadata found: {}", err);
+ info!("no metadata found: {}", err);
continue;
}
};
let len = BytePos::decode(decoder)?;
let hi = lo + len;
- let sess = if let Some(sess) = decoder.sess {
- sess
- } else {
+ let Some(sess) = decoder.sess else {
bug!("Cannot decode Span without Session.")
};
}
}
- if let EntryKind::Mod(data) = kind {
- for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+ if let EntryKind::Mod(exports) = kind {
+ for exp in exports.decode((self, sess)) {
match exp.res {
Res::Def(DefKind::Macro(..), _) => {}
_ if macros_only => continue,
}
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
- if let EntryKind::Mod(m) = self.kind(id) {
- m.decode((self, sess)).expansion
- } else {
- panic!("Expected module, found {:?}", self.local_def_id(id))
+ match self.kind(id) {
+ EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+ self.get_expn_that_defined(id, sess)
+ }
+ _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
}
}
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
use rustc_session::utils::NativeLibKind;
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
$($name:ident => $compute:block)*) => {
- pub fn provide_extern(providers: &mut Providers) {
+ pub fn provide_extern(providers: &mut ExternProviders) {
$(fn $name<$lt>(
$tcx: TyCtxt<$lt>,
def_id_arg: ty::query::query_keys::$name<$lt>,
$compute
})*
- *providers = Providers {
+ *providers = ExternProviders {
$($name,)*
..*providers
};
}
}
+impl IntoArgs for ty::InstanceDef<'tcx> {
+ fn into_args(self) -> (DefId, DefId) {
+ (self.def_id(), self.def_id())
+ }
+}
+
provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { cdata.get_type(def_id.index, tcx) }
generics_of => { cdata.get_generics(def_id.index, tcx.sess) }
Lazy::empty()
};
- let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
- record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+ 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 {
record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
item_id.def_id.local_def_index
}
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
- let unused = self.tcx.unused_generic_params(def_id);
+ let instance =
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
+ let unused = self.tcx.unused_generic_params(instance);
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<ModData>),
+ Mod(Lazy<[Export]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
#[derive(Encodable, Decodable)]
struct RenderedConst(String);
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
- reexports: Lazy<[Export]>,
- expansion: ExpnId,
-}
-
#[derive(MetadataEncodable, MetadataDecodable)]
struct FnData {
asyncness: hir::IsAsync,
either = "1.5.0"
gsgdt = "0.1.2"
tracing = "0.1"
+rustc-rayon = "0.3.1"
rustc-rayon-core = "0.3.1"
polonius-engine = "0.13.0"
rustc_apfloat = { path = "../rustc_apfloat" }
[] tys: rustc_middle::ty::TyS<$tcx>,
[] predicates: rustc_middle::ty::PredicateInner<$tcx>,
- // HIR query types
- [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
- [few] hir_definitions: rustc_hir::definitions::Definitions,
- [] hir_owner: rustc_middle::hir::Owner<$tcx>,
- [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
-
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena
// (during lowering) and the `librustc_middle` arena (for decoding MIR)
// This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
[decode] span: rustc_span::Span,
[decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+
+ [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
], $tcx);
)
}
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
/// jump table instead of large matches.
pub struct DepKindStruct {
- /// Whether the DepNode has parameters (query keys).
- pub(super) has_params: bool,
-
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
/// When their result is needed, it is recomputed. They are useful for fine-grained
/// dependency tracking, and caching within one compiler invocation.
- pub(super) is_anon: bool,
+ pub is_anon: bool,
/// Eval-always queries do not track their dependencies, and are always recomputed, even if
/// their inputs have not changed since the last compiler invocation. The result is still
/// cached within one compiler invocation.
- pub(super) is_eval_always: bool,
+ pub is_eval_always: bool,
/// Whether the query key can be recovered from the hashed fingerprint.
/// See [DepNodeParams] trait for the behaviour of each key type.
- // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style
- // can be made a specialized associated const.
- fingerprint_style: fn() -> FingerprintStyle,
-}
-
-impl std::ops::Deref for DepKind {
- type Target = DepKindStruct;
- fn deref(&self) -> &DepKindStruct {
- &DEP_KINDS[*self as usize]
- }
+ pub fingerprint_style: FingerprintStyle,
+
+ /// The red/green evaluation system will try to mark a specific DepNode in the
+ /// dependency graph as green by recursively trying to mark the dependencies of
+ /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+ /// where we don't know if it is red or green and we therefore actually have
+ /// to recompute its value in order to find out. Since the only piece of
+ /// information that we have at that point is the `DepNode` we are trying to
+ /// re-evaluate, we need some way to re-run a query from just that. This is what
+ /// `force_from_dep_node()` implements.
+ ///
+ /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+ /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+ /// is usually constructed by computing a stable hash of the query-key that the
+ /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+ /// back from hash to query-key (since hash functions are not reversible). For
+ /// this reason `force_from_dep_node()` is expected to fail from time to time
+ /// because we just cannot find out, from the `DepNode` alone, what the
+ /// corresponding query-key is and therefore cannot re-run the query.
+ ///
+ /// The system deals with this case letting `try_mark_green` fail which forces
+ /// the root query to be re-evaluated.
+ ///
+ /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+ /// Fortunately, we can use some contextual information that will allow us to
+ /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+ /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+ /// valid `DefPathHash`. Since we also always build a huge table that maps every
+ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+ /// everything we need to re-run the query.
+ ///
+ /// Take the `mir_promoted` query as an example. Like many other queries, it
+ /// just has a single parameter: the `DefId` of the item it will compute the
+ /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+ /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+ /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+ /// `DefId` in `tcx.def_path_hash_to_def_id`.
+ pub force_from_dep_node: Option<fn(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool>,
+
+ /// Invoke a query to put the on-disk cached value in memory.
+ pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'_>, DepNode)>,
}
impl DepKind {
#[inline(always)]
- pub fn fingerprint_style(&self) -> FingerprintStyle {
+ pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
// Only fetch the DepKindStruct once.
- let data: &DepKindStruct = &**self;
+ let data = tcx.query_kind(self);
if data.is_anon {
return FingerprintStyle::Opaque;
}
-
- (data.fingerprint_style)()
- }
-}
-
-// erase!() just makes tokens go away. It's used to specify which macro argument
-// is repeated (i.e., which sub-expression of the macro we are in) but don't need
-// to actually use any of the arguments.
-macro_rules! erase {
- ($x:tt) => {{}};
-}
-
-macro_rules! is_anon_attr {
- (anon) => {
- true
- };
- ($attr:ident) => {
- false
- };
-}
-
-macro_rules! is_eval_always_attr {
- (eval_always) => {
- true
- };
- ($attr:ident) => {
- false
- };
-}
-
-macro_rules! contains_anon_attr {
- ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false});
-}
-
-macro_rules! contains_eval_always_attr {
- ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false});
-}
-
-#[allow(non_upper_case_globals)]
-pub mod dep_kind {
- use super::*;
- use crate::ty::query::query_keys;
- use rustc_query_system::dep_graph::FingerprintStyle;
-
- // We use this for most things when incr. comp. is turned off.
- pub const Null: DepKindStruct = DepKindStruct {
- has_params: false,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Unit,
- };
-
- pub const TraitSelect: DepKindStruct = DepKindStruct {
- has_params: false,
- is_anon: true,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Unit,
- };
-
- pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
- has_params: true,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Opaque,
- };
-
- pub const CompileMonoItem: DepKindStruct = DepKindStruct {
- has_params: true,
- is_anon: false,
- is_eval_always: false,
-
- fingerprint_style: || FingerprintStyle::Opaque,
- };
-
- macro_rules! define_query_dep_kinds {
- ($(
- [$($attrs:tt)*]
- $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
- ,)*) => (
- $(pub const $variant: DepKindStruct = {
- const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false;
- const is_anon: bool = contains_anon_attr!($($attrs)*);
- const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
-
- #[inline(always)]
- fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle {
- <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
- ::fingerprint_style()
- }
-
- DepKindStruct {
- has_params,
- is_anon,
- is_eval_always,
- fingerprint_style,
- }
- };)*
- );
+ data.fingerprint_style
}
-
- rustc_dep_node_append!([define_query_dep_kinds!][]);
}
macro_rules! define_dep_nodes {
) => (
#[macro_export]
macro_rules! make_dep_kind_array {
- ($mod:ident) => {[ $(($mod::$variant),)* ]};
+ ($mod:ident) => {[ $($mod::$variant()),* ]};
}
- static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind);
-
- /// This enum serves as an index into the `DEP_KINDS` array.
+ /// This enum serves as an index into arrays built by `make_dep_kind_array`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
#[allow(non_camel_case_types)]
pub enum DepKind {
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
/// Extracts the DefId corresponding to this DepNode. This will work
/// if two conditions are met:
fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
/// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>;
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<Self, ()>;
/// Used in testing
fn has_label_string(label: &str) -> bool;
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
- debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash);
+ fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
+ debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
}
/// refers to something from the previous compilation session that
/// has been removed.
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
- if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash {
- Some(
- tcx.on_disk_cache
- .as_ref()?
- .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())),
- )
+ if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
+ Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())))
} else {
None
}
}
/// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
+ fn from_label_string(
+ tcx: TyCtxt<'_>,
+ label: &str,
+ def_path_hash: DefPathHash,
+ ) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
- match kind.fingerprint_style() {
+ match kind.fingerprint_style(tcx) {
FingerprintStyle::Opaque => Err(()),
- FingerprintStyle::Unit => {
- if !kind.has_params {
- Ok(DepNode::new_no_params(kind))
- } else {
- Err(())
- }
+ FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
+ FingerprintStyle::DefPathHash => {
+ Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
}
- FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)),
}
}
FingerprintStyle::Unit
}
+ #[inline(always)]
fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
Fingerprint::ZERO
}
+ #[inline(always)]
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(())
}
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
tcx.def_path_hash(*self).0
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.def_path_str(*self)
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
self.to_def_id().to_fingerprint(tcx)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
self.to_def_id().to_debug_str(tcx)
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.expect_local())
}
FingerprintStyle::DefPathHash
}
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
def_id.to_fingerprint(tcx)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
tcx.crate_name(*self).to_string()
}
+ #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
// We actually would not need to specialize the implementation of this
// method but it's faster to combine the hashes than to instantiate a full
// hashing context and stable-hashing state.
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let (def_id_0, def_id_1) = *self;
def_path_hash_0.0.combine(def_path_hash_1.0)
}
+ #[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
let (def_id_0, def_id_1) = *self;
// We actually would not need to specialize the implementation of this
// method but it's faster to combine the hashes than to instantiate a full
// hashing context and stable-hashing state.
+ #[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
let HirId { owner, local_id } = *self;
SerializedDepNodeIndex, WorkProduct, WorkProductId,
};
-pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
+pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
impl rustc_query_system::dep_graph::DepKind for DepKind {
const NULL: Self = DepKind::Null;
- #[inline(always)]
- fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle {
- DepKind::fingerprint_style(self)
- }
-
- #[inline(always)]
- fn is_eval_always(&self) -> bool {
- self.is_eval_always
- }
-
- #[inline(always)]
- fn has_params(&self) -> bool {
- self.has_params
- }
-
fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", node.kind)?;
-
- if !node.kind.has_params && !node.kind.is_anon {
- return Ok(());
- }
-
- write!(f, "(")?;
+ write!(f, "{:?}(", node.kind)?;
ty::tls::with_opt(|opt_tcx| {
if let Some(tcx) = opt_tcx {
fn sess(&self) -> &Session {
self.sess
}
+
+ #[inline(always)]
+ fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
+ kind.fingerprint_style(*self)
+ }
+
+ #[inline(always)]
+ fn is_eval_always(&self, kind: DepKind) -> bool {
+ self.query_kind(kind).is_eval_always
+ }
+
+ fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
+ debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+ // We must avoid ever having to call `force_from_dep_node()` for a
+ // `DepNode::codegen_unit`:
+ // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+ // would always end up having to evaluate the first caller of the
+ // `codegen_unit` query that *is* reconstructible. This might very well be
+ // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+ // to re-trigger calling the `codegen_unit` query with the right key. At
+ // that point we would already have re-done all the work we are trying to
+ // avoid doing in the first place.
+ // The solution is simple: Just explicitly call the `codegen_unit` query for
+ // each CGU, right after partitioning. This way `try_mark_green` will always
+ // hit the cache instead of having to go through `force_from_dep_node`.
+ // This assertion makes sure, we actually keep applying the solution above.
+ debug_assert!(
+ dep_node.kind != DepKind::codegen_unit,
+ "calling force_from_dep_node() on DepKind::codegen_unit"
+ );
+
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.force_from_dep_node {
+ f(*self, dep_node);
+ true
+ } else {
+ false
+ }
+ }
+
+ fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
+ let cb = self.query_kind(dep_node.kind);
+ if let Some(f) = cb.try_load_from_on_disk_cache {
+ f(*self, dep_node)
+ }
+ }
}
+++ /dev/null
-//! This module provides a simplified abstraction for working with
-//! code blocks identified by their integer `NodeId`. In particular,
-//! it captures a common set of attributes that all "function-like
-//! things" (represented by `FnLike` instances) share. For example,
-//! all `FnLike` instances have a type signature (be it explicit or
-//! inferred). And all `FnLike` instances have a body, i.e., the code
-//! that is run when the function-like thing it represents is invoked.
-//!
-//! With the above abstraction in place, one can treat the program
-//! text as a collection of blocks of code (and most such blocks are
-//! nested within a uniquely determined `FnLike`), and users can ask
-//! for the `Code` associated with a particular NodeId.
-
-use crate::hir::map::Map;
-use rustc_hir as hir;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Expr, FnDecl, Node};
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-/// An FnLikeNode is a Node that is like a fn, in that it has a decl
-/// and a body (as well as a NodeId, a span, etc).
-///
-/// More specifically, it is one of either:
-///
-/// - A function item,
-/// - A closure expr (i.e., an ExprKind::Closure), or
-/// - The default implementation for a trait method.
-///
-/// To construct one, use the `Code::from_node` function.
-#[derive(Copy, Clone, Debug)]
-pub struct FnLikeNode<'a> {
- node: Node<'a>,
-}
-
-/// MaybeFnLike wraps a method that indicates if an object
-/// corresponds to some FnLikeNode.
-trait MaybeFnLike {
- fn is_fn_like(&self) -> bool;
-}
-
-impl MaybeFnLike for hir::Item<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ItemKind::Fn(..))
- }
-}
-
-impl MaybeFnLike for hir::ImplItem<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ImplItemKind::Fn(..))
- }
-}
-
-impl MaybeFnLike for hir::TraitItem<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
- }
-}
-
-impl MaybeFnLike for hir::Expr<'_> {
- fn is_fn_like(&self) -> bool {
- matches!(self.kind, hir::ExprKind::Closure(..))
- }
-}
-
-/// Carries either an FnLikeNode or an Expr, as these are the two
-/// constructs that correspond to "code" (as in, something from which
-/// we can construct a control-flow graph).
-#[derive(Copy, Clone)]
-pub enum Code<'a> {
- FnLike(FnLikeNode<'a>),
- Expr(&'a Expr<'a>),
-}
-
-impl<'a> Code<'a> {
- pub fn id(&self) -> hir::HirId {
- match *self {
- Code::FnLike(node) => node.id(),
- Code::Expr(block) => block.hir_id,
- }
- }
-
- /// Attempts to construct a Code from presumed FnLike or Expr node input.
- pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
- match map.get(id) {
- Node::Block(_) => {
- // Use the parent, hopefully an expression node.
- Code::from_node(map, map.get_parent_node(id))
- }
- Node::Expr(expr) => Some(Code::Expr(expr)),
- node => FnLikeNode::from_node(node).map(Code::FnLike),
- }
- }
-}
-
-/// These are all the components one can extract from a fn item for
-/// use when implementing FnLikeNode operations.
-struct ItemFnParts<'a> {
- ident: Ident,
- decl: &'a hir::FnDecl<'a>,
- header: hir::FnHeader,
- vis: &'a hir::Visibility<'a>,
- generics: &'a hir::Generics<'a>,
- body: hir::BodyId,
- id: hir::HirId,
- span: Span,
-}
-
-/// These are all the components one can extract from a closure expr
-/// for use when implementing FnLikeNode operations.
-struct ClosureParts<'a> {
- decl: &'a FnDecl<'a>,
- body: hir::BodyId,
- id: hir::HirId,
- span: Span,
-}
-
-impl<'a> ClosureParts<'a> {
- fn new(d: &'a FnDecl<'a>, b: hir::BodyId, id: hir::HirId, s: Span) -> Self {
- ClosureParts { decl: d, body: b, id, span: s }
- }
-}
-
-impl<'a> FnLikeNode<'a> {
- /// Attempts to construct a FnLikeNode from presumed FnLike node input.
- pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
- let fn_like = match node {
- Node::Item(item) => item.is_fn_like(),
- Node::TraitItem(tm) => tm.is_fn_like(),
- Node::ImplItem(it) => it.is_fn_like(),
- Node::Expr(e) => e.is_fn_like(),
- _ => false,
- };
- fn_like.then_some(FnLikeNode { node })
- }
-
- pub fn body(self) -> hir::BodyId {
- self.handle(
- |i: ItemFnParts<'a>| i.body,
- |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _| body,
- |c: ClosureParts<'a>| c.body,
- )
- }
-
- pub fn decl(self) -> &'a FnDecl<'a> {
- self.handle(
- |i: ItemFnParts<'a>| &*i.decl,
- |_, _, sig: &'a hir::FnSig<'a>, _, _, _| &sig.decl,
- |c: ClosureParts<'a>| c.decl,
- )
- }
-
- pub fn span(self) -> Span {
- self.handle(
- |i: ItemFnParts<'_>| i.span,
- |_, _, _: &'a hir::FnSig<'a>, _, _, span| span,
- |c: ClosureParts<'_>| c.span,
- )
- }
-
- pub fn id(self) -> hir::HirId {
- self.handle(
- |i: ItemFnParts<'_>| i.id,
- |id, _, _: &'a hir::FnSig<'a>, _, _, _| id,
- |c: ClosureParts<'_>| c.id,
- )
- }
-
- pub fn constness(self) -> hir::Constness {
- self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
- }
-
- pub fn asyncness(self) -> hir::IsAsync {
- self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
- }
-
- pub fn unsafety(self) -> hir::Unsafety {
- self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
- }
-
- pub fn kind(self) -> FnKind<'a> {
- let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
- FnKind::ItemFn(p.ident, p.generics, p.header, p.vis)
- };
- let closure = |_: ClosureParts<'a>| FnKind::Closure;
- let method =
- |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _| FnKind::Method(ident, sig, vis);
- self.handle(item, method, closure)
- }
-
- fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
- where
- I: FnOnce(ItemFnParts<'a>) -> A,
- M: FnOnce(
- hir::HirId,
- Ident,
- &'a hir::FnSig<'a>,
- Option<&'a hir::Visibility<'a>>,
- hir::BodyId,
- Span,
- ) -> A,
- C: FnOnce(ClosureParts<'a>) -> A,
- {
- match self.node {
- Node::Item(i) => match i.kind {
- hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
- id: i.hir_id(),
- ident: i.ident,
- decl: &sig.decl,
- body: block,
- vis: &i.vis,
- span: i.span,
- header: sig.header,
- generics,
- }),
- _ => bug!("item FnLikeNode that is not fn-like"),
- },
- Node::TraitItem(ti) => match ti.kind {
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- method(ti.hir_id(), ti.ident, sig, None, body, ti.span)
- }
- _ => bug!("trait method FnLikeNode that is not fn-like"),
- },
- Node::ImplItem(ii) => match ii.kind {
- hir::ImplItemKind::Fn(ref sig, body) => {
- method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span)
- }
- _ => bug!("impl method FnLikeNode that is not fn-like"),
- },
- Node::Expr(e) => match e.kind {
- hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
- closure(ClosureParts::new(&decl, block, e.hir_id, e.span))
- }
- _ => bug!("expr FnLikeNode that is not fn-like"),
- },
- _ => bug!("other FnLikeNode that is not fn-like"),
- }
- }
-}
+++ /dev/null
-use crate::arena::Arena;
-use crate::hir::map::Map;
-use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_hir::definitions;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_query_system::ich::StableHashingContext;
-use rustc_session::Session;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{Span, DUMMY_SP};
-
-use std::iter::repeat;
-
-/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
-pub(super) struct NodeCollector<'a, 'hir> {
- arena: &'hir Arena<'hir>,
-
- /// The crate
- krate: &'hir Crate<'hir>,
-
- /// Source map
- source_map: &'a SourceMap,
-
- map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
- parenting: FxHashMap<LocalDefId, HirId>,
-
- /// The parent of this node
- parent_node: hir::HirId,
-
- current_dep_node_owner: LocalDefId,
-
- definitions: &'a definitions::Definitions,
-
- hcx: StableHashingContext<'a>,
-}
-
-fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
- let i = k.index();
- let len = map.len();
- if i >= len {
- map.extend(repeat(None).take(i - len + 1));
- }
- debug_assert!(map[k].is_none());
- map[k] = Some(v);
-}
-
-fn hash_body(
- hcx: &mut StableHashingContext<'_>,
- item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
-) -> Fingerprint {
- let mut stable_hasher = StableHasher::new();
- hcx.while_hashing_hir_bodies(true, |hcx| {
- item_like.hash_stable(hcx, &mut stable_hasher);
- });
- stable_hasher.finish()
-}
-
-impl<'a, 'hir> NodeCollector<'a, 'hir> {
- pub(super) fn root(
- sess: &'a Session,
- arena: &'hir Arena<'hir>,
- krate: &'hir Crate<'hir>,
- definitions: &'a definitions::Definitions,
- hcx: StableHashingContext<'a>,
- ) -> NodeCollector<'a, 'hir> {
- let mut collector = NodeCollector {
- arena,
- krate,
- source_map: sess.source_map(),
- parent_node: hir::CRATE_HIR_ID,
- current_dep_node_owner: CRATE_DEF_ID,
- definitions,
- hcx,
- map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
- parenting: FxHashMap::default(),
- };
- collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
-
- collector
- }
-
- pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
- // Insert bodies into the map
- for (id, body) in self.krate.bodies.iter() {
- let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
- assert!(bodies.insert(id.hir_id.local_id, body).is_none());
- }
- IndexedHir { map: self.map, parenting: self.parenting }
- }
-
- fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
- let hash = hash_body(&mut self.hcx, node);
-
- let mut nodes = IndexVec::new();
- nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
-
- debug_assert!(self.map[owner].is_none());
- self.map[owner] =
- Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
- }
-
- fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
- debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
- debug_assert_ne!(hir_id.local_id.as_u32(), 0);
-
- // Make sure that the DepNode of some node coincides with the HirId
- // owner of that node.
- if cfg!(debug_assertions) {
- if hir_id.owner != self.current_dep_node_owner {
- let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
- Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(),
- None => format!("{:?}", node),
- };
-
- span_bug!(
- span,
- "inconsistent DepNode at `{:?}` for `{}`: \
- current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
- self.source_map.span_to_diagnostic_string(span),
- node_str,
- self.definitions
- .def_path(self.current_dep_node_owner)
- .to_string_no_crate_verbose(),
- self.current_dep_node_owner,
- self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
- hir_id.owner,
- )
- }
- }
-
- let nodes = self.map[hir_id.owner].as_mut().unwrap();
-
- debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
- insert_vec_map(
- &mut nodes.nodes,
- hir_id.local_id,
- ParentedNode { parent: self.parent_node.local_id, node: node },
- );
- }
-
- fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
- let parent_node = self.parent_node;
- self.parent_node = parent_node_id;
- f(self);
- self.parent_node = parent_node;
- }
-
- fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
- let prev_owner = self.current_dep_node_owner;
- let prev_parent = self.parent_node;
-
- self.current_dep_node_owner = dep_node_owner;
- self.parent_node = HirId::make_owner(dep_node_owner);
- f(self);
- self.current_dep_node_owner = prev_owner;
- self.parent_node = prev_parent;
- }
-
- fn insert_nested(&mut self, item: LocalDefId) {
- #[cfg(debug_assertions)]
- {
- let dk_parent = self.definitions.def_key(item).parent.unwrap();
- let dk_parent = LocalDefId { local_def_index: dk_parent };
- let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
- debug_assert_eq!(
- dk_parent.owner, self.parent_node.owner,
- "Different parents for {:?}",
- item
- )
- }
-
- assert_eq!(self.parenting.insert(item, self.parent_node), None);
- }
-}
-
-impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
- type Map = Map<'hir>;
-
- /// Because we want to track parent items and so forth, enable
- /// deep walking so that we walk nested items in the context of
- /// their outer items.
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- panic!("`visit_nested_xxx` must be manually implemented in this visitor");
- }
-
- fn visit_nested_item(&mut self, item: ItemId) {
- debug!("visit_nested_item: {:?}", item);
- self.insert_nested(item.def_id);
- self.visit_item(self.krate.item(item));
- }
-
- fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
- self.insert_nested(item_id.def_id);
- self.visit_trait_item(self.krate.trait_item(item_id));
- }
-
- fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
- self.insert_nested(item_id.def_id);
- self.visit_impl_item(self.krate.impl_item(item_id));
- }
-
- fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
- self.insert_nested(foreign_id.def_id);
- self.visit_foreign_item(self.krate.foreign_item(foreign_id));
- }
-
- fn visit_nested_body(&mut self, id: BodyId) {
- self.visit_body(self.krate.body(id));
- }
-
- fn visit_param(&mut self, param: &'hir Param<'hir>) {
- let node = Node::Param(param);
- self.insert(param.pat.span, param.hir_id, node);
- self.with_parent(param.hir_id, |this| {
- intravisit::walk_param(this, param);
- });
- }
-
- fn visit_item(&mut self, i: &'hir Item<'hir>) {
- debug!("visit_item: {:?}", i);
- self.insert_owner(i.def_id, OwnerNode::Item(i));
- self.with_dep_node_owner(i.def_id, |this| {
- if let ItemKind::Struct(ref struct_def, _) = i.kind {
- // If this is a tuple or unit-like struct, register the constructor.
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
- }
- }
- intravisit::walk_item(this, i);
- });
- }
-
- fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
- self.with_dep_node_owner(fi.def_id, |this| {
- intravisit::walk_foreign_item(this, fi);
- });
- }
-
- fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
- self.insert(param.span, param.hir_id, Node::GenericParam(param));
- intravisit::walk_generic_param(self, param);
- }
-
- fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
- self.with_parent(param, |this| {
- intravisit::walk_const_param_default(this, ct);
- })
- }
-
- fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
- self.with_dep_node_owner(ti.def_id, |this| {
- intravisit::walk_trait_item(this, ti);
- });
- }
-
- fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
- self.with_dep_node_owner(ii.def_id, |this| {
- intravisit::walk_impl_item(this, ii);
- });
- }
-
- fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
- let node =
- if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
- self.insert(pat.span, pat.hir_id, node);
-
- self.with_parent(pat.hir_id, |this| {
- intravisit::walk_pat(this, pat);
- });
- }
-
- fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
- let node = Node::Arm(arm);
-
- self.insert(arm.span, arm.hir_id, node);
-
- self.with_parent(arm.hir_id, |this| {
- intravisit::walk_arm(this, arm);
- });
- }
-
- fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
- self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
-
- self.with_parent(constant.hir_id, |this| {
- intravisit::walk_anon_const(this, constant);
- });
- }
-
- fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
- self.insert(expr.span, expr.hir_id, Node::Expr(expr));
-
- self.with_parent(expr.hir_id, |this| {
- intravisit::walk_expr(this, expr);
- });
- }
-
- fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
- self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
-
- self.with_parent(stmt.hir_id, |this| {
- intravisit::walk_stmt(this, stmt);
- });
- }
-
- fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
- if let Some(hir_id) = path_segment.hir_id {
- self.insert(path_span, hir_id, Node::PathSegment(path_segment));
- }
- intravisit::walk_path_segment(self, path_span, path_segment);
- }
-
- fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
- self.insert(ty.span, ty.hir_id, Node::Ty(ty));
-
- self.with_parent(ty.hir_id, |this| {
- intravisit::walk_ty(this, ty);
- });
- }
-
- fn visit_infer(&mut self, inf: &'hir InferArg) {
- self.insert(inf.span, inf.hir_id, Node::Infer(inf));
-
- self.with_parent(inf.hir_id, |this| {
- intravisit::walk_inf(this, inf);
- });
- }
-
- fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
- self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
-
- self.with_parent(tr.hir_ref_id, |this| {
- intravisit::walk_trait_ref(this, tr);
- });
- }
-
- fn visit_fn(
- &mut self,
- fk: intravisit::FnKind<'hir>,
- fd: &'hir FnDecl<'hir>,
- b: BodyId,
- s: Span,
- id: HirId,
- ) {
- assert_eq!(self.parent_node, id);
- intravisit::walk_fn(self, fk, fd, b, s, id);
- }
-
- fn visit_block(&mut self, block: &'hir Block<'hir>) {
- self.insert(block.span, block.hir_id, Node::Block(block));
- self.with_parent(block.hir_id, |this| {
- intravisit::walk_block(this, block);
- });
- }
-
- fn visit_local(&mut self, l: &'hir Local<'hir>) {
- self.insert(l.span, l.hir_id, Node::Local(l));
- self.with_parent(l.hir_id, |this| {
- intravisit::walk_local(this, l);
- })
- }
-
- fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
- self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
- }
-
- fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) {
- match visibility.node {
- VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
- VisibilityKind::Restricted { hir_id, .. } => {
- self.insert(visibility.span, hir_id, Node::Visibility(visibility));
- self.with_parent(hir_id, |this| {
- intravisit::walk_vis(this, visibility);
- });
- }
- }
- }
-
- fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
- self.insert(v.span, v.id, Node::Variant(v));
- self.with_parent(v.id, |this| {
- // Register the constructor of this variant.
- if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
- this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
- }
- intravisit::walk_variant(this, v, g, item_id);
- });
- }
-
- fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
- self.insert(field.span, field.hir_id, Node::Field(field));
- self.with_parent(field.hir_id, |this| {
- intravisit::walk_field_def(this, field);
- });
- }
-
- fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
- // Do not visit the duplicate information in TraitItemRef. We want to
- // map the actual nodes, not the duplicate ones in the *Ref.
- let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
-
- self.visit_nested_trait_item(id);
- }
-
- fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
- // Do not visit the duplicate information in ImplItemRef. We want to
- // map the actual nodes, not the duplicate ones in the *Ref.
- let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
-
- self.visit_nested_impl_item(id);
- }
-
- fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
- // Do not visit the duplicate information in ForeignItemRef. We want to
- // map the actual nodes, not the duplicate ones in the *Ref.
- let ForeignItemRef { id, ident: _, span: _ } = *fi;
-
- self.visit_nested_foreign_item(id);
- }
-}
-use self::collector::NodeCollector;
-
-use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
+use crate::hir::{ModuleItems, Owner};
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_target::spec::abi::Abi;
use std::collections::VecDeque;
-pub mod blocks;
-mod collector;
-
fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
match node {
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
let krate = self.krate();
- krate.owners.iter().filter_map(|owner| match owner.as_ref()? {
- OwnerNode::Item(item) => Some(*item),
+ krate.owners.iter().filter_map(|owner| match owner.as_ref()?.node() {
+ OwnerNode::Item(item) => Some(item),
_ => None,
})
}
}
pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
- self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+ self.find_parent_node(hir_id).unwrap()
}
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
- self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies.get(&id.hir_id.local_id).unwrap()
+ self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
}
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
- _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
+ _ => Ident::empty(),
})
}
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
- self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id))
+ self.krate()
+ .owners
+ .iter_enumerated()
+ .flat_map(move |(owner, owner_info)| {
+ let bodies = &owner_info.as_ref()?.nodes.bodies;
+ Some(bodies.iter().map(move |&(local_id, _)| {
+ let hir_id = HirId { owner, local_id };
+ let body_id = BodyId { hir_id };
+ self.body_owner_def_id(body_id)
+ }))
+ })
+ .flatten()
}
pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
- par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id)));
+ use rustc_data_structures::sync::{par_iter, ParallelIterator};
+ #[cfg(parallel_compiler)]
+ use rustc_rayon::iter::IndexedParallelIterator;
+
+ par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
+ let owner = LocalDefId::new(owner);
+ if let Some(owner_info) = owner_info {
+ par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| {
+ let hir_id = HirId { owner, local_id: *local_id };
+ let body_id = BodyId { hir_id };
+ f(self.body_owner_def_id(body_id))
+ })
+ }
+ });
}
pub fn ty_param_owner(&self, id: HirId) -> HirId {
/// Walks the attributes in a crate.
pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
let krate = self.krate();
- for (&id, attrs) in krate.attrs.iter() {
- for a in *attrs {
- visitor.visit_attribute(id, a)
+ for (owner, info) in krate.owners.iter_enumerated() {
+ if let Some(info) = info {
+ for (local_id, attrs) in info.attrs.map.iter() {
+ let id = HirId { owner, local_id: *local_id };
+ for a in *attrs {
+ visitor.visit_attribute(id, a)
+ }
+ }
}
}
}
{
let krate = self.krate();
for owner in krate.owners.iter().filter_map(Option::as_ref) {
- match owner {
+ match owner.node() {
OwnerNode::Item(item) => visitor.visit_item(item),
OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
{
let krate = self.krate();
- par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() {
+ par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref().map(OwnerInfo::node) {
Some(OwnerNode::Item(item)) => visitor.visit_item(item),
Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::Item(item) }) => item,
+ Some(Owner { node: OwnerNode::Item(item), .. }) => item,
_ => bug!("expected item, found {}", self.node_to_string(id)),
}
}
pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::ImplItem(item) }) => item,
+ Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(id)),
}
}
pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::TraitItem(item) }) => item,
+ Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(id)),
}
}
pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
match self.tcx.hir_owner(id.expect_owner()) {
- Some(Owner { node: OwnerNode::ForeignItem(item) }) => item,
+ Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
_ => bug!("expected foreign item, found {}", self.node_to_string(id)),
}
}
}
}
-pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx IndexedHir<'tcx> {
- let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
-
- // We can access untracked state since we are an eval_always query.
- let hcx = tcx.create_stable_hashing_context();
- let mut collector = NodeCollector::root(
- tcx.sess,
- &**tcx.arena,
- tcx.untracked_crate,
- &tcx.untracked_resolutions.definitions,
- hcx,
- );
- let top_mod = tcx.untracked_crate.module();
- collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
-
- let map = collector.finalize_and_compute_crate_hash();
- tcx.arena.alloc(map)
-}
-
pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
- assert_eq!(crate_num, LOCAL_CRATE);
-
- // We can access untracked state since we are an eval_always query.
- let mut hcx = tcx.create_stable_hashing_context();
-
- let mut hir_body_nodes: Vec<_> = tcx
- .index_hir(())
- .map
- .iter_enumerated()
- .filter_map(|(def_id, hod)| {
- let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id);
- let hash = hod.as_ref()?.hash;
- Some((def_path_hash, hash, def_id))
- })
- .collect();
- hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+ debug_assert_eq!(crate_num, LOCAL_CRATE);
+ let krate = tcx.hir_crate(());
+ let hir_body_hash = krate.hir_hash;
let upstream_crates = upstream_crates(tcx);
source_file_names.sort_unstable();
+ let mut hcx = tcx.create_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
- for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() {
- def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher);
- fingerprint.hash_stable(&mut hcx, &mut stable_hasher);
- AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id }
- .hash_stable(&mut hcx, &mut stable_hasher);
- if tcx.sess.opts.debugging_opts.incremental_relative_spans {
- let span = tcx.untracked_resolutions.definitions.def_span(*def_id);
- debug_assert_eq!(span.parent(), None);
- span.hash_stable(&mut hcx, &mut stable_hasher);
- }
- }
+ hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+ if tcx.sess.opts.debugging_opts.incremental_relative_spans {
+ let definitions = &tcx.untracked_resolutions.definitions;
+ let mut owner_spans: Vec<_> = krate
+ .owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let _ = info.as_ref()?;
+ let def_path_hash = definitions.def_path_hash(def_id);
+ let span = definitions.def_span(def_id);
+ debug_assert_eq!(span.parent(), None);
+ Some((def_path_hash, span))
+ })
+ .collect();
+ owner_spans.sort_unstable_by_key(|bn| bn.0);
+ owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
+ }
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
use crate::ty::query::Providers;
use crate::ty::TyCtxt;
-use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
use rustc_span::DUMMY_SP;
-use std::collections::BTreeMap;
-
-/// Result of HIR indexing.
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
- /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
- // The `mut` comes from construction time, and is harmless since we only ever hand out
- // immutable refs to IndexedHir.
- map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
- /// Map from each owner to its parent's HirId inside another owner.
- // This map is separate from `map` to eventually allow for per-owner indexing.
- parenting: FxHashMap<LocalDefId, HirId>,
-}
/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
node: OwnerNode<'tcx>,
+ hash_without_bodies: Fingerprint,
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
+ #[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let Owner { node } = self;
- hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
- }
-}
-
-/// HIR node coupled with its parent's id in the same HIR owner.
-///
-/// The parent is trash when the node is a HIR owner.
-#[derive(Clone, Debug)]
-pub struct ParentedNode<'tcx> {
- parent: ItemLocalId,
- node: Node<'tcx>,
-}
-
-#[derive(Debug)]
-pub struct OwnerNodes<'tcx> {
- /// Pre-computed hash of the full HIR.
- hash: Fingerprint,
- /// Full HIR for the current owner.
- // The zeroth node's parent is trash, but is never accessed.
- nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
- /// Content of local bodies.
- bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- // We ignore the `nodes` and `bodies` fields since these refer to information included in
- // `hash` which is hashed in the collector and used for the crate hash.
- let OwnerNodes { hash, nodes: _, bodies: _ } = *self;
- hash.hash_stable(hcx, hasher);
- }
-}
-
-/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
-/// to the nodes whose `HirId::owner` is `prefix`.
-#[derive(Copy, Clone)]
-pub struct AttributeMap<'tcx> {
- map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
- prefix: LocalDefId,
-}
-
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for AttributeMap<'tcx> {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let range = self.range();
-
- range.clone().count().hash_stable(hcx, hasher);
- for (key, value) in range {
- key.hash_stable(hcx, hasher);
- value.hash_stable(hcx, hasher);
- }
- }
-}
-
-impl<'tcx> std::fmt::Debug for AttributeMap<'tcx> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("AttributeMap")
- .field("prefix", &self.prefix)
- .field("range", &&self.range().collect::<Vec<_>>()[..])
- .finish()
- }
-}
-
-impl<'tcx> AttributeMap<'tcx> {
- fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
- self.map.get(&HirId { owner: self.prefix, local_id: id }).copied().unwrap_or(&[])
- }
-
- fn range(&self) -> std::collections::btree_map::Range<'_, rustc_hir::HirId, &[Attribute]> {
- let local_zero = ItemLocalId::from_u32(0);
- let range = HirId { owner: self.prefix, local_id: local_zero }..HirId {
- owner: LocalDefId { local_def_index: self.prefix.local_def_index + 1 },
- local_id: local_zero,
- };
- self.map.range(range)
+ let Owner { node: _, hash_without_bodies } = self;
+ hash_without_bodies.hash_stable(hcx, hasher)
}
}
hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
};
providers.hir_crate = |tcx, ()| tcx.untracked_crate;
- providers.index_hir = map::index_hir;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {
- let owner = tcx.index_hir(()).map[id].as_ref()?;
- let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
- let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
- Some(Owner { node })
+ let owner = tcx.hir_crate(()).owners[id].as_ref()?;
+ let node = owner.node();
+ Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
};
- providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
+ providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| {
- let index = tcx.index_hir(());
- index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
+ // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash.
+ let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
+ let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
+ let def_id = LocalDefId { local_def_index };
+ let mut parent_hir_id =
+ tcx.untracked_resolutions.definitions.local_def_id_to_hir_id(def_id);
+ if let Some(local_id) =
+ tcx.hir_crate(()).owners[parent_hir_id.owner].as_ref().unwrap().parenting.get(&id)
+ {
+ parent_hir_id.local_id = *local_id;
+ }
+ parent_hir_id
+ });
+ parent
};
- providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
+ providers.hir_attrs =
+ |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map_or(AttributeMap::EMPTY, |o| &o.attrs);
providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
providers.fn_arg_names = |tcx, id| {
#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(in_band_lifetimes)]
/// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
/// error which will report the first range of bytes which is uninitialized.
fn check_init(&self, range: AllocRange) -> AllocResult {
- self.is_init(range).or_else(|idx_range| {
- Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+ self.is_init(range).map_err(|idx_range| {
+ AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
access_offset: range.start,
access_size: range.size,
uninit_offset: idx_range.start,
uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
- })))
+ }))
})
}
}
impl<'tcx> MonoItem<'tcx> {
+ /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims).
+ pub fn is_user_defined(&self) -> bool {
+ match *self {
+ MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)),
+ MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true,
+ }
+ }
+
pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
match *self {
MonoItem::Fn(instance) => {
/// or `typeck` appears in the name.
/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name
/// or `typeck` and `bar` both appear in the name.
+#[inline]
pub fn dump_mir<'tcx, F>(
tcx: TyCtxt<'tcx>,
pass_num: Option<&dyn Display>,
pub struct ConstQualifs {
pub has_mut_interior: bool,
pub needs_drop: bool,
+ pub needs_non_const_drop: bool,
pub custom_eq: bool,
pub error_occured: Option<ErrorReported>,
}
for statement in statements {
let source_range = source_range_no_file(tcx, &statement.source_info.span);
text.push(format!(
- "\n{}{}: {}: {}",
+ "\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
statement_kind_name(&statement),
- format!("{:?}", statement)
+ statement
));
}
if let Some(term) = terminator {
/// prefer wrappers like `tcx.visit_all_items_in_krate()`.
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
eval_always
- no_hash
desc { "get the crate HIR" }
}
- /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
- /// Avoid calling this query directly.
- query index_hir(_: ()) -> &'tcx crate::hir::IndexedHir<'tcx> {
- eval_always
- no_hash
- desc { "index HIR" }
- }
-
/// The items in a module.
///
/// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
- eval_always
desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_parent(key: LocalDefId) -> hir::HirId {
- eval_always
desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
}
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
- eval_always
+ query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
}
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_attrs(key: LocalDefId) -> rustc_middle::hir::AttributeMap<'tcx> {
- eval_always
+ query hir_attrs(key: LocalDefId) -> &'tcx hir::AttributeMap<'tcx> {
desc { |tcx| "HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
+ separate_provide_extern
}
query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
path = tcx.def_path_str(key),
}
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query analysis(key: ()) -> Result<(), ErrorReported> {
desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// Bounds from the parent (e.g. with nested impl trait) are not included.
query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Elaborated version of the predicates from `explicit_item_bounds`.
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
desc { "looking up the native libraries of a linked crate" }
+ separate_provide_extern
}
query lint_levels(_: ()) -> LintLevelMap {
// This query reads from untracked data in definitions.
eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_panic_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_panic_runtime" }
+ separate_provide_extern
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_const_qualif_const_arg(
key: (LocalDefId, DefId)
desc {
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
}
+ separate_provide_extern
}
/// Try to build an abstract representation of the given constant.
query thir_abstract_const_of_const_arg(
) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query promoted_mir_of_const_arg(
key: (LocalDefId, DefId)
/// Returns the predicates written explicitly by the user.
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from the `DefId` of a trait to the list of
/// additional acyclicity requirements).
query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
query trait_def(key: DefId) -> ty::TraitDef {
desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
query adt_def(key: DefId) -> &'tcx ty::AdtDef {
desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query adt_destructor(key: DefId) -> Option<ty::Destructor> {
desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
// The cycle error here should be reported as an error by `check_representable`.
/// `is_const_fn` function.
query is_const_fn_raw(key: DefId) -> bool {
desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query asyncness(key: DefId) -> hir::IsAsync {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `true` if calls to the function may be promoted.
/// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
query is_foreign_item(key: DefId) -> bool {
desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets a map with the variance of every item; use `item_variance` instead.
/// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Maps from thee `DefId` of a type to its (inferred) outlives.
/// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from a trait item to the trait item "descriptor".
query associated_item(key: DefId) -> ty::AssocItem {
desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
/// Collects the associated items defined on a trait or impl.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
query inherent_impls(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
eval_always
+ separate_provide_extern
}
/// The result of unsafety-checking this `LocalDefId`.
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// The signature of functions.
+ /// Computes the signature of the function.
query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
+ /// Performs lint checking for the module.
query lint_mod(key: LocalDefId) -> () {
desc { |tcx| "linting {}", describe_as_module(key, tcx) }
}
desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
}
+ /// Checks for uses of unstable APIs in the module.
query check_mod_unstable_api_usage(key: LocalDefId) -> () {
desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
}
}
/// Caches `CoerceUnsized` kinds for impls on custom types.
- query coerce_unsized_info(key: DefId)
- -> ty::adjustment::CoerceUnsizedInfo {
- desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
- }
+ query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+ desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
query typeck_item_bodies(_: ()) -> () {
desc { "type-checking all item bodies" }
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx, opt_result) {
- tcx.is_closure(key.to_def_id())
- || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
- }
+ cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
}
+ /// Generates a MIR body for the shim.
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
query opt_def_kind(def_id: DefId) -> Option<DefKind> {
desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
+ /// Gets the span for the definition.
query def_span(def_id: DefId) -> Span {
desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
- // FIXME(mw): DefSpans are not really inputs since they are derived from
- // HIR. But at the moment HIR hashing still contains some hacks that allow
- // to make type debuginfo to be source location independent. Declaring
- // DefSpan an input makes sure that changes to these are always detected
- // regardless of HIR hashing.
- eval_always
+ separate_provide_extern
}
+ /// Gets the span for the identifier of the definition.
query def_ident_span(def_id: DefId) -> Option<Span> {
desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool {
query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
query rendered_const(def_id: DefId) -> String {
desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Given an `associated_item`, find the trait it belongs to.
/// Return `None` if the `DefId` is not an associated item.
query trait_of_item(associated_item: DefId) -> Option<DefId> {
desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+ separate_provide_extern
}
query is_ctfe_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query own_existential_vtable_entries(
query dylib_dependency_formats(_: CrateNum)
-> &'tcx [(CrateNum, LinkagePreference)] {
desc { "dylib dependency formats of crate" }
+ separate_provide_extern
}
query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
query is_compiler_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_compiler_builtins" }
+ separate_provide_extern
}
query has_global_allocator(_: CrateNum) -> bool {
// This query depends on untracked global state in CStore
eval_always
fatal_cycle
desc { "checking if the crate has_global_allocator" }
+ separate_provide_extern
}
query has_panic_handler(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate has_panic_handler" }
+ separate_provide_extern
}
query is_profiler_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "query a crate is `#![profiler_runtime]`" }
+ separate_provide_extern
}
query panic_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic strategy" }
+ separate_provide_extern
}
query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic-in-drop strategy" }
+ separate_provide_extern
}
query is_no_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "test whether a crate has `#![no_builtins]`" }
+ separate_provide_extern
}
query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
fatal_cycle
desc { "query a crate's symbol mangling version" }
+ separate_provide_extern
}
query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
eval_always
desc { "getting crate's ExternCrateData" }
+ separate_provide_extern
}
query specializes(_: (DefId, DefId)) -> bool {
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_constness(def_id: DefId) -> hir::Constness {
desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query check_item_well_formed(key: LocalDefId) -> () {
-> DefIdMap<SymbolExportLevel> {
storage(ArenaCacheSelector<'tcx>)
desc { "looking up the exported symbols of a crate" }
+ separate_provide_extern
}
query is_reachable_non_generic(def_id: DefId) -> bool {
desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
desc { |tcx|
"collecting available upstream monomorphizations for `{}`",
tcx.def_path_str(def_id),
}
+ separate_provide_extern
}
/// Returns the upstream crate that exports drop-glue for the given
query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
desc { "looking up the foreign modules of a linked crate" }
+ separate_provide_extern
}
/// Identifies the entry-point (e.g., the `main` function) for a given
query crate_hash(_: CrateNum) -> Svh {
eval_always
desc { "looking up the hash a crate" }
+ separate_provide_extern
}
query crate_host_hash(_: CrateNum) -> Option<Svh> {
eval_always
desc { "looking up the hash of a host version of a crate" }
+ separate_provide_extern
}
query extra_filename(_: CrateNum) -> String {
eval_always
desc { "looking up the extra filename for a crate" }
+ separate_provide_extern
}
query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
eval_always
desc { "looking up the paths for extern crates" }
+ separate_provide_extern
}
/// Given a crate and a trait, look up all impls of that trait in the crate.
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up implementations of a trait in a crate" }
+ separate_provide_extern
}
/// Given a crate, look up all trait impls in that crate.
query all_trait_implementations(_: CrateNum)
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
+ separate_provide_extern
}
query is_dllimport_foreign_item(def_id: DefId) -> bool {
query visibility(def_id: DefId) -> ty::Visibility {
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Computes the set of modules from which this type is visibly uninhabited.
query dep_kind(_: CrateNum) -> CrateDepKind {
eval_always
desc { "fetching what a dependency looks like" }
+ separate_provide_extern
}
+
+ /// Gets the name of the crate.
query crate_name(_: CrateNum) -> Symbol {
eval_always
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) }
+ separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
query defined_lib_features(_: CrateNum)
-> &'tcx [(Symbol, Option<Symbol>)] {
desc { "calculating the lib features defined in a crate" }
+ separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata.
query get_lang_items(_: ()) -> LanguageItems {
/// Returns the lang items defined in another crate by loading it from metadata.
query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
desc { "calculating the lang items defined in a crate" }
+ separate_provide_extern
}
/// Returns the diagnostic items defined in a crate.
query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating the diagnostic items map in a crate" }
+ separate_provide_extern
}
query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
desc { "calculating the missing lang items in a crate" }
+ separate_provide_extern
}
query visible_parent_map(_: ()) -> DefIdMap<DefId> {
storage(ArenaCacheSelector<'tcx>)
query missing_extern_crate_item(_: CrateNum) -> bool {
eval_always
desc { "seeing if we're missing an `extern crate` item for this crate" }
+ separate_provide_extern
}
query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
eval_always
desc { "looking at the source for a crate" }
+ separate_provide_extern
}
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
eval_always
query is_private_dep(c: CrateNum) -> bool {
eval_always
desc { "check whether crate {} is a private dependency", c }
+ separate_provide_extern
}
query allocator_kind(_: ()) -> Option<AllocatorKind> {
eval_always
query exported_symbols(_: CrateNum)
-> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
desc { "exported_symbols" }
+ separate_provide_extern
}
query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
desc { "codegen_unit" }
}
- query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
- cache_on_disk_if { key.is_local() }
+ query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+ cache_on_disk_if { key.def_id().is_local() }
desc {
|tcx| "determining which generic parameters are unused by `{}`",
- tcx.def_path_str(key)
+ tcx.def_path_str(key.def_id())
}
+ separate_provide_extern
}
query backend_optimization_level(_: ()) -> OptLevel {
desc { "optimization level used by backend" }
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum SelectionError<'tcx> {
+ /// The trait is not implemented.
Unimplemented,
+ /// After a closure impl has selected, its "outputs" were evaluated
+ /// (which for closures includes the "input" type params) and they
+ /// didn't resolve. See `confirm_poly_trait_refs` for more.
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
+ /// The trait pointed by `DefId` is not object safe.
TraitNotObjectSafe(DefId),
+ /// A given constant couldn't be evaluated.
NotConstEvaluatable(NotConstEvaluatable),
+ /// Exceeded the recursion depth during type projection.
Overflow,
+ /// Signaling that an error has already been emitted, to avoid
+ /// multiple errors being shown.
ErrorReporting,
+ /// Multiple applicable `impl`s where found. The `DefId`s correspond to
+ /// all the `impl`s' Items.
+ Ambiguous(Vec<DefId>),
}
/// When performing resolution, it is typically the case that there
use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache<
- ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
+ (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>;
-pub type EvaluationCache<'tcx> =
- Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
+pub type EvaluationCache<'tcx> = Cache<
+ (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
+ EvaluationResult,
+>;
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
/// `false` if there are no *further* obligations.
has_nested: bool,
},
- ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
+ ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
//! Type context book-keeping.
use crate::arena::Arena;
-use crate::dep_graph::DepGraph;
+use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
where
Self: Sized;
- /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
- /// session, if it still exists. This is used during incremental compilation to
- /// turn a deserialized `DefPathHash` into its current `DefId`.
- fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId;
-
fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
pub queries: &'tcx dyn query::QueryEngine<'tcx>,
pub query_caches: query::QueryCaches<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
// Internal caches for metadata decoding. No need to track deps on this.
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
dep_graph: DepGraph,
on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
+ query_kinds: &'tcx [DepKindStruct],
crate_name: &str,
output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
on_disk_cache,
queries,
query_caches: query::QueryCaches::default(),
+ query_kinds,
ty_rcache: Default::default(),
pred_rcache: Default::default(),
selection_cache: Default::default(),
}
}
+ crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+ &self.query_kinds[k as usize]
+ }
+
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
#[track_caller]
pub fn ty_error(self) -> Ty<'tcx> {
}
}
+ /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
+ /// session, if it still exists. This is used during incremental compilation to
+ /// turn a deserialized `DefPathHash` into its current `DefId`.
+ pub fn def_path_hash_to_def_id(self, hash: DefPathHash) -> DefId {
+ debug!("def_path_hash_to_def_id({:?})", hash);
+
+ let stable_crate_id = hash.stable_crate_id();
+
+ // If this is a DefPathHash from the local crate, we can look up the
+ // DefId in the tcx's `Definitions`.
+ if stable_crate_id == self.sess.local_stable_crate_id() {
+ self.untracked_resolutions.definitions.local_def_path_hash_to_def_id(hash).to_def_id()
+ } else {
+ // If this is a DefPathHash from an upstream crate, let the CrateStore map
+ // it to a DefId.
+ let cstore = &self.untracked_resolutions.cstore;
+ let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+ cstore.def_path_hash_to_def_id(cnum, hash)
+ }
+ }
+
pub fn def_path_debug_str(self, def_id: DefId) -> String {
// We are explicitly not going through queries here in order to get
// crate name and stable crate id since this code is called from debug!()
#[inline(always)]
pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
- let krate = self.gcx.untracked_crate;
let resolutions = &self.gcx.untracked_resolutions;
-
- StableHashingContext::new(self.sess, krate, &resolutions.definitions, &*resolutions.cstore)
+ StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore)
}
#[inline(always)]
pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
- let krate = self.gcx.untracked_crate;
let resolutions = &self.gcx.untracked_resolutions;
-
StableHashingContext::ignore_spans(
self.sess,
- krate,
&resolutions.definitions,
&*resolutions.cstore,
)
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
+ 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.crate_name = |tcx, id| {
) -> bool {
let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
- let param = if let Some(param) = param {
- param
- } else {
+ let Some(param) = param else {
return false;
};
pub enum TypeError<'tcx> {
Mismatch,
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
+ PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
ConstnessMismatch(values) => {
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
}
+ PolarityMismatch(values) => {
+ write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
+ }
UnsafetyMismatch(values) => {
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
}
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
- | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
- | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
- false
- }
+ | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
+ | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
+ | VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability
| ArgumentMutability(_)
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
- let opaque_local_def_id = def_id.expect_local();
- let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
- let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
- hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
- _ => bug!("The HirId comes from a `ty::Opaque`"),
+ let opaque_local_def_id = def_id.as_local();
+ let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
+ let hir = self.hir();
+ let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
+ match &hir.expect_item(opaque_hir_id).kind {
+ hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+ _ => bug!("The HirId comes from a `ty::Opaque`"),
+ }
+ } else {
+ return false;
};
let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
}
}
+ /// Returns the `DefId` of instances which might not require codegen locally.
+ pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
+ match self {
+ ty::InstanceDef::Item(def) => Some(def.did),
+ ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
+ InstanceDef::VtableShim(..)
+ | InstanceDef::ReifyShim(..)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::Virtual(..)
+ | InstanceDef::Intrinsic(..)
+ | InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::CloneShim(..) => None,
+ }
+ }
+
#[inline]
pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
match self {
return self;
}
- if let InstanceDef::Item(def) = self.def {
- let polymorphized_substs = polymorphize(tcx, def.did, self.substs);
- debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
- Self { def: self.def, substs: polymorphized_substs }
- } else {
- self
- }
+ let polymorphized_substs = polymorphize(tcx, self.def, self.substs);
+ debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+ Self { def: self.def, substs: polymorphized_substs }
}
}
fn polymorphize<'tcx>(
tcx: TyCtxt<'tcx>,
- def_id: DefId,
+ instance: ty::InstanceDef<'tcx>,
substs: SubstsRef<'tcx>,
) -> SubstsRef<'tcx> {
- debug!("polymorphize({:?}, {:?})", def_id, substs);
- let unused = tcx.unused_generic_params(def_id);
+ debug!("polymorphize({:?}, {:?})", instance, substs);
+ let unused = tcx.unused_generic_params(instance);
debug!("polymorphize: unused={:?}", unused);
// If this is a closure or generator then we need to handle the case where another closure
// from the function is captured as an upvar and hasn't been polymorphized. In this case,
// the unpolymorphized upvar closure would result in a polymorphized closure producing
// multiple mono items (and eventually symbol clashes).
+ let def_id = instance.def_id();
let upvars_ty = if tcx.is_closure(def_id) {
Some(substs.as_closure().tupled_upvars_ty())
} else if tcx.type_of(def_id).is_generator() {
debug!("fold_ty: ty={:?}", ty);
match ty.kind {
ty::Closure(def_id, substs) => {
- let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
if substs == polymorphized_substs {
ty
} else {
}
}
ty::Generator(def_id, substs, movability) => {
- let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ let polymorphized_substs = polymorphize(
+ self.tcx,
+ ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+ substs,
+ );
if substs == polymorphized_substs {
ty
} else {
}
// Extract the number of elements from the layout of the array field:
- let len = if let Ok(TyAndLayout {
+ let Ok(TyAndLayout {
layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
..
- }) = self.layout_of(f0_ty)
- {
- count
- } else {
+ }) = self.layout_of(f0_ty) else {
return Err(LayoutError::Unknown(ty));
};
- (*e_ty, *len, true)
+ (*e_ty, *count, true)
} else {
// First ADT field is not an array:
(f0_ty, def.non_enum_variant().fields.len() as _, false)
// Compute the ABI of the element type:
let e_ly = self.layout_of(e_ty)?;
- let e_abi = if let Abi::Scalar(scalar) = e_ly.abi {
- scalar
- } else {
+ let Abi::Scalar(e_abi) = e_ly.abi else {
// This error isn't caught in typeck, e.g., if
// the element type of the vector is generic.
tcx.sess.fatal(&format!(
// LLVM's definition of `noalias` is based solely on memory
// dependencies rather than pointer equality
//
- // Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide
- // whether or not to actually emit the attribute.
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
let no_alias = match kind {
PointerKind::Shared | PointerKind::UniqueBorrowed => false,
PointerKind::UniqueOwned => true,
pub predicates: Vec<Predicate<'tcx>>,
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(
+ Copy,
+ Clone,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ HashStable,
+ Debug,
+ TypeFoldable
+)]
pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
Reservation,
}
+impl ImplPolarity {
+ /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+ pub fn flip(&self) -> Option<ImplPolarity> {
+ match self {
+ ImplPolarity::Positive => Some(ImplPolarity::Negative),
+ ImplPolarity::Negative => Some(ImplPolarity::Positive),
+ ImplPolarity::Reservation => None,
+ }
+ }
+}
+
+impl fmt::Display for ImplPolarity {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Positive => f.write_str("positive"),
+ Self::Negative => f.write_str("negative"),
+ Self::Reservation => f.write_str("reservation"),
+ }
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
self.inner.kind
}
+
+ /// Flips the polarity of a Predicate.
+ ///
+ /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+ let kind = self
+ .inner
+ .kind
+ .map_bound(|kind| match kind {
+ PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
+ Some(PredicateKind::Trait(TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: polarity.flip()?,
+ }))
+ }
+
+ _ => None,
+ })
+ .transpose()?;
+
+ Some(tcx.mk_predicate(kind))
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
pub trait_ref: TraitRef<'tcx>,
pub constness: BoundConstness,
+
+ pub polarity: ImplPolarity,
}
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.value
.map_bound(|trait_ref| {
- PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
+ PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: ty::ImplPolarity::Positive,
+ })
})
.to_predicate(tcx)
}
match self.tcx().extern_crate(def_id) {
Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
(ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
- debug!("try_print_visible_def_path: def_id={:?}", def_id);
- return Ok((
- if !span.is_dummy() {
- self.print_def_path(def_id, &[])?
- } else {
- self.path_crate(cnum)?
- },
- true,
- ));
+ // NOTE(eddyb) the only reason `span` might be dummy,
+ // that we're aware of, is that it's the `std`/`core`
+ // `extern crate` injected by default.
+ // FIXME(eddyb) find something better to key this on,
+ // or avoid ending up with `ExternCrateSource::Extern`,
+ // for the injected `std`/`core`.
+ if span.is_dummy() {
+ return Ok((self.path_crate(cnum)?, true));
+ }
+
+ // Disable `try_print_trimmed_def_path` behavior within
+ // the `print_def_path` call, to avoid infinite recursion
+ // in cases where the `extern crate foo` has non-trivial
+ // parents, e.g. it's nested in `impl foo::Trait for Bar`
+ // (see also issues #55779 and #87932).
+ self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?;
+
+ return Ok((self, true));
}
(ExternCrateSource::Path, LOCAL_CRATE) => {
- debug!("try_print_visible_def_path: def_id={:?}", def_id);
return Ok((self.path_crate(cnum)?, true));
}
_ => {}
p!(print_def_path(did, substs));
if !substs.as_closure().is_valid() {
p!(" closure_substs=(unavailable)");
+ p!(write(" substs={:?}", substs));
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
}
}
+/// Helper for `TyCtxtEnsure` to avoid a closure.
+#[inline(always)]
+fn noop<T>(_: &T) {}
+
macro_rules! query_helper_param_ty {
(DefId) => { impl IntoQueryParam<DefId> };
($K:ty) => { $K };
};
}
+macro_rules! separate_provide_extern_decl {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ for<'tcx> fn(
+ TyCtxt<'tcx>,
+ query_keys::$name<'tcx>,
+ ) -> query_values::$name<'tcx>
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_default {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ )
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_default!([$($modifiers)*][$($args)*])
+ };
+}
+
macro_rules! define_callbacks {
(<$tcx:tt>
$($(#[$attr:meta])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param();
- let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {});
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
let lookup = match cached {
Ok(()) => return,
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
{
let key = key.into_query_param();
- let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| {
- value.clone()
- });
+ let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
let lookup = match cached {
Ok(value) => return value,
) -> query_values::$name<'tcx>,)*
}
+ pub struct ExternProviders {
+ $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+ }
+
impl Default for Providers {
fn default() -> Self {
Providers {
}
}
+ impl Default for ExternProviders {
+ fn default() -> Self {
+ ExternProviders {
+ $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+ }
+ }
+ }
+
impl Copy for Providers {}
impl Clone for Providers {
fn clone(&self) -> Self { *self }
}
+ impl Copy for ExternProviders {}
+ impl Clone for ExternProviders {
+ fn clone(&self) -> Self { *self }
+ }
+
pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
}
}
+impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::ImplPolarity,
+ b: ty::ImplPolarity,
+ ) -> RelateResult<'tcx, ty::ImplPolarity> {
+ if a != b {
+ Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
Ok(ty::TraitPredicate {
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
constness: relation.relate(a.constness, b.constness)?,
+ polarity: relation.relate(a.polarity, b.polarity)?,
})
}
}
if let ty::BoundConstness::ConstIfConst = self.constness {
write!(f, "~const ")?;
}
- write!(f, "TraitPredicate({:?})", self.trait_ref)
+ write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
- tcx.lift(self.trait_ref)
- .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
+ tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: self.polarity,
+ })
}
}
Some(match self {
Mismatch => Mismatch,
ConstnessMismatch(x) => ConstnessMismatch(x),
+ PolarityMismatch(x) => PolarityMismatch(x),
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
self.map_bound(|trait_ref| ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
})
}
}
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
let closure_span = tcx.hir().span(closure_hir_id);
- let (capture_index, capture) = if let Some(capture_details) =
+ let Some((capture_index, capture)) =
find_capture_matching_projections(
typeck_results,
var_hir_id,
closure_def_id,
&from_builder.projection,
- ) {
- capture_details
- } else {
+ ) else {
if !enable_precise_capture(tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
) {
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
- let block = if let Some(block) = blocks[drop_idx] {
- block
- } else {
- continue;
- };
+ let Some(block) = blocks[drop_idx] else { continue };
match drop_data.0.kind {
DropKind::Value => {
let terminator = TerminatorKind::Drop {
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(once_cell)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::intravisit::FnKind;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
let def_id = body.source.def_id().expect_local();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
- if let FnKind::Closure = fn_like_node.kind() {
+ if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() {
+ if let FnKind::Closure = fn_kind {
// closures can't recur, so they don't matter.
return;
}
traits::NonStructuralMatchTy::Opaque => {
"opaque types cannot be used in patterns".to_string()
}
+ traits::NonStructuralMatchTy::Closure => {
+ "closures cannot be used in patterns".to_string()
+ }
traits::NonStructuralMatchTy::Generator => {
"generators cannot be used in patterns".to_string()
}
}
}
+ /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
+ #[cfg(test)]
+ pub(crate) fn allow_unreachable(&mut self) {
+ #[cfg(debug_assertions)]
+ self.reachable_blocks.insert_all()
+ }
+
/// Returns the underlying `Results`.
pub fn results(&self) -> &Results<'tcx, A> {
&self.results.borrow()
let mut cursor =
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+ cursor.allow_unreachable();
+
let every_target = || {
body.basic_blocks()
.iter_enumerated()
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
/// to a given local.
///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
-/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
- kind: K,
+/// immovable generators.
+pub struct MaybeBorrowedLocals {
ignore_borrow_on_drop: bool,
}
/// A dataflow analysis that records whether a pointer or reference exists that may alias the
/// given local.
pub fn all_borrows() -> Self {
- MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
- }
-}
-
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
- /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
- /// alias the given local.
- ///
- /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
- /// types with interior mutability.
- pub fn mut_borrows_only(
- tcx: TyCtxt<'tcx>,
- body: &'mir mir::Body<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Self {
- MaybeBorrowedLocals {
- kind: MutBorrow { body, tcx, param_env },
- ignore_borrow_on_drop: false,
- }
+ MaybeBorrowedLocals { ignore_borrow_on_drop: false }
}
}
-impl<K> MaybeBorrowedLocals<K> {
+impl MaybeBorrowedLocals {
/// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
///
/// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
}
- fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
- TransferFunction {
- kind: &self.kind,
- trans,
- ignore_borrow_on_drop: self.ignore_borrow_on_drop,
- }
+ fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
}
}
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
- const NAME: &'static str = K::ANALYSIS_NAME;
+ const NAME: &'static str = "maybe_borrowed_locals";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = unborrowed
}
}
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
}
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
+struct TransferFunction<'a, T> {
trans: &'a mut T,
- kind: &'a K,
ignore_borrow_on_drop: bool,
}
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
where
T: GenKill<Local>,
- K: BorrowAnalysisKind<'tcx>,
{
fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
self.super_statement(stmt, location);
self.super_rvalue(rvalue, location);
match rvalue {
- mir::Rvalue::AddressOf(mt, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
+ mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
- mir::Rvalue::Ref(_, kind, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
+ mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
}
}
}
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
- tcx: TyCtxt<'tcx>,
- body: &'mir Body<'tcx>,
- param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
- /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
- ///
- /// This assumes that it is UB to take the address of a struct field whose type is
- /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
- /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
- /// have to check the type of the borrowed **local** instead of the borrowed **place**
- /// below. See [rust-lang/unsafe-code-guidelines#134].
- ///
- /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
- fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
- !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
- }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
- const ANALYSIS_NAME: &'static str;
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
- const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
- fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
- true
- }
- fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
- true
- }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
- const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
- match kind {
- mir::BorrowKind::Mut { .. } => true,
- mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
- self.shared_borrow_allows_mutation(place)
- }
- }
- }
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
- match mt {
- Mutability::Mut => true,
- Mutability::Not => self.shared_borrow_allows_mutation(place),
- }
- }
-}
mod liveness;
mod storage_liveness;
-pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
+pub use self::borrowed_locals::MaybeBorrowedLocals;
pub use self::init_locals::MaybeInitializedLocals;
pub use self::liveness::MaybeLiveLocals;
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(exact_size_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(once_cell)]
#![feature(stmt_expr_attributes)]
use rustc_middle::ty::{self, Ty, TyCtxt};
use crate::impls::{
- DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
- MaybeUninitializedPlaces,
+ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
};
use crate::move_paths::{HasMoveData, MoveData};
use crate::move_paths::{LookupResult, MovePathIndex};
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
}
- if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
- let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
-
- sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
- }
-
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
}
}
-impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
- fn peek_at(
- &self,
- tcx: TyCtxt<'tcx>,
- place: mir::Place<'tcx>,
- flow_state: &BitSet<Local>,
- call: PeekCall,
- ) {
- info!(?place, "peek_at");
- let local = if let Some(l) = place.as_local() {
- l
- } else {
- tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
- return;
- };
-
- if !flow_state.contains(local) {
- tcx.sess.span_err(call.span, "rustc_peek: bit not set");
- }
- }
-}
-
impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
fn peek_at(
&self,
call: PeekCall,
) {
info!(?place, "peek_at");
- let local = if let Some(l) = place.as_local() {
- l
- } else {
+ let Some(local) = place.as_local() else {
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
return;
};
return;
}
- use rustc_middle::hir::map::blocks::FnLikeNode;
let def_id = body.source.def_id().expect_local();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst;
// Only run const prop on functions, methods, closures and associated constants
use crate::MirPass;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_index::vec::IndexVec;
use rustc_middle::hir;
-use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::dump_enabled;
TerminatorKind,
};
use rustc_middle::ty::TyCtxt;
-use rustc_query_system::ich::StableHashingContext;
use rustc_span::def_id::DefId;
use rustc_span::source_map::SourceMap;
use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
}
let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
- let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
// Only instrument functions, methods, and closures (not constants since they are evaluated
// at compile time by Miri).
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
// Closures are carved out by their initial `Assign` statement.)
if !is_fn_like {
- trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id());
+ trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id());
return;
}
}
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
+ // FIXME(cjgillot) Stop hashing HIR manually here.
let mut hcx = tcx.create_no_span_stable_hashing_context();
- hash(&mut hcx, &hir_body.value).to_smaller_hash()
-}
-
-fn hash(
- hcx: &mut StableHashingContext<'tcx>,
- node: &impl HashStable<StableHashingContext<'tcx>>,
-) -> Fingerprint {
let mut stable_hasher = StableHasher::new();
- node.hash_stable(hcx, &mut stable_hasher);
+ let owner = hir_body.id().hir_id.owner;
+ let bodies = &tcx.hir_owner_nodes(owner).as_ref().unwrap().bodies;
+ hcx.with_hir_bodies(false, owner, bodies, |hcx| {
+ hir_body.value.hash_stable(hcx, &mut stable_hasher)
+ });
stable_hasher.finish()
}
//! This pass just dumps MIR at a specified point.
use std::borrow::Cow;
-use std::fmt;
use std::fs::File;
use std::io;
use crate::MirPass;
+use rustc_middle::mir::write_mir_pretty;
use rustc_middle::mir::Body;
-use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutputFilenames, OutputType};
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
}
-pub struct Disambiguator {
- is_after: bool,
-}
-
-impl fmt::Display for Disambiguator {
- fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- let title = if self.is_after { "after" } else { "before" };
- write!(formatter, "{}", title)
- }
-}
-
-pub fn on_mir_pass<'tcx>(
- tcx: TyCtxt<'tcx>,
- pass_num: &dyn fmt::Display,
- pass_name: &str,
- body: &Body<'tcx>,
- is_after: bool,
-) {
- if dump_enabled(tcx, pass_name, body.source.def_id()) {
- dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(()));
- }
-}
-
pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
let path = outputs.path(OutputType::Mir);
let mut f = io::BufWriter::new(File::create(&path)?);
assert!(args.next().is_none());
let tuple = Place::from(tuple);
- let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() {
- s
- } else {
+ let ty::Tuple(tuple_tys) = tuple.ty(caller_body, tcx).ty.kind() else {
bug!("Closure arguments are not passed as a tuple");
};
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(option_get_or_insert_default)]
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
+mod reveal_all;
mod separate_const_switch;
mod shim;
mod simplify;
let mut index = 0;
let mut run_pass = |pass: &dyn MirPass<'tcx>| {
let run_hooks = |body: &_, index, is_after| {
- dump_mir::on_mir_pass(
+ let disambiguator = if is_after { "after" } else { "before" };
+ dump_mir(
tcx,
- &format_args!("{:03}-{:03}", phase_index, index),
+ Some(&format_args!("{:03}-{:03}", phase_index, index)),
&pass.name(),
+ &disambiguator,
body,
- is_after,
+ |_, _| Ok(()),
);
};
run_hooks(body, index, false);
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- use rustc_middle::hir::map::blocks::FnLikeNode;
- let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
if is_fn_like {
let did = def.did.to_def_id();
let def = ty::WithOptConstParam::unknown(did);
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
+ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
&lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
&normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&unreachable_prop::UnreachablePropagation,
pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let language_items = tcx.lang_items();
- let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() {
- slice_len_fn_item
- } else {
+ let Some(slice_len_fn_item_def_id) = language_items.slice_len_fn() else {
// there is no language item to compare to :)
return;
};
operand,
cast_ty,
) => {
- let local = if let Some(local) = place.as_local() { local } else { return };
+ let Some(local) = place.as_local() else { return };
match operand {
Operand::Copy(place) | Operand::Move(place) => {
let operand_local =
}
}
Rvalue::Len(place) => {
- let local = if let Some(local) = place.local_or_deref_local() {
- local
- } else {
+ let Some(local) = place.local_or_deref_local() else {
return;
};
if let Some(cast_statement_idx) = state.get(&local).copied() {
trace!("Running RemoveUnneededDrops on {:?}", body.source);
let did = body.source.def_id();
- let param_env = tcx.param_env(did);
+ let param_env = tcx.param_env_reveal_all_normalized(did);
let mut should_simplify = false;
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
--- /dev/null
+//! Normalizes MIR in RevealAll mode.
+
+use crate::MirPass;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct RevealAll;
+
+impl<'tcx> MirPass<'tcx> for RevealAll {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
+ // Do not apply this transformation to generators.
+ if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx))
+ && body.generator.is_none()
+ {
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ RevealAllVisitor { tcx, param_env }.visit_body(body);
+ }
+ }
+}
+
+struct RevealAllVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
+ *ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ }
+
+ #[inline]
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ _: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ match elem {
+ PlaceElem::Field(field, ty) => {
+ let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
+ // None of those contain a Ty.
+ PlaceElem::Index(..)
+ | PlaceElem::Deref
+ | PlaceElem::ConstantIndex { .. }
+ | PlaceElem::Subslice { .. }
+ | PlaceElem::Downcast(..) => None,
+ }
+ }
+}
let bb = BasicBlock::from_usize(bb);
trace!("processing block {:?}", bb);
- let discriminant_ty =
- if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) {
- ty
- } else {
- continue;
- };
+ let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
+ continue;
+ };
let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
// involving a dependency, and the lack of context is confusing) in this MVP, we focus on
// diagnostics on edges crossing a crate boundary: the collected mono items which are not
// defined in the local crate.
- if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+ if tcx.sess.diagnostic().err_count() > error_count
+ && starting_point.node.krate() != LOCAL_CRATE
+ && starting_point.node.is_user_defined()
{
let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
tcx.sess.span_note_without_error(
}
}
}
+ mir::TerminatorKind::Assert { ref msg, .. } => {
+ let lang_item = match msg {
+ mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
+ _ => LangItem::Panic,
+ };
+ let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
+ if should_codegen_locally(tcx, &instance) {
+ self.output.push(create_fn_mono_item(tcx, instance, source));
+ }
+ }
mir::TerminatorKind::Goto { .. }
| mir::TerminatorKind::SwitchInt { .. }
| mir::TerminatorKind::Resume
| mir::TerminatorKind::Abort
| mir::TerminatorKind::Return
- | mir::TerminatorKind::Unreachable
- | mir::TerminatorKind::Assert { .. } => {}
+ | mir::TerminatorKind::Unreachable => {}
mir::TerminatorKind::GeneratorDrop
| mir::TerminatorKind::Yield { .. }
| mir::TerminatorKind::FalseEdge { .. }
}
}
-// Returns `true` if we should codegen an instance in the local crate.
-// Returns `false` if we can just link to the upstream crate and therefore don't
-// need a mono item.
+/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
+/// can just link to the upstream crate and therefore don't need a mono item.
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
- let def_id = match instance.def {
- ty::InstanceDef::Item(def) => def.did,
- ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
- ty::InstanceDef::VtableShim(..)
- | ty::InstanceDef::ReifyShim(..)
- | ty::InstanceDef::ClosureOnceShim { .. }
- | ty::InstanceDef::Virtual(..)
- | ty::InstanceDef::FnPtrShim(..)
- | ty::InstanceDef::DropGlue(..)
- | ty::InstanceDef::Intrinsic(_)
- | ty::InstanceDef::CloneShim(..) => return true,
+ let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() {
+ def_id
+ } else {
+ return true;
};
if tcx.is_foreign_item(def_id) {
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
+#![feature(let_else)]
#![feature(in_band_lifetimes)]
#![recursion_limit = "256"]
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::print::characteristic_def_id_of_type;
-use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
+use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt};
use rustc_span::symbol::Symbol;
use super::PartitioningCx;
// call it.
return None;
}
- // This is a method within an impl, find out what the self-type is:
- let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
- instance.substs,
- ty::ParamEnv::reveal_all(),
- tcx.type_of(impl_def_id),
- );
- if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
- return Some(def_id);
+
+ // When polymorphization is enabled, methods which do not depend on their generic
+ // parameters, but the self-type of their impl block do will fail to normalize.
+ if !tcx.sess.opts.debugging_opts.polymorphize
+ || !instance.definitely_needs_subst(tcx)
+ {
+ // This is a method within an impl, find out what the self-type is:
+ let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
+ instance.substs,
+ ty::ParamEnv::reveal_all(),
+ tcx.type_of(impl_def_id),
+ );
+ if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
+ return Some(def_id);
+ }
}
}
let is_generic = instance.substs.non_erasable_generics().next().is_some();
// Upstream `DefId` instances get different handling than local ones.
- let def_id = if let Some(def_id) = def_id.as_local() {
- def_id
- } else {
+ let Some(def_id) = def_id.as_local() else {
return if export_generics && is_generic {
// If it is an upstream monomorphization and we export generics, we must make
// it available to downstream crates.
providers.unused_generic_params = unused_generic_params;
}
-/// Determine which generic parameters are used by the function/method/closure represented by
-/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
-/// indicates all parameters are used).
+/// Determine which generic parameters are used by the instance.
+///
+/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
+/// parameters are used).
#[instrument(level = "debug", skip(tcx))]
-fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
+fn unused_generic_params<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: ty::InstanceDef<'tcx>,
+) -> FiniteBitSet<u32> {
if !tcx.sess.opts.debugging_opts.polymorphize {
// If polymorphization disabled, then all parameters are used.
return FiniteBitSet::new_empty();
}
- // Polymorphization results are stored in cross-crate metadata only when there are unused
- // parameters, so assume that non-local items must have only used parameters (else this query
- // would not be invoked, and the cross-crate metadata used instead).
- if !def_id.is_local() {
+ let def_id = instance.def_id();
+ // Exit early if this instance should not be polymorphized.
+ if !should_polymorphize(tcx, def_id, instance) {
return FiniteBitSet::new_empty();
}
return FiniteBitSet::new_empty();
}
- // Exit early when there is no MIR available.
- let context = tcx.hir().body_const_context(def_id.expect_local());
- match context {
- Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
- debug!("no mir available");
- return FiniteBitSet::new_empty();
- }
- Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
- debug!("no ctfe mir available");
- return FiniteBitSet::new_empty();
- }
- _ => {}
- }
-
// Create a bitset with N rightmost ones for each parameter.
let generics_count: u32 =
generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
unused_parameters.set_range(0..generics_count);
debug!(?unused_parameters, "(start)");
+
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
debug!(?unused_parameters, "(after default)");
// Visit MIR and accumululate used generic parameters.
- let body = match context {
+ let body = match tcx.hir().body_const_context(def_id.expect_local()) {
// Const functions are actually called and should thus be considered for polymorphization
- // via their runtime MIR
+ // via their runtime MIR.
Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
Some(_) => tcx.mir_for_ctfe(def_id),
};
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
vis.visit_body(body);
- debug!(?unused_parameters, "(after visitor)");
-
- mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
debug!(?unused_parameters, "(end)");
// Emit errors for debugging and testing if enabled.
unused_parameters
}
+/// Returns `true` if the instance should be polymorphized.
+fn should_polymorphize<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ instance: ty::InstanceDef<'tcx>,
+) -> bool {
+ // If an instance's MIR body is not polymorphic then the modified substitutions that are
+ // derived from polymorphization's result won't make any difference.
+ if !instance.has_polymorphic_mir_body() {
+ return false;
+ }
+
+ // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
+ if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) {
+ return false;
+ }
+
+ // Polymorphization results are stored in cross-crate metadata only when there are unused
+ // parameters, so assume that non-local items must have only used parameters (else this query
+ // would not be invoked, and the cross-crate metadata used instead).
+ if !def_id.is_local() {
+ return false;
+ }
+
+ // Foreign items have no bodies to analyze.
+ if tcx.is_foreign_item(def_id) {
+ return false;
+ }
+
+ // Make sure there is MIR available.
+ match tcx.hir().body_const_context(def_id.expect_local()) {
+ Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
+ debug!("no mir available");
+ return false;
+ }
+ Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
+ debug!("no ctfe mir available");
+ return false;
+ }
+ _ => true,
+ }
+}
+
/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
}
}
-/// Search the predicates on used generic parameters for any unused generic parameters, and mark
-/// those as used.
-#[instrument(level = "debug", skip(tcx, def_id))]
-fn mark_used_by_predicates<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- unused_parameters: &mut FiniteBitSet<u32>,
-) {
- let def_id = tcx.closure_base_def_id(def_id);
- let predicates = tcx.explicit_predicates_of(def_id);
-
- let mut current_unused_parameters = FiniteBitSet::new_empty();
- // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
- // bit set so that this is skipped if all parameters are already used.
- while current_unused_parameters != *unused_parameters {
- debug!(?current_unused_parameters, ?unused_parameters);
- current_unused_parameters = *unused_parameters;
-
- for (predicate, _) in predicates.predicates {
- // Consider all generic params in a predicate as used if any other parameter in the
- // predicate is used.
- let any_param_used = {
- let mut vis = HasUsedGenericParams { tcx, unused_parameters };
- predicate.visit_with(&mut vis).is_break()
- };
-
- if any_param_used {
- let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
- predicate.visit_with(&mut vis);
- }
- }
- }
-
- if let Some(parent) = predicates.parent {
- mark_used_by_predicates(tcx, parent, unused_parameters);
- }
-}
-
/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
/// parameter which was unused.
#[instrument(level = "debug", skip(tcx, generics))]
/// a closure, generator or constant).
#[instrument(level = "debug", skip(self, def_id, substs))]
fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
- let unused = self.tcx.unused_generic_params(def_id);
+ let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+ let unused = self.tcx.unused_generic_params(instance);
debug!(?self.unused_parameters, ?unused);
for (i, arg) in substs.iter().enumerate() {
let i = i.try_into().unwrap();
src_file.prefer_local(),
line_nos
) {
- eprintln!("Error writting to file {}", e.to_string())
+ eprintln!("Error writing to file {}", e)
}
}
}
rustc_span = { path = "../rustc_span" }
rustc_ast = { path = "../rustc_ast" }
unicode-normalization = "0.1.11"
+unicode-width = "0.1.4"
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError};
-use rustc_session::lint::builtin::RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX;
+use rustc_session::lint::builtin::{
+ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{sym, Symbol};
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
+ /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
+ /// complain about it.
+ fn lint_unicode_text_flow(&self, start: BytePos) {
+ // Opening delimiter of the length 2 is not included into the comment text.
+ let content_start = start + BytePos(2);
+ let content = self.str_from(content_start);
+ let span = self.mk_sp(start, self.pos);
+ const UNICODE_TEXT_FLOW_CHARS: &[char] = &[
+ '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}',
+ '\u{202C}', '\u{2069}',
+ ];
+ if content.contains(UNICODE_TEXT_FLOW_CHARS) {
+ self.sess.buffer_lint_with_diagnostic(
+ &TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ span,
+ ast::CRATE_NODE_ID,
+ "unicode codepoint changing visible direction of text present in comment",
+ BuiltinLintDiagnostics::UnicodeTextFlow(span, content.to_string()),
+ );
+ }
+ }
+
/// Turns simple `rustc_lexer::TokenKind` enum into a rich
/// `rustc_ast::TokenKind`. This turns strings into interned
/// symbols and runs additional validation.
Some(match token {
rustc_lexer::TokenKind::LineComment { doc_style } => {
// Skip non-doc comments
- let doc_style = doc_style?;
+ let doc_style = if let Some(doc_style) = doc_style {
+ doc_style
+ } else {
+ self.lint_unicode_text_flow(start);
+ return None;
+ };
// Opening delimiter of the length 3 is not included into the symbol.
let content_start = start + BytePos(3);
}
// Skip non-doc comments
- let doc_style = doc_style?;
+ let doc_style = if let Some(doc_style) = doc_style {
+ doc_style
+ } else {
+ self.lint_unicode_text_flow(start);
+ return None;
+ };
// Opening delimiter of the length 3 and closing delimiter of the length 2
// are not included into the symbol.
assert!(mode.is_bytes());
let (c, span) = last_char();
let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
- err.span_label(span, "byte constant must be ASCII");
+ let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+ format!(" but is {:?}", c)
+ } else {
+ String::new()
+ };
+ err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
if (c as u32) <= 0xFF {
err.span_suggestion(
span,
&format!(
- "if you meant to use the unicode code point for '{}', use a \\xHH escape",
+ "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
c
),
format!("\\x{:X}", c as u32),
err.span_suggestion(
span,
&format!(
- "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
+ "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
c
),
utf8.as_bytes()
}
EscapeError::NonAsciiCharInByteString => {
assert!(mode.is_bytes());
- let (_c, span) = last_char();
+ let (c, span) = last_char();
+ let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+ format!(" but is {:?}", c)
+ } else {
+ String::new()
+ };
handler
.struct_span_err(span, "raw byte string must be ASCII")
- .span_label(span, "must be ASCII")
+ .span_label(span, &format!("must be ASCII{}", postfix))
.emit();
}
EscapeError::OutOfRangeHexEscape => {
self.struct_span_err(
MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
- "unexpected parenthesis surrounding `for` loop head",
+ "unexpected parentheses surrounding `for` loop head",
)
.multipart_suggestion(
- "remove parenthesis in `for` loop",
+ "remove parentheses in `for` loop",
vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
return Err(e);
}
- (Ident::invalid(), ItemKind::Use(tree))
+ (Ident::empty(), ItemKind::Use(tree))
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
- } else if self.is_macro_rules_item() {
+ } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
// MACRO_RULES ITEM
- self.parse_item_macro_rules(vis)?
+ self.parse_item_macro_rules(vis, has_bang)?
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
self.recover_missing_kw_before_item()?;
return Ok(None);
} else if macros_allowed && self.check_path() {
// MACRO INVOCATION ITEM
- (Ident::invalid(), ItemKind::MacCall(self.parse_item_macro(vis)?))
+ (Ident::empty(), ItemKind::MacCall(self.parse_item_macro(vis)?))
} else {
return Ok(None);
};
|| self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
- || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+ || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
/// Are we sure this could not possibly be a macro invocation?
}
};
- Ok((Ident::invalid(), item_kind))
+ Ok((Ident::empty(), item_kind))
}
fn parse_item_list<T>(
let abi = self.parse_abi(); // ABI?
let items = self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?;
let module = ast::ForeignMod { unsafety, abi, items };
- Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
+ Ok((Ident::empty(), ItemKind::ForeignMod(module)))
}
/// Parses a foreign item (one in an `extern { ... }` block).
Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false })))
}
- /// Is this unambiguously the start of a `macro_rules! foo` item definition?
- fn is_macro_rules_item(&mut self) -> bool {
- self.check_keyword(kw::MacroRules)
- && self.look_ahead(1, |t| *t == token::Not)
- && self.look_ahead(2, |t| t.is_ident())
+ /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
+
+ fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
+ if self.check_keyword(kw::MacroRules) {
+ let macro_rules_span = self.token.span;
+
+ if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
+ return IsMacroRulesItem::Yes { has_bang: true };
+ } else if self.look_ahead(1, |t| (t.is_ident())) {
+ // macro_rules foo
+ self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
+ .span_suggestion(
+ macro_rules_span,
+ "add a `!`",
+ "macro_rules!".to_owned(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ return IsMacroRulesItem::Yes { has_bang: false };
+ }
+ }
+
+ IsMacroRulesItem::No
}
/// Parses a `macro_rules! foo { ... }` declarative macro.
- fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+ fn parse_item_macro_rules(
+ &mut self,
+ vis: &Visibility,
+ has_bang: bool,
+ ) -> PResult<'a, ItemInfo> {
self.expect_keyword(kw::MacroRules)?; // `macro_rules`
- self.expect(&token::Not)?; // `!`
+ if has_bang {
+ self.expect(&token::Not)?; // `!`
+ }
let ident = self.parse_ident()?;
if self.eat(&token::Not) {
}
}
}
+
+enum IsMacroRulesItem {
+ Yes { has_bang: bool },
+ No,
+}
/// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`,
/// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
/// If the following element can't be a tuple (i.e., it's a function definition), then
- /// it's not a tuple struct field), and the contents within the parentheses isn't valid,
+ /// it's not a tuple struct field), and the contents within the parentheses aren't valid,
/// so emit a proper diagnostic.
// Public for rustfmt usage.
pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym};
None => LocalKind::Decl,
Some(init) => {
if self.eat_keyword(kw::Else) {
+ if self.token.is_keyword(kw::If) {
+ // `let...else if`. Emit the same error that `parse_block()` would,
+ // but explicitly point out that this pattern is not allowed.
+ let msg = "conditional `else if` is not supported for `let...else`";
+ return Err(self.error_block_no_opening_brace_msg(msg));
+ }
let els = self.parse_block()?;
self.check_let_else_init_bool_expr(&init);
self.check_let_else_init_trailing_brace(&init);
),
)
.multipart_suggestion(
- "wrap the expression in parenthesis",
+ "wrap the expression in parentheses",
suggs,
Applicability::MachineApplicable,
)
"right curly brace `}` before `else` in a `let...else` statement not allowed",
)
.multipart_suggestion(
- "try wrapping the expression in parenthesis",
+ "try wrapping the expression in parentheses",
suggs,
Applicability::MachineApplicable,
)
Ok(block)
}
- fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+ fn error_block_no_opening_brace_msg(&mut self, msg: &str) -> DiagnosticBuilder<'a> {
let sp = self.token.span;
- let tok = super::token_descr(&self.token);
- let mut e = self.struct_span_err(sp, &format!("expected `{{`, found {}", tok));
+ let mut e = self.struct_span_err(sp, msg);
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
// Check to see if the user has written something like
_ => {}
}
e.span_label(sp, "expected `{`");
- Err(e)
+ e
+ }
+
+ fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
+ let tok = super::token_descr(&self.token);
+ let msg = format!("expected `{{`, found {}", tok);
+ Err(self.error_block_no_opening_brace_msg(&msg))
}
/// Parses a block. Inner attributes are allowed.
}
// Parses the `typeof(EXPR)`.
- // To avoid ambiguity, the type is surrounded by parenthesis.
+ // To avoid ambiguity, the type is surrounded by parentheses.
fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
self.expect(&token::OpenDelim(token::Paren))?;
let expr = self.parse_anon_const_expr()?;
"not a `use` item",
);
}
- err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information")
+ err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
.emit();
},
);
use rustc_middle::thir::abstract_const::Node as ACNode;
use rustc_middle::ty::fold::TypeVisitor;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
- self.visit_trait(trait_ref)
- }
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: _,
+ polarity: _,
+ }) => self.visit_trait(trait_ref),
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
self.visit_projection_ty(projection_ty)
tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>,
) -> ControlFlow<V::BreakTy> {
- const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() {
- ACNode::Leaf(leaf) => {
- let leaf = leaf.subst(tcx, ct.substs);
- self.visit_const(leaf)
- }
+ const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+ ACNode::Leaf(leaf) => self.visit_const(leaf),
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
ControlFlow::CONTINUE
doctest = false
[dependencies]
-measureme = "9.0.0"
+measureme = "10.0.0"
rustc-rayon-core = "0.3.1"
-tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
extern crate rustc_macros;
#[macro_use]
extern crate rustc_middle;
-#[macro_use]
-extern crate tracing;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::DiagnosticBuilder;
-use rustc_middle::dep_graph;
+use rustc_middle::arena::Arena;
+use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex};
use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
-use rustc_middle::ty::query::{Providers, QueryEngine};
+use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::ich::StableHashingContext;
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
#[macro_use]
mod plumbing;
pub use plumbing::QueryCtxt;
-use plumbing::QueryStruct;
use rustc_query_system::query::*;
mod stats;
mod values;
use self::values::Value;
-use rustc_query_system::query::QueryAccessors;
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryDescription;
+pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable};
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
mod util;
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+ if def_id.is_top_level_module() {
+ "top-level module".to_string()
+ } else {
+ format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+ }
+}
+
rustc_query_append! { [define_queries!][<'tcx>] }
impl<'tcx> Queries<'tcx> {
// Do this *before* we clone 'latest_foreign_def_path_hashes', since
// loading existing queries may cause us to create new DepNodes, which
// may in turn end up invoking `store_foreign_def_id_hash`
- tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx));
+ tcx.dep_graph.exec_cache_promotions(tcx);
*self.serialized_data.write() = None;
}
Ok(())
})
}
-
- fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId {
- debug!("def_path_hash_to_def_id({:?})", hash);
-
- let stable_crate_id = hash.stable_crate_id();
-
- // If this is a DefPathHash from the local crate, we can look up the
- // DefId in the tcx's `Definitions`.
- if stable_crate_id == tcx.sess.local_stable_crate_id() {
- tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id()
- } else {
- // If this is a DefPathHash from an upstream crate, let the CrateStore map
- // it to a DefId.
- let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id);
- tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash)
- }
- }
}
impl<'sess> OnDiskCache<'sess> {
// If we get to this point, then all of the query inputs were green,
// which means that the definition with this hash is guaranteed to
// still exist in the current compilation session.
- Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash))
+ Ok(d.tcx().def_path_hash_to_def_id(def_path_hash))
}
}
) -> FileEncodeResult
where
CTX: QueryContext + 'tcx,
- Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
+ Q: super::QueryDescription<CTX>,
Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
{
let _timer = tcx
if res.is_err() {
return;
}
- if Q::cache_on_disk(tcx, &key, Some(value)) {
+ if Q::cache_on_disk(*tcx.dep_context(), &key) {
let dep_node = SerializedDepNodeIndex::new(dep_node.index());
// Record position of the cache entry.
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::{on_disk_cache, queries, Queries};
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use crate::{on_disk_cache, Queries};
+use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::HasDepContext;
-use rustc_query_system::query::{
- QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
-};
+use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::{Diagnostic, Handler};
use rustc_serialize::opaque;
-use rustc_span::def_id::LocalDefId;
use std::any::Any;
self.queries.try_collect_active_jobs(**self)
}
- fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
- let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
- (cb.try_load_from_on_disk_cache)(*self, dep_node)
- }
-
- fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
- debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
- // We must avoid ever having to call `force_from_dep_node()` for a
- // `DepNode::codegen_unit`:
- // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
- // would always end up having to evaluate the first caller of the
- // `codegen_unit` query that *is* reconstructible. This might very well be
- // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
- // to re-trigger calling the `codegen_unit` query with the right key. At
- // that point we would already have re-done all the work we are trying to
- // avoid doing in the first place.
- // The solution is simple: Just explicitly call the `codegen_unit` query for
- // each CGU, right after partitioning. This way `try_mark_green` will always
- // hit the cache instead of having to go through `force_from_dep_node`.
- // This assertion makes sure, we actually keep applying the solution above.
- debug_assert!(
- dep_node.kind != DepKind::codegen_unit,
- "calling force_from_dep_node() on DepKind::codegen_unit"
- );
-
- let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
- (cb.force_from_dep_node)(*self, dep_node)
- }
-
// Interactions with on_disk_cache
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
self.queries
}
}
-/// This struct stores metadata about each Query.
-///
-/// Information is retrieved by indexing the `QUERIES` array using the integer value
-/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual
-/// jump table instead of large matches.
-pub struct QueryStruct {
- /// The red/green evaluation system will try to mark a specific DepNode in the
- /// dependency graph as green by recursively trying to mark the dependencies of
- /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
- /// where we don't know if it is red or green and we therefore actually have
- /// to recompute its value in order to find out. Since the only piece of
- /// information that we have at that point is the `DepNode` we are trying to
- /// re-evaluate, we need some way to re-run a query from just that. This is what
- /// `force_from_dep_node()` implements.
- ///
- /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
- /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
- /// is usually constructed by computing a stable hash of the query-key that the
- /// `DepNode` corresponds to. Consequently, it is not in general possible to go
- /// back from hash to query-key (since hash functions are not reversible). For
- /// this reason `force_from_dep_node()` is expected to fail from time to time
- /// because we just cannot find out, from the `DepNode` alone, what the
- /// corresponding query-key is and therefore cannot re-run the query.
- ///
- /// The system deals with this case letting `try_mark_green` fail which forces
- /// the root query to be re-evaluated.
- ///
- /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
- /// Fortunately, we can use some contextual information that will allow us to
- /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
- /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
- /// valid `DefPathHash`. Since we also always build a huge table that maps every
- /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
- /// everything we need to re-run the query.
- ///
- /// Take the `mir_promoted` query as an example. Like many other queries, it
- /// just has a single parameter: the `DefId` of the item it will compute the
- /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
- /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
- /// is actually a `DefPathHash`, and can therefore just look up the corresponding
- /// `DefId` in `tcx.def_path_hash_to_def_id`.
- ///
- /// When you implement a new query, it will likely have a corresponding new
- /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
- /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
- /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
- /// add it to the "We don't have enough information to reconstruct..." group in
- /// the match below.
- pub(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool,
-
- /// Invoke a query to put the on-disk cached value in memory.
- pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode),
-}
-
macro_rules! handle_cycle_error {
([][$tcx: expr, $error:expr]) => {{
$error.emit();
}
macro_rules! hash_result {
- ([][$hcx:expr, $result:expr]) => {{
- dep_graph::hash_result($hcx, &$result)
+ ([]) => {{
+ Some(dep_graph::hash_result)
}};
- ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+ ([(no_hash) $($rest:tt)*]) => {{
None
}};
+ ([$other:tt $($modifiers:tt)*]) => {
+ hash_result!([$($modifiers)*])
+ };
+}
+
+macro_rules! get_provider {
+ ([][$tcx:expr, $name:ident, $key:expr]) => {{
+ $tcx.queries.local_providers.$name
+ }};
+ ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
+ if $key.query_crate_is_local() {
+ $tcx.queries.local_providers.$name
+ } else {
+ $tcx.queries.extern_providers.$name
+ }
+ }};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
- hash_result!([$($modifiers)*][$($args)*])
+ get_provider!([$($modifiers)*][$($args)*])
};
}
const NAME: &'static str = stringify!($name);
}
- impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
- const ANON: bool = is_anon!([$($modifiers)*]);
- const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
- const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
+ impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+ rustc_query_description! { $name<$tcx> }
type Cache = query_storage::$name<$tcx>;
}
#[inline]
- fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
- fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+ QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value>
{
- if key.query_crate_is_local() {
- tcx.queries.local_providers.$name
- } else {
- tcx.queries.extern_providers.$name
+ let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
+ let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
+ QueryVtable {
+ anon: is_anon!([$($modifiers)*]),
+ eval_always: is_eval_always!([$($modifiers)*]),
+ dep_kind: dep_graph::DepKind::$name,
+ hash_result: hash_result!([$($modifiers)*]),
+ handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+ compute,
+ cache_on_disk,
+ try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
}
}
-
- fn hash_result(
- _hcx: &mut StableHashingContext<'_>,
- _result: &Self::Value
- ) -> Option<Fingerprint> {
- hash_result!([$($modifiers)*][_hcx, _result])
- }
-
- fn handle_cycle_error(
- tcx: QueryCtxt<'tcx>,
- mut error: DiagnosticBuilder<'_>,
- ) -> Self::Value {
- handle_cycle_error!([$($modifiers)*][tcx, error])
- }
})*
- #[allow(non_upper_case_globals)]
+ #[allow(nonstandard_style)]
pub mod query_callbacks {
use super::*;
use rustc_middle::dep_graph::DepNode;
use rustc_query_system::dep_graph::FingerprintStyle;
// We use this for most things when incr. comp. is turned off.
- pub const Null: QueryStruct = QueryStruct {
- force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn Null() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Unit,
+ force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const TraitSelect: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn TraitSelect() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: true,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Unit,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const CompileCodegenUnit: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn CompileCodegenUnit() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Opaque,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- pub const CompileMonoItem: QueryStruct = QueryStruct {
- force_from_dep_node: |_, _| false,
- try_load_from_on_disk_cache: |_, _| {},
- };
+ pub fn CompileMonoItem() -> DepKindStruct {
+ DepKindStruct {
+ is_anon: false,
+ is_eval_always: false,
+ fingerprint_style: FingerprintStyle::Opaque,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
+ }
- $(pub const $name: QueryStruct = {
- const is_anon: bool = is_anon!([$($modifiers)*]);
+ $(pub fn $name()-> DepKindStruct {
+ let is_anon = is_anon!([$($modifiers)*]);
+ let is_eval_always = is_eval_always!([$($modifiers)*]);
- #[inline(always)]
- fn fingerprint_style() -> FingerprintStyle {
- <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
- ::fingerprint_style()
- }
+ let fingerprint_style =
+ <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::fingerprint_style();
- fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
- <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
+ if is_anon || !fingerprint_style.reconstructible() {
+ return DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: None,
+ try_load_from_on_disk_cache: None,
+ }
}
- fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
- force_query::<queries::$name<'_>, _>(tcx, dep_node)
+ #[inline(always)]
+ fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option<query_keys::$name<'tcx>> {
+ <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, &dep_node)
}
- fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
- if is_anon {
- return
- }
-
- if !fingerprint_style().reconstructible() {
- return
+ fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool {
+ if let Some(key) = recover(tcx, dep_node) {
+ let tcx = QueryCtxt::from_tcx(tcx);
+ force_query::<queries::$name<'_>, _>(tcx, key, dep_node);
+ true
+ } else {
+ false
}
+ }
- debug_assert!(tcx.dep_graph.is_green(dep_node));
+ fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) {
+ debug_assert!(tcx.dep_graph.is_green(&dep_node));
- let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
- if queries::$name::cache_on_disk(tcx, &key, None) {
+ let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
+ if queries::$name::cache_on_disk(tcx, &key) {
let _ = tcx.$name(key);
}
}
- QueryStruct {
- force_from_dep_node,
- try_load_from_on_disk_cache,
+ DepKindStruct {
+ is_anon,
+ is_eval_always,
+ fingerprint_style,
+ force_from_dep_node: Some(force_from_dep_node),
+ try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache),
}
- };)*
+ })*
}
- static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks);
+ pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] {
+ arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
+ }
}
}
input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
pub struct Queries<$tcx> {
local_providers: Box<Providers>,
- extern_providers: Box<Providers>,
+ extern_providers: Box<ExternProviders>,
pub on_disk_cache: Option<OnDiskCache<$tcx>>,
impl<$tcx> Queries<$tcx> {
pub fn new(
local_providers: Providers,
- extern_providers: Providers,
+ extern_providers: ExternProviders,
on_disk_cache: Option<OnDiskCache<$tcx>>,
) -> Self {
Queries {
}
};
}
-
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
- if def_id.is_top_level_module() {
- "top-level module".to_string()
- } else {
- format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
- }
-}
-
-rustc_query_description! {}
/// Creates a new, parameterless DepNode. This method will assert
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
- pub fn new_no_params(kind: K) -> DepNode<K> {
- debug_assert!(!kind.has_params());
+ pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K>
+ where
+ Ctxt: super::DepContext<DepKind = K>,
+ {
+ debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() }
}
#[cfg(debug_assertions)]
{
- if !kind.fingerprint_style().reconstructible()
+ if !tcx.fingerprint_style(kind).reconstructible()
&& (tcx.sess().opts.debugging_opts.incremental_info
|| tcx.sess().opts.debugging_opts.query_dep_graph)
{
where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
- #[inline]
+ #[inline(always)]
default fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
}
+ #[inline(always)]
default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
let mut hcx = tcx.create_stable_hashing_context();
let mut hasher = StableHasher::new();
hasher.finish()
}
+ #[inline(always)]
default fn to_debug_str(&self, _: Ctxt) -> String {
format!("{:?}", *self)
}
+ #[inline(always)]
default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
None
}
/// each task has a `DepNodeIndex` that uniquely identifies it. This unique
/// ID is used for self-profiling.
virtual_dep_node_index: Lrc<AtomicU32>,
-
- /// The cached event id for profiling node interning. This saves us
- /// from having to look up the event id every time we intern a node
- /// which may incur too much overhead.
- /// This will be None if self-profiling is disabled.
- node_intern_event_id: Option<EventId>,
}
rustc_index::newtype_index! {
dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
}
-pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
+pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
where
R: for<'a> HashStable<StableHashingContext<'a>>,
{
let mut stable_hasher = StableHasher::new();
result.hash_stable(hcx, &mut stable_hasher);
-
- Some(stable_hasher.finish())
+ stable_hasher.finish()
}
impl<K: DepKind> DepGraph<K> {
) -> DepGraph<K> {
let prev_graph_node_count = prev_graph.node_count();
- let current =
- CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+ let current = CurrentDepGraph::new(
+ profiler,
+ prev_graph_node_count,
+ encoder,
+ record_graph,
+ record_stats,
+ );
// Instantiate a dependy-less node only once for anonymous queries.
let _green_node_index = current.intern_new_node(
);
debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
- let node_intern_event_id = profiler
- .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
- .map(EventId::from_label);
-
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
colors: DepNodeColorMap::new(prev_graph_node_count),
})),
virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
- node_intern_event_id,
}
}
pub fn new_disabled() -> DepGraph<K> {
- DepGraph {
- data: None,
- virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
- node_intern_event_id: None,
- }
+ DepGraph { data: None, virtual_dep_node_index: Lrc::new(AtomicU32::new(0)) }
}
/// Returns `true` if we are actually building the full dep-graph, and `false` otherwise.
cx: Ctxt,
arg: A,
task: fn(Ctxt, A) -> R,
- hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+ hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
) -> (R, DepNodeIndex) {
if self.is_fully_enabled() {
self.with_task_impl(key, cx, arg, task, hash_result)
cx: Ctxt,
arg: A,
task: fn(Ctxt, A) -> R,
- hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+ hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
) -> (R, DepNodeIndex) {
// This function is only called when the graph is enabled.
let data = self.data.as_ref().unwrap();
key
);
- let task_deps = if key.kind.is_eval_always() {
+ let task_deps = if cx.dep_context().is_eval_always(key.kind) {
None
} else {
Some(Lock::new(TaskDeps {
let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
let dcx = cx.dep_context();
- let mut hcx = dcx.create_stable_hashing_context();
let hashing_timer = dcx.profiler().incr_result_hashing();
- let current_fingerprint = hash_result(&mut hcx, &result);
+ let current_fingerprint = hash_result.map(|f| {
+ let mut hcx = dcx.create_stable_hashing_context();
+ f(&mut hcx, &result)
+ });
let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
- // Get timer for profiling `DepNode` interning
- let node_intern_timer =
- self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
// Intern the new `DepNode`.
let (dep_node_index, prev_and_color) = data.current.intern_node(
dcx.profiler(),
current_fingerprint,
print_status,
);
- drop(node_intern_timer);
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
where
OP: FnOnce() -> R,
{
- debug_assert!(!dep_kind.is_eval_always());
+ debug_assert!(!cx.is_eval_always(dep_kind));
if let Some(ref data) = self.data {
let task_deps = Lock::new(TaskDeps::default());
tcx: Ctxt,
dep_node: &DepNode<K>,
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
- debug_assert!(!dep_node.kind.is_eval_always());
+ debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
// Return None if the dep graph is disabled
let data = self.data.as_ref()?;
// We don't know the state of this dependency. If it isn't
// an eval_always node, let's try to mark it green recursively.
- if !dep_dep_node.kind.is_eval_always() {
+ if !tcx.dep_context().is_eval_always(dep_dep_node.kind) {
debug!(
"try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
is unknown, trying to mark it green",
"try_mark_previous_green({:?}) --- trying to force dependency {:?}",
dep_node, dep_dep_node
);
- if !tcx.try_force_from_dep_node(dep_dep_node) {
+ if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
// The DepNode could not be forced.
debug!(
"try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
}
// We never try to mark eval_always nodes as green
- debug_assert!(!dep_node.kind.is_eval_always());
+ debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
//
// This method will only load queries that will end up in the disk cache.
// Other queries will not be executed.
- pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt) {
- let tcx = qcx.dep_context();
+ pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
let data = self.data.as_ref().unwrap();
match data.colors.get(prev_index) {
Some(DepNodeColor::Green(_)) => {
let dep_node = data.previous.index_to_node(prev_index);
- qcx.try_load_from_on_disk_cache(&dep_node);
+ tcx.try_load_from_on_disk_cache(dep_node);
}
None | Some(DepNodeColor::Red) => {
// We can skip red nodes because a node can only be marked
/// debugging and only active with `debug_assertions`.
total_read_count: AtomicU64,
total_duplicate_read_count: AtomicU64,
+
+ /// The cached event id for profiling node interning. This saves us
+ /// from having to look up the event id every time we intern a node
+ /// which may incur too much overhead.
+ /// This will be None if self-profiling is disabled.
+ node_intern_event_id: Option<EventId>,
}
impl<K: DepKind> CurrentDepGraph<K> {
fn new(
+ profiler: &SelfProfilerRef,
prev_graph_node_count: usize,
encoder: FileEncoder,
record_graph: bool,
let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200;
+ let node_intern_event_id = profiler
+ .get_or_alloc_cached_string("incr_comp_intern_dep_graph_node")
+ .map(EventId::from_label);
+
CurrentDepGraph {
encoder: Steal::new(GraphEncoder::new(
encoder,
forbidden_edge,
total_read_count: AtomicU64::new(0),
total_duplicate_read_count: AtomicU64::new(0),
+ node_intern_event_id,
}
}
) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) {
let print_status = cfg!(debug_assertions) && print_status;
+ // Get timer for profiling `DepNode` interning
+ let _node_intern_timer =
+ self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));
+
if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
// Determine the color and index of the new `DepNode`.
if let Some(fingerprint) = fingerprint {
/// Access the compiler session.
fn sess(&self) -> &Session;
+
+ /// Return whether this kind always require evaluation.
+ fn is_eval_always(&self, kind: Self::DepKind) -> bool;
+
+ fn fingerprint_style(&self, kind: Self::DepKind) -> FingerprintStyle;
+
+ /// Try to force a dep node to execute and see if it's green.
+ fn try_force_from_dep_node(&self, dep_node: DepNode<Self::DepKind>) -> bool;
+
+ /// Load data from the on-disk cache.
+ fn try_load_from_on_disk_cache(&self, dep_node: DepNode<Self::DepKind>);
}
pub trait HasDepContext: Copy {
}
/// Describes the contents of the fingerprint generated by a given query.
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
const NULL: Self;
- /// Return whether this kind always require evaluation.
- fn is_eval_always(&self) -> bool;
-
- /// Return whether this kind requires additional parameters to be executed.
- fn has_params(&self) -> bool;
-
/// Implementation of `std::fmt::Debug` for `DepNode`.
fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
fn read_deps<OP>(op: OP)
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
-
- fn fingerprint_style(&self) -> FingerprintStyle;
}
index
}
- fn finish(self) -> FileEncodeResult {
+ fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self;
let () = result?;
IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?;
debug!("position: {:?}", encoder.position());
// Drop the encoder so that nothing is written after the counts.
- encoder.flush()
+ let result = encoder.flush();
+ // FIXME(rylev): we hardcode the dep graph file name so we don't need a dependency on
+ // rustc_incremental just for that.
+ profiler.artifact_size("dep_graph", "dep-graph.bin", encoder.position() as u64);
+ result
}
}
pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph");
- self.status.into_inner().finish()
+ self.status.into_inner().finish(profiler)
}
}
use crate::ich;
use rustc_ast as ast;
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::sync::Lrc;
use rustc_hir as hir;
cstore: &'a dyn CrateStore,
pub(super) body_resolver: BodyResolver<'a>,
hash_spans: bool,
- hash_bodies: bool,
pub(super) node_id_hashing_mode: NodeIdHashingMode,
// Very often, we are hashing something that does not need the
/// We could also just store a plain reference to the `hir::Crate` but we want
/// to avoid that the crate is used to get untracked access to all of the HIR.
#[derive(Clone, Copy)]
-pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
-
-impl<'tcx> BodyResolver<'tcx> {
- /// Returns a reference to the `hir::Body` with the given `BodyId`.
- /// **Does not do any tracking**; use carefully.
- pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
- self.0.body(id)
- }
+pub(super) enum BodyResolver<'tcx> {
+ Forbidden,
+ Traverse {
+ hash_bodies: bool,
+ owner: LocalDefId,
+ bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
+ },
}
impl<'a> StableHashingContext<'a> {
- /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
- /// Don't use it for anything else or you'll run the risk of
- /// leaking data out of the tracking system.
#[inline]
fn new_with_or_without_spans(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
always_ignore_spans: bool,
!always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
StableHashingContext {
- body_resolver: BodyResolver(krate),
+ body_resolver: BodyResolver::Forbidden,
definitions,
cstore,
caching_source_map: None,
raw_source_map: sess.source_map(),
hash_spans: hash_spans_initial,
- hash_bodies: true,
node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
}
}
#[inline]
pub fn new(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
Self::new_with_or_without_spans(
sess,
- krate,
definitions,
cstore,
/*always_ignore_spans=*/ false,
#[inline]
pub fn ignore_spans(
sess: &'a Session,
- krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
let always_ignore_spans = true;
- Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+ Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
}
+ /// Allow hashing
#[inline]
- pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
- let prev_hash_bodies = self.hash_bodies;
- self.hash_bodies = hash_bodies;
+ pub fn while_hashing_hir_bodies(&mut self, hb: bool, f: impl FnOnce(&mut Self)) {
+ let prev = match &mut self.body_resolver {
+ BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+ BodyResolver::Traverse { ref mut hash_bodies, .. } => {
+ std::mem::replace(hash_bodies, hb)
+ }
+ };
f(self);
- self.hash_bodies = prev_hash_bodies;
+ match &mut self.body_resolver {
+ BodyResolver::Forbidden => unreachable!(),
+ BodyResolver::Traverse { ref mut hash_bodies, .. } => *hash_bodies = prev,
+ }
+ }
+
+ #[inline]
+ pub fn with_hir_bodies(
+ &mut self,
+ hash_bodies: bool,
+ owner: LocalDefId,
+ bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
+ f: impl FnOnce(&mut Self),
+ ) {
+ let prev = self.body_resolver;
+ self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
+ f(self);
+ self.body_resolver = prev;
}
#[inline]
self.definitions.def_path_hash(def_id)
}
- #[inline]
- pub fn hash_bodies(&self) -> bool {
- self.hash_bodies
- }
-
#[inline]
pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
match self.caching_source_map {
//! This module contains `HashStable` implementations for various HIR data
//! types in no particular order.
+use crate::ich::hcx::BodyResolver;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_hir as hir;
-use rustc_hir::definitions::DefPathHash;
-use smallvec::SmallVec;
use std::mem;
impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
#[inline]
fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
let hcx = self;
- if hcx.hash_bodies() {
- hcx.body_resolver.body(id).hash_stable(hcx, hasher);
+ match hcx.body_resolver {
+ BodyResolver::Forbidden => panic!("Hashing HIR bodies is forbidden."),
+ BodyResolver::Traverse { hash_bodies: false, .. } => {}
+ BodyResolver::Traverse { hash_bodies: true, owner, bodies } => {
+ assert_eq!(id.hir_id.owner, owner);
+ bodies[&id.hir_id.local_id].hash_stable(hcx, hasher);
+ }
}
}
self.node_id_hashing_mode = prev_hash_node_ids;
}
+
+ #[inline]
+ fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) {
+ self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+ let hir::TraitCandidate { def_id, import_ids } = tc;
+
+ def_id.hash_stable(hcx, hasher);
+ import_ids.hash_stable(hcx, hasher);
+ });
+ }
}
impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
});
}
}
-
-impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- let hir::TraitCandidate { def_id, import_ids } = self;
-
- def_id.hash_stable(hcx, hasher);
- import_ids.hash_stable(hcx, hasher);
- });
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
- type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
-
- fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
- let hir::TraitCandidate { def_id, import_ids } = self;
-
- (
- hcx.def_path_hash(*def_id),
- import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
- )
- }
-}
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(thread_local_const_init)]
type Stored: Clone;
}
-pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
+pub struct QueryVtable<CTX: QueryContext, K, V> {
pub anon: bool,
pub dep_kind: CTX::DepKind,
pub eval_always: bool,
+ pub cache_on_disk: bool,
- pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>,
+ pub compute: fn(CTX::DepContext, K) -> V,
+ pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
- pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
- pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
+ pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
}
impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
DepNode::construct(tcx, self.dep_kind, key)
}
- pub(crate) fn hash_result(
- &self,
- hcx: &mut StableHashingContext<'_>,
- value: &V,
- ) -> Option<Fingerprint> {
- (self.hash_result)(hcx, value)
- }
-
- pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
- (self.cache_on_disk)(tcx, key, value)
+ pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
+ (self.compute)(tcx, key)
}
pub(crate) fn try_load_from_disk(&self, tcx: CTX, index: SerializedDepNodeIndex) -> Option<V> {
- (self.try_load_from_disk)(tcx, index)
+ self.try_load_from_disk
+ .expect("QueryDescription::load_from_disk() called for an unsupported query.")(
+ tcx, index,
+ )
}
}
-pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
- const ANON: bool;
- const EVAL_ALWAYS: bool;
- const DEP_KIND: CTX::DepKind;
+pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
+ const TRY_LOAD_FROM_DISK: Option<fn(CTX, SerializedDepNodeIndex) -> Option<Self::Value>>;
type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
+ fn describe(tcx: CTX, key: Self::Key) -> String;
+
// Don't use this method to access query results, instead use the methods on TyCtxt
fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, Self::Key>
where
CTX: 'a;
// Don't use this method to compute query results, instead use the methods on TyCtxt
- fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
-
- fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value)
- -> Option<Fingerprint>;
-
- fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
-}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
- fn describe(tcx: CTX, key: Self::Key) -> String;
-
- #[inline]
- fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
- false
- }
-
- fn try_load_from_disk(_: CTX, _: SerializedDepNodeIndex) -> Option<Self::Value> {
- panic!("QueryDescription::load_from_disk() called for an unsupported query.")
- }
-}
-
-pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> {
- const VTABLE: QueryVtable<CTX, K, V>;
-}
+ fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
-impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
-where
- CTX: QueryContext,
- Q: QueryDescription<CTX>,
-{
- const VTABLE: QueryVtable<CTX, Q::Key, Q::Value> = QueryVtable {
- anon: Q::ANON,
- dep_kind: Q::DEP_KIND,
- eval_always: Q::EVAL_ALWAYS,
- hash_result: Q::hash_result,
- handle_cycle_error: Q::handle_cycle_error,
- cache_on_disk: Q::cache_on_disk,
- try_load_from_disk: Q::try_load_from_disk,
- };
+ fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
}
if Some(i) == num_frames {
break;
}
- let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
- info
- } else {
+ let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else {
break;
};
let mut diag = Diagnostic::new(
};
mod config;
-pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
+pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
-use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>;
- /// Load data from the on-disk cache.
- fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
-
- /// Try to force a dep node to execute and see if it's green.
- fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
-
/// Load side effects associated to the node in the previous session.
fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
+use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
+use crate::query::config::{QueryDescription, QueryVtable};
use crate::query::job::{
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
};
lookup: QueryLookup,
dep_node: Option<DepNode<CTX::DepKind>>,
query: &QueryVtable<CTX, C::Key, C::Value>,
- compute: fn(CTX::DepContext, C::Key) -> C::Value,
) -> (C::Stored, Option<DepNodeIndex>)
where
C: QueryCache,
query.dep_kind,
) {
TryGetJob::NotYetStarted(job) => {
- let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute);
+ let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
let result = job.complete(cache, result, dep_node_index);
(result, Some(dep_node_index))
}
mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
query: &QueryVtable<CTX, K, V>,
job_id: QueryJobId<CTX::DepKind>,
- compute: fn(CTX::DepContext, K) -> V,
) -> (V, DepNodeIndex)
where
K: Clone + DepNodeParams<CTX::DepContext>,
// Fast path for when incr. comp. is off.
if !dep_graph.is_fully_enabled() {
let prof_timer = tcx.dep_context().profiler().query_provider();
- let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key));
+ let result = tcx.start_query(job_id, None, || query.compute(*tcx.dep_context(), key));
let dep_node_index = dep_graph.next_virtual_depnode_index();
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
return (result, dep_node_index);
// The diagnostics for this query will be promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
if let Some(ret) = tcx.start_query(job_id, None, || {
- try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute)
+ try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
}) {
return ret;
}
let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || {
if query.anon {
return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
- compute(*tcx.dep_context(), key)
+ query.compute(*tcx.dep_context(), key)
});
}
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
- dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result)
+ dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
key: &K,
dep_node: &DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, K, V>,
- compute: fn(CTX::DepContext, K) -> V,
) -> Option<(V, DepNodeIndex)>
where
K: Clone,
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
- if query.cache_on_disk(tcx, key, None) {
+ 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);
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
- // We always expect to find a cached result for things that
- // can be forced from `DepNode`.
- debug_assert!(
- !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(),
- "missing on-disk cache entry for {:?}",
- dep_node
- );
-
if let Some(result) = result {
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
return Some((result, dep_node_index));
}
+
+ // We always expect to find a cached result for things that
+ // can be forced from `DepNode`.
+ debug_assert!(
+ !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+ "missing on-disk cache entry for {:?}",
+ dep_node
+ );
}
// We could not load a result from the on-disk cache, so
let prof_timer = tcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone()));
+ let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
);
debug!("BEGIN verify_ich({:?})", dep_node);
- let mut hcx = tcx.create_stable_hashing_context();
-
- let new_hash = query.hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO);
- debug!("END verify_ich({:?})", dep_node);
-
+ let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
+ let mut hcx = tcx.create_stable_hashing_context();
+ f(&mut hcx, result)
+ });
let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
+ debug!("END verify_ich({:?})", dep_node);
if Some(new_hash) != old_hash {
let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
}
}
-#[inline(never)]
-fn force_query_impl<CTX, C>(
- tcx: CTX,
- state: &QueryState<CTX::DepKind, C::Key>,
- cache: &QueryCacheStore<C>,
- key: C::Key,
- dep_node: DepNode<CTX::DepKind>,
- query: &QueryVtable<CTX, C::Key, C::Value>,
- compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> bool
-where
- C: QueryCache,
- C::Key: DepNodeParams<CTX::DepContext>,
- CTX: QueryContext,
-{
- debug_assert!(!query.anon);
-
- // We may be concurrently trying both execute and force a query.
- // Ensure that only one of them runs the query.
- let cached = cache.cache.lookup(cache, &key, |_, index| {
- if unlikely!(tcx.dep_context().profiler().enabled()) {
- tcx.dep_context().profiler().query_cache_hit(index.into());
- }
- });
-
- let lookup = match cached {
- Ok(()) => return true,
- Err(lookup) => lookup,
- };
-
- let _ =
- try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute);
- true
-}
-
pub enum QueryMode {
Get,
Ensure,
Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- let query = &Q::VTABLE;
+ let query = Q::make_vtable(tcx, &key);
let dep_node = if let QueryMode::Ensure = mode {
- let (must_run, dep_node) = ensure_must_run(tcx, &key, query);
+ let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
if !must_run {
return None;
}
};
debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
- let compute = Q::compute_fn(tcx, &key);
let (result, dep_node_index) = try_execute_query(
tcx,
Q::query_state(tcx),
key,
lookup,
dep_node,
- query,
- compute,
+ &query,
);
if let Some(dep_node_index) = dep_node_index {
tcx.dep_context().dep_graph().read_index(dep_node_index)
Some(result)
}
-pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
+pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
where
Q: QueryDescription<CTX>,
Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- if Q::ANON {
- return false;
- }
-
- if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() {
- return false;
- }
+ // We may be concurrently trying both execute and force a query.
+ // Ensure that only one of them runs the query.
+ let cache = Q::query_cache(tcx);
+ let cached = cache.cache.lookup(cache, &key, |_, index| {
+ if unlikely!(tcx.dep_context().profiler().enabled()) {
+ tcx.dep_context().profiler().query_cache_hit(index.into());
+ }
+ });
- let key = if let Some(key) =
- <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
- {
- key
- } else {
- return false;
+ let lookup = match cached {
+ Ok(()) => return,
+ Err(lookup) => lookup,
};
- let compute = Q::compute_fn(tcx, &key);
- force_query_impl(
- tcx,
- Q::query_state(tcx),
- Q::query_cache(tcx),
- key,
- *dep_node,
- &Q::VTABLE,
- compute,
- )
+ let query = Q::make_vtable(tcx, &key);
+ let state = Q::query_state(tcx);
+ debug_assert!(!query.anon);
+
+ try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query);
}
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_metadata = { path = "../rustc_metadata" }
+rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
- let expn_id = if def_kind == DefKind::Mod {
- self.cstore().module_expansion_untracked(def_id, &self.session)
- } else {
- // FIXME: Parent expansions for enums and traits are not kept in metadata.
- ExpnId::root()
- };
Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, name),
- expn_id,
+ self.cstore().module_expansion_untracked(def_id, &self.session),
self.cstore().get_span_untracked(def_id, &self.session),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.map_or(false, |module| module.no_implicit_prelude),
pub descr: &'static str,
pub path: Path,
pub accessible: bool,
+ /// An extra note that should be issued if this item is suggested
+ pub note: Option<String>,
}
/// Adjust the impl span so that just the `impl` keyword is taken by removing
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
+ if suggestions.is_empty() {
+ err.help(&msg);
+ return err;
+ }
err.multipart_suggestion(&msg, suggestions, applicability);
}
return;
}
+ // #90113: Do not count an inaccessible reexported item as a candidate.
+ if let NameBindingKind::Import { binding, .. } = name_binding.kind {
+ if this.is_accessible_from(binding.vis, parent_scope.module)
+ && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+ {
+ return;
+ }
+ }
+
// collect results based on the filter function
// avoid suggesting anything from the same module in which we are resolving
+ // avoid suggesting anything with a hygienic name
if ident.name == lookup_ident.name
&& ns == namespace
&& !ptr::eq(in_module, parent_scope.module)
+ && !ident.span.normalize_to_macros_2_0().from_expansion()
{
let res = name_binding.res();
if filter_fn(res) {
}
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+ // See if we're recommending TryFrom, TryInto, or FromIterator and add
+ // a note about editions
+ let note = if let Some(did) = did {
+ let requires_note = !did.is_local()
+ && this.cstore().item_attrs(did, this.session).iter().any(
+ |attr| {
+ if attr.has_name(sym::rustc_diagnostic_item) {
+ [sym::TryInto, sym::TryFrom, sym::FromIterator]
+ .map(|x| Some(x))
+ .contains(&attr.value_str())
+ } else {
+ false
+ }
+ },
+ );
+
+ requires_note.then(|| {
+ format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ path_names_to_string(&path)
+ )
+ })
+ } else {
+ None
+ };
+
candidates.push(ImportSuggestion {
did,
descr: res.descr(),
path,
accessible: child_accessible,
+ note,
});
}
}
(b1, b2, misc1, misc2, false)
};
- let mut err = struct_span_err!(
- self.session,
- ident.span,
- E0659,
- "`{ident}` is ambiguous ({why})",
- why = kind.descr()
- );
+ let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
err.span_label(ident.span, "ambiguous name");
+ err.note(&format!("ambiguous because of {}", kind.descr()));
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
{
// Insert a placeholder that's later replaced by `self`/`super`/etc.
- path.insert(0, Segment::from_ident(Ident::invalid()));
+ path.insert(0, Segment::from_ident(Ident::empty()));
}
_ => return None,
}
module: ModuleOrUniformRoot<'b>,
ident: Ident,
) -> Option<(Option<Suggestion>, Vec<String>)> {
- let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module {
- module
- } else {
+ let ModuleOrUniformRoot::Module(mut crate_module) = module else {
return None;
};
return;
}
- let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
- let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+ let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
+ let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
candidates.iter().for_each(|c| {
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
- .push((path_names_to_string(&c.path), c.descr, c.did))
+ .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
});
// we want consistent results across executions, but candidates are produced
let instead = if instead { " instead" } else { "" };
let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
+ for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ err.note(note);
+ }
+
if let Some(span) = use_placement_span {
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
assert!(!inaccessible_path_strings.is_empty());
if inaccessible_path_strings.len() == 1 {
- let (name, descr, def_id) = &inaccessible_path_strings[0];
+ let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!("{} `{}` exists but is inaccessible", descr, name);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
} else {
err.note(&msg);
}
+ if let Some(note) = (*note).as_deref() {
+ err.note(note);
+ }
} else {
- let (_, descr_first, _) = &inaccessible_path_strings[0];
+ let (_, descr_first, _, _) = &inaccessible_path_strings[0];
let descr = if inaccessible_path_strings
.iter()
.skip(1)
- .all(|(_, descr, _)| descr == descr_first)
+ .all(|(_, descr, _, _)| descr == descr_first)
{
- format!("{}", descr_first)
+ descr_first.to_string()
} else {
"item".to_string()
};
let mut has_colon = false;
let mut spans = Vec::new();
- for (name, _, def_id) in &inaccessible_path_strings {
+ for (name, _, def_id, _) in &inaccessible_path_strings {
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
let span = definitions.def_span(local_def_id);
let span = session.source_map().guess_head_span(span);
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
}
+ for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ err.note(note);
+ }
+
err.span_note(multi_span, &msg);
}
}
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
- full_path.push(Segment::from_ident(Ident::invalid()));
+ full_path.push(Segment::from_ident(Ident::empty()));
self.r.lint_if_path_starts_with_module(
import.crate_lint(),
&full_path,
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
let traits = self.traits_in_scope(item_name, ns);
- self.r.trait_map.as_mut().unwrap().insert(id, traits);
+ self.r.trait_map.insert(id, traits);
}
if PrimTy::from_name(path[0].ident.name).is_some() {
// the field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.traits_in_scope(ident, ValueNS);
- self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
ExprKind::MethodCall(ref segment, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
let traits = self.traits_in_scope(segment.ident, ValueNS);
- self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
+ self.r.trait_map.insert(expr.id, traits);
}
_ => {
// Nothing to do.
descr: "module",
path,
accessible: true,
+ note: None,
},
));
} else {
matches!(source, PathSource::TupleStruct(..)) || source.is_call();
if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
- // suggest path with added parenthesis.
+ // suggest path with added parentheses.
let mut suggestable_variants = variants
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (name, reg) = Region::early(&self.tcx.hir(), &mut index, ¶m);
- let def_id = if let Region::EarlyBound(_, def_id, _) = reg {
- def_id
- } else {
+ let Region::EarlyBound(_, def_id, _) = reg else {
bug!();
};
// We cannot predict what lifetimes are unused in opaque type.
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![recursion_limit = "256"]
use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_query_system::ich::StableHashingContext;
use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
use rustc_session::lint;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency};
-use rustc_span::source_map::{CachingSourceMapView, Spanned};
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
impl AmbiguityKind {
fn descr(self) -> &'static str {
match self {
- AmbiguityKind::Import => "name vs any other name during import resolution",
- AmbiguityKind::BuiltinAttr => "built-in attribute vs any other name",
- AmbiguityKind::DeriveHelper => "derive helper attribute vs any other name",
+ AmbiguityKind::Import => "multiple potential import sources",
+ AmbiguityKind::BuiltinAttr => "a name conflict with a builtin attribute",
+ AmbiguityKind::DeriveHelper => "a name conflict with a derive helper attribute",
AmbiguityKind::MacroRulesVsModularized => {
- "`macro_rules` vs non-`macro_rules` from other module"
+ "a conflict between a `macro_rules` name and a non-`macro_rules` name from another module"
}
AmbiguityKind::GlobVsOuter => {
- "glob import vs any other name from outer scope during import/macro resolution"
+ "a conflict between a name from a glob import and an outer scope during import or macro resolution"
}
- AmbiguityKind::GlobVsGlob => "glob import vs glob import in the same module",
+ AmbiguityKind::GlobVsGlob => "multiple glob imports of a name in the same module",
AmbiguityKind::GlobVsExpanded => {
- "glob import vs macro-expanded name in the same \
- module during import/macro resolution"
+ "a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution"
}
AmbiguityKind::MoreExpandedVsOuter => {
- "macro-expanded name vs less macro-expanded name \
- from outer scope during import/macro resolution"
+ "a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution"
}
}
}
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
export_map: ExportMap,
- trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
+ trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
/// Anonymous modules are pseudo-modules that are implicitly created around items
&mut self.definitions
}
+ fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
+ StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
+ }
+
fn lint_buffer(&mut self) -> &mut LintBuffer {
&mut self.lint_buffer
}
self.next_node_id()
}
- fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
- std::mem::replace(&mut self.trait_map, None).unwrap()
+ fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<TraitCandidate>> {
+ self.trait_map.remove(&node)
}
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
}
}
-struct ExpandHasher<'a, 'b> {
- source_map: CachingSourceMapView<'a>,
- resolver: &'a Resolver<'b>,
-}
-
-impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> {
- #[inline]
- fn hash_spans(&self) -> bool {
- true
- }
-
- #[inline]
- fn def_span(&self, id: LocalDefId) -> Span {
- self.resolver.def_span(id)
- }
-
- #[inline]
- fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
- self.resolver.def_path_hash(def_id)
- }
-
- #[inline]
- fn span_data_to_lines_and_cols(
- &mut self,
- span: &rustc_span::SpanData,
- ) -> Option<(Lrc<rustc_span::SourceFile>, usize, rustc_span::BytePos, usize, rustc_span::BytePos)>
- {
- self.source_map.span_data_to_lines_and_cols(span)
- }
-}
-
impl<'a> Resolver<'a> {
pub fn new(
session: &'a Session,
label_res_map: Default::default(),
extern_crate_map: Default::default(),
export_map: FxHashMap::default(),
- trait_map: Some(NodeMap::default()),
+ trait_map: NodeMap::default(),
underscore_disambiguator: 0,
empty_module,
module_map,
self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
}
- fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> {
- ExpandHasher {
- source_map: CachingSourceMapView::new(self.session.source_map()),
- resolver: self,
- }
- }
-
pub fn next_node_id(&mut self) -> NodeId {
let next = self
.next_node_id
} else {
(
format!("use of undeclared crate or module `{}`", ident),
- self.find_similarly_named_module_or_crate(
- ident.name,
- &parent_scope.module,
- )
- .map(|sugg| {
- (
- vec![(ident.span, sugg.to_string())],
+ if ident.name == sym::alloc {
+ Some((
+ vec![],
String::from(
- "there is a crate or module with a similar name",
+ "add `extern crate alloc` to use the `alloc` crate",
),
Applicability::MaybeIncorrect,
+ ))
+ } else {
+ self.find_similarly_named_module_or_crate(
+ ident.name,
+ &parent_scope.module,
)
- }),
+ .map(|sugg| {
+ (
+ vec![(ident.span, sugg.to_string())],
+ String::from(
+ "there is a crate or module with a similar name",
+ ),
+ Applicability::MaybeIncorrect,
+ )
+ })
+ },
)
}
} else {
id,
span,
name: ident.to_string(),
- qualname: format!("{}::{}", qualname, ident.to_string()),
+ qualname: format!("{}::{}", qualname, ident),
value: typ,
parent: None,
children: vec![],
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(ident.span) {
- let qualname = format!("{}${}", ident.to_string(), hir_id);
+ let qualname = format!("{}${}", ident, hir_id);
let id = id_from_hir_id(hir_id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
d.read_seq(|d, len| {
assert!(len == N);
let mut v = [0u8; N];
- for x in &mut v {
- *x = d.read_seq_elt(|d| Decodable::decode(d))?;
+ for i in 0..len {
+ v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
}
Ok(v)
})
}
}
+/// The different settings that can be enabled via the `-Z location-detail` flag.
+#[derive(Clone, PartialEq, Hash, Debug)]
+pub struct LocationDetail {
+ pub file: bool,
+ pub line: bool,
+ pub column: bool,
+}
+
+impl LocationDetail {
+ pub fn all() -> Self {
+ Self { file: true, line: true, column: true }
+ }
+}
+
#[derive(Clone, PartialEq, Hash, Debug)]
pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
- LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
+ LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
Option<LdImpl>,
OutputType,
RealFileName,
+ LocationDetail,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizers: &str =
- "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub const parse_linker_plugin_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+ pub const parse_location_detail: &str =
+ "comma seperated list of location details to track: `file`, `line`, or `column`";
pub const parse_switch_with_opt_path: &str =
"an optional path to the profiling data output directory";
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
}
}
+ crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
+ if let Some(v) = v {
+ ld.line = false;
+ ld.file = false;
+ ld.column = false;
+ for s in v.split(',') {
+ match s {
+ "file" => ld.file = true,
+ "line" => ld.line = true,
+ "column" => ld.column = true,
+ _ => return false,
+ }
+ }
+ true
+ } else {
+ false
+ }
+ }
+
crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
match v {
Some(s) => {
for s in v.split(',') {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
+ "cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
"a list LLVM plugins to enable (space separated)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
"generate JSON tracing data file from LLVM data (default: no)"),
+ location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
+ "comma seperated list of location details to be tracked when using caller_location \
+ valid options are `file`, `line`, and `column` (default: all)"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
+ "emit noalias metadata for mutable references (default: yes)"),
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
"use new LLVM pass manager (default: no)"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
"compile without linking"),
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+ no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+ "do not use unique names for text and data sections when -Z function-sections is used"),
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
"prevent automatic injection of the profiler_builtins crate"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
"specify the events recorded by the self profiler;
for example: `-Z self-profile-events=default,query-keys`
all options: none, all, default, generic-activity, query-provider, query-cache-hit
- query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm"),
+ query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
show_span: Option<String> = (None, parse_opt_string, [TRACKED],
}
}
- pub fn with_silent_emitter() -> Self {
+ pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
- let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
+ let fatal_handler = Handler::with_tty_emitter(ColorConfig::Auto, false, None, None);
+ let handler = Handler::with_emitter(
+ false,
+ None,
+ Box::new(SilentEmitter { fatal_handler, fatal_note }),
+ );
ParseSess::with_span_handler(handler, sm)
}
pub fn is_nightly_build(&self) -> bool {
self.opts.unstable_features.is_nightly_build()
}
+ pub fn is_sanitizer_cfi_enabled(&self) -> bool {
+ self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
+ }
pub fn overflow_checks(&self) -> bool {
self.opts
.cg
disable it using `-C target-feature=-crt-static`",
);
}
+
+ // LLVM CFI requires LTO.
+ if sess.is_sanitizer_cfi_enabled() {
+ if sess.opts.cg.lto == config::LtoCli::Unspecified
+ || sess.opts.cg.lto == config::LtoCli::No
+ || sess.opts.cg.lto == config::LtoCli::Thin
+ {
+ sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+ }
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
/// }
- /// n(f);
+ /// n!(f);
/// macro n($j:ident) {
/// use foo::*;
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
let lookup = &lookup.as_str();
let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
- let (case_insensitive_match, levenshtein_match) = name_vec
+ // Priority of matches:
+ // 1. Exact case insensitive match
+ // 2. Levenshtein distance match
+ // 3. Sorted word match
+ if let Some(case_insensitive_match) =
+ name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase())
+ {
+ return Some(*case_insensitive_match);
+ }
+ let levenshtein_match = name_vec
.iter()
.filter_map(|&name| {
let dist = lev_distance(lookup, &name.as_str());
if dist <= max_dist { Some((name, dist)) } else { None }
})
// Here we are collecting the next structure:
- // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
- .fold((None, None), |result, (candidate, dist)| {
- (
- if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
- Some(candidate)
- } else {
- result.0
- },
- match result.1 {
- None => Some((candidate, dist)),
- Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
- },
- )
+ // (levenshtein_match, levenshtein_distance)
+ .fold(None, |result, (candidate, dist)| match result {
+ None => Some((candidate, dist)),
+ Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
});
- // Priority of matches:
- // 1. Exact case insensitive match
- // 2. Levenshtein distance match
- // 3. Sorted word match
- if let Some(candidate) = case_insensitive_match {
- Some(candidate)
- } else if levenshtein_match.is_some() {
+ if levenshtein_match.is_some() {
levenshtein_match.map(|(candidate, _)| candidate)
} else {
find_match_by_sorted_words(name_vec, lookup)
assert_eq!(find_best_match_for_name(&input, Symbol::intern("1111111111"), None), None);
- let input = vec![Symbol::intern("aAAA")];
+ let input = vec![Symbol::intern("AAAA")];
assert_eq!(
- find_best_match_for_name(&input, Symbol::intern("AAAA"), None),
- Some(Symbol::intern("aAAA"))
+ find_best_match_for_name(&input, Symbol::intern("aaaa"), None),
+ Some(Symbol::intern("AAAA"))
);
- let input = vec![Symbol::intern("AAAA")];
- // Returns None because `lev_distance > max_dist / 3`
- assert_eq!(find_best_match_for_name(&input, Symbol::intern("aaaa"), None), None);
-
let input = vec![Symbol::intern("AAAA")];
assert_eq!(
find_best_match_for_name(&input, Symbol::intern("aaaa"), Some(4)),
await_macro,
bang,
begin_panic,
- begin_panic_fmt,
bench,
bin,
bind_by_move_pattern_guards,
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
+ cfi,
char,
client,
clippy,
div_assign,
doc,
doc_alias,
+ doc_auto_cfg,
doc_cfg,
doc_cfg_hide,
doc_keyword,
rustc_partition_reused,
rustc_peek,
rustc_peek_definite_init,
- rustc_peek_indirectly_mutable,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,
rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
+ rustc_strict_coherence,
rustc_symbol_name,
rustc_synthetic,
rustc_test_marker,
type_alias_enum_variants,
type_alias_impl_trait,
type_ascription,
+ type_changing_struct_update,
type_id,
type_length_limit,
type_macros,
}
#[inline]
- pub fn invalid() -> Ident {
+ pub fn empty() -> Ident {
Ident::with_dummy_span(kw::Empty)
}
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
+use rustc_target::abi::call::FnAbi;
use tracing::debug;
ty::SymbolName::new(tcx, &symbol_name)
}
+/// This function computes the typeid for the given function ABI.
+pub fn typeid_for_fnabi(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+ v0::mangle_typeid_for_fnabi(tcx, fn_abi)
+}
+
/// Computes the symbol name for the given instance. This function will call
/// `compute_instantiating_crate` if it needs to factor the instantiating crate
/// into the symbol name.
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;
std::mem::take(&mut cx.out)
}
+pub(super) fn mangle_typeid_for_fnabi(
+ _tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+) -> String {
+ // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
+ // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
+ // associated with a type identifier (i.e., test type membership).
+ //
+ // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
+ // type metadata identifiers for function pointers. The typeinfo name encoding is a
+ // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
+ //
+ // For cross-language LLVM CFI support, a compatible encoding must be used by either
+ //
+ // a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
+ // type encodings[4]), or at least types used at the FFI boundary.
+ // b. Reducing the types to the least common denominator between types used by Clang (or at
+ // least types used at the FFI boundary) and Rust compilers (if even possible).
+ // c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
+ // possibly other compilers).
+ //
+ // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
+ // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
+ // code. Option (c) would require changes to Clang to use the new ABI.
+ //
+ // [1] https://llvm.org/docs/TypeMetadata.html
+ // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
+ // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
+ // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
+ //
+ // FIXME(rcvalle): See comment above.
+ let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
+ format!("typeid{}", arg_count)
+}
+
struct BinderLevel {
/// The range of distances from the root of what's
/// being printed, to the lifetimes in a binder.
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
const InReg = 1 << 5;
- // NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles
- // in earlier versions. FIXME: Remove this distinction once possible.
+ // Due to past miscompiles in LLVM, we use a separate attribute for
+ // &mut arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled
+ // with the `-Zmutable-noalias` debugging option.
const NoAliasMutRef = 1 << 6;
}
}
// In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
// If niche zero is already reserved, the selection of bounds are of little interest.
let move_start = |v: WrappingRange| {
- let start = v.start.wrapping_sub(1) & max_value;
+ let start = v.start.wrapping_sub(count) & max_value;
Some((start, Scalar { value, valid_range: v.with_start(start) }))
};
let move_end = |v: WrappingRange| {
pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
- base.cpu = "apple-a12".to_string();
+ base.cpu = "apple-a14".to_string();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
..base
arch: "aarch64".to_string(),
options: TargetOptions {
max_atomic_width: Some(128),
- supported_sanitizers: SanitizerSet::ADDRESS,
+ supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
..super::fuchsia_base::opts()
},
}
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
features: "+neon,+fp-armv8".to_string(),
- supported_sanitizers: SanitizerSet::HWADDRESS,
+ supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
..super::android_base::opts()
},
}
options: TargetOptions {
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::MEMORY
| SanitizerSet::THREAD,
..super::freebsd_base::opts()
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::THREAD
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
..super::linux_gnu_base::opts()
pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
- options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
+ options: TargetOptions {
+ features: "+outline-atomics".to_string(),
+ mcount: "\u{1}_mcount".to_string(),
+ ..base
+ },
}
}
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions, TlsModel};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
);
TargetOptions {
- os: "hermit".to_string(),
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
disable_redzone: true,
linker: Some("rust-lld".to_owned()),
executables: true,
- has_elf_tls: true,
pre_link_args,
panic_strategy: PanicStrategy::Abort,
position_independent_executables: true,
static_position_independent_executables: true,
- tls_model: TlsModel::InitialExec,
..Default::default()
}
}
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
+ const CFI = 1 << 5;
}
}
fn as_str(self) -> Option<&'static str> {
Some(match self {
SanitizerSet::ADDRESS => "address",
+ SanitizerSet::CFI => "cfi",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::THREAD => "thread",
fn into_iter(self) -> Self::IntoIter {
[
SanitizerSet::ADDRESS,
+ SanitizerSet::CFI,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::THREAD,
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
+
+ ("x86_64-unknown-none", x86_64_unknown_none),
}
/// Warnings encountered when parsing the target `json`.
AmdGpuKernel => self.arch == "amdgcn",
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
+ Thiscall { .. } => self.arch == "x86",
// On windows these fall-back to platform native calling convention (C) when the
// architecture is not supported.
//
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
- Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall if self.is_like_windows => {
- true
- }
+ Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
// Outside of Windows we want to only support these calling conventions for the
// architectures for which these calling conventions are actually well defined.
- Stdcall { .. } | Fastcall | Thiscall { .. } if self.arch == "x86" => true,
+ Stdcall { .. } | Fastcall if self.arch == "x86" => true,
Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
// Return a `None` for other cases so that we know to emit a future compat lint.
- Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall => return None,
+ Stdcall { .. } | Fastcall | Vectorcall => return None,
})
}
for s in a {
base.$key_name |= match s.as_string() {
Some("address") => SanitizerSet::ADDRESS,
+ Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("thread") => SanitizerSet::THREAD,
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-fuchsia".to_string(),
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-pc-solaris".to_string(),
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
// LLVM does not currently have a separate illumos target,
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
base.static_position_independent_executables = true;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
--- /dev/null
+// Generic x86-64 target for bare-metal code - Floating point disabled
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+
+use super::{
+ CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType,
+ Target, TargetOptions,
+};
+
+pub fn target() -> Target {
+ let opts = TargetOptions {
+ cpu: "x86-64".to_string(),
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+ stack_probes: StackProbeType::Call,
+ position_independent_executables: true,
+ static_position_independent_executables: true,
+ relro_level: RelroLevel::Full,
+ relocation_model: RelocModel::Pic,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker: Some("rust-lld".to_owned()),
+ features:
+ "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
+ .to_string(),
+ executables: true,
+ disable_redzone: true,
+ panic_strategy: PanicStrategy::Abort,
+ code_model: Some(CodeModel::Kernel),
+ ..Default::default()
+ };
+ Target {
+ llvm_target: "x86_64-unknown-none-elf".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+ .to_string(),
+ arch: "x86_64".to_string(),
+ options: opts,
+ }
+}
#![feature(hash_drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
-use crate::traits::{self, ObligationCause, PredicateObligation};
+use crate::traits;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::free_regions::FreeRegionRelations;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, InferCtxt, InferOk};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::Span;
-use std::ops::ControlFlow;
-
-/// Whether member constraints should be generated for all opaque types
-#[derive(Debug)]
-pub enum GenerateMemberConstraints {
- /// The default, used by typeck
- WhenRequired,
- /// The borrow checker needs member constraints in any case where we don't
- /// have a `'static` bound. This is because the borrow checker has more
- /// flexibility in the values of regions. For example, given `f<'a, 'b>`
- /// the borrow checker can have an inference variable outlive `'a` and `'b`,
- /// but not be equal to `'static`.
- IfNoStaticBound,
-}
-
pub trait InferCtxtExt<'tcx> {
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T>;
-
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
-
- fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- mode: GenerateMemberConstraints,
- free_region_relations: &FRR,
- );
-
- /*private*/
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region_index: usize,
- );
-
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
- /// Replaces all opaque types in `value` with fresh inference variables
- /// and creates appropriate obligations. For example, given the input:
- ///
- /// impl Iterator<Item = impl Debug>
- ///
- /// this method would create two type variables, `?0` and `?1`. It would
- /// return the type `?0` but also the obligations:
- ///
- /// ?0: Iterator<Item = ?1>
- /// ?1: Debug
- ///
- /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
- /// info about the `impl Iterator<..>` type and `?1` to info about
- /// the `impl Debug` type.
- ///
- /// # Parameters
- ///
- /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
- /// is defined
- /// - `body_id` -- the body-id with which the resulting obligations should
- /// be associated
- /// - `param_env` -- the in-scope parameter environment to be used for
- /// obligations
- /// - `value` -- the value within which we are instantiating opaque types
- /// - `value_span` -- the span where the value came from, used in error reporting
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T> {
- debug!(
- "instantiate_opaque_types(value={:?}, body_id={:?}, \
- param_env={:?}, value_span={:?})",
- value, body_id, param_env, value_span,
- );
- let mut instantiator =
- Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
- let value = instantiator.instantiate_opaque_types_in_map(value);
- InferOk { value, obligations: instantiator.obligations }
- }
-
- /// Given the map `opaque_types` containing the opaque
- /// `impl Trait` types whose underlying, hidden types are being
- /// inferred, this method adds constraints to the regions
- /// appearing in those underlying hidden types to ensure that they
- /// at least do not refer to random scopes within the current
- /// function. These constraints are not (quite) sufficient to
- /// guarantee that the regions are actually legal values; that
- /// final condition is imposed after region inference is done.
- ///
- /// # The Problem
- ///
- /// Let's work through an example to explain how it works. Assume
- /// the current function is as follows:
- ///
- /// ```text
- /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
- /// ```
- ///
- /// Here, we have two `impl Trait` types whose values are being
- /// inferred (the `impl Bar<'a>` and the `impl
- /// Bar<'b>`). Conceptually, this is sugar for a setup where we
- /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
- /// the return type of `foo`, we *reference* those definitions:
- ///
- /// ```text
- /// type Foo1<'x> = impl Bar<'x>;
- /// type Foo2<'x> = impl Bar<'x>;
- /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
- /// // ^^^^ ^^
- /// // | |
- /// // | substs
- /// // def_id
- /// ```
- ///
- /// As indicating in the comments above, each of those references
- /// is (in the compiler) basically a substitution (`substs`)
- /// applied to the type of a suitable `def_id` (which identifies
- /// `Foo1` or `Foo2`).
- ///
- /// Now, at this point in compilation, what we have done is to
- /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
- /// fresh inference variables C1 and C2. We wish to use the values
- /// of these variables to infer the underlying types of `Foo1` and
- /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
- /// constraints like:
- ///
- /// ```text
- /// for<'a> (Foo1<'a> = C1)
- /// for<'b> (Foo1<'b> = C2)
- /// ```
- ///
- /// For these equation to be satisfiable, the types `C1` and `C2`
- /// can only refer to a limited set of regions. For example, `C1`
- /// can only refer to `'static` and `'a`, and `C2` can only refer
- /// to `'static` and `'b`. The job of this function is to impose that
- /// constraint.
- ///
- /// Up to this point, C1 and C2 are basically just random type
- /// inference variables, and hence they may contain arbitrary
- /// regions. In fact, it is fairly likely that they do! Consider
- /// this possible definition of `foo`:
- ///
- /// ```text
- /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
- /// (&*x, &*y)
- /// }
- /// ```
- ///
- /// Here, the values for the concrete types of the two impl
- /// traits will include inference variables:
- ///
- /// ```text
- /// &'0 i32
- /// &'1 i32
- /// ```
- ///
- /// Ordinarily, the subtyping rules would ensure that these are
- /// sufficiently large. But since `impl Bar<'a>` isn't a specific
- /// type per se, we don't get such constraints by default. This
- /// is where this function comes into play. It adds extra
- /// constraints to ensure that all the regions which appear in the
- /// inferred type are regions that could validly appear.
- ///
- /// This is actually a bit of a tricky constraint in general. We
- /// want to say that each variable (e.g., `'0`) can only take on
- /// values that were supplied as arguments to the opaque type
- /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
- /// scope. We don't have a constraint quite of this kind in the current
- /// region checker.
- ///
- /// # The Solution
- ///
- /// We generally prefer to make `<=` constraints, since they
- /// integrate best into the region solver. To do that, we find the
- /// "minimum" of all the arguments that appear in the substs: that
- /// is, some region which is less than all the others. In the case
- /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
- /// all). Then we apply that as a least bound to the variables
- /// (e.g., `'a <= '0`).
- ///
- /// In some cases, there is no minimum. Consider this example:
- ///
- /// ```text
- /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
- /// ```
- ///
- /// Here we would report a more complex "in constraint", like `'r
- /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
- /// the hidden type).
- ///
- /// # Constrain regions, not the hidden concrete type
- ///
- /// Note that generating constraints on each region `Rc` is *not*
- /// the same as generating an outlives constraint on `Tc` iself.
- /// For example, if we had a function like this:
- ///
- /// ```rust
- /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
- /// (x, y)
- /// }
- ///
- /// // Equivalent to:
- /// type FooReturn<'a, T> = impl Foo<'a>;
- /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
- /// ```
- ///
- /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
- /// is an inference variable). If we generated a constraint that
- /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
- /// but this is not necessary, because the opaque type we
- /// create will be allowed to reference `T`. So we only generate a
- /// constraint that `'0: 'a`.
- ///
- /// # The `free_region_relations` parameter
- ///
- /// The `free_region_relations` argument is used to find the
- /// "minimum" of the regions supplied to a given opaque type.
- /// It must be a relation that can answer whether `'a <= 'b`,
- /// where `'a` and `'b` are regions that appear in the "substs"
- /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
- ///
- /// Note that we do not impose the constraints based on the
- /// generic regions from the `Foo1` definition (e.g., `'x`). This
- /// is because the constraints we are imposing here is basically
- /// the concern of the one generating the constraining type C1,
- /// which is the current function. It also means that we can
- /// take "implied bounds" into account in some cases:
- ///
- /// ```text
- /// trait SomeTrait<'a, 'b> { }
- /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
- /// ```
- ///
- /// Here, the fact that `'b: 'a` is known only because of the
- /// implied bounds from the `&'a &'b u32` parameter, and is not
- /// "inherent" to the opaque type definition.
- ///
- /// # Parameters
- ///
- /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
- /// - `free_region_relations` -- something that can be used to relate
- /// the free regions (`'a`) that appear in the impl trait.
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
- let opaque_types = self.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_defn) in opaque_types {
- self.constrain_opaque_type(
- opaque_type_key,
- &opaque_defn,
- GenerateMemberConstraints::WhenRequired,
- free_region_relations,
- );
- }
- }
-
- /// See `constrain_opaque_types` for documentation.
- #[instrument(level = "debug", skip(self, free_region_relations))]
- fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- mode: GenerateMemberConstraints,
- free_region_relations: &FRR,
- ) {
- let def_id = opaque_type_key.def_id;
-
- let tcx = self.tcx;
-
- let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
-
- debug!(?concrete_ty);
-
- let first_own_region = match opaque_defn.origin {
- hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
- // We lower
- //
- // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
- //
- // into
- //
- // type foo::<'p0..'pn>::Foo<'q0..'qm>
- // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
- //
- // For these types we only iterate over `'l0..lm` below.
- tcx.generics_of(def_id).parent_count
- }
- // These opaque type inherit all lifetime parameters from their
- // parent, so we have to check them all.
- hir::OpaqueTyOrigin::TyAlias => 0,
- };
-
- let span = tcx.def_span(def_id);
-
- // Check if the `impl Trait` bounds include region bounds.
- // For example, this would be true for:
- //
- // fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
- //
- // but false for:
- //
- // fn foo<'c>() -> impl Trait<'c>
- //
- // unless `Trait` was declared like:
- //
- // trait Trait<'c>: 'c
- //
- // in which case it would be true.
- //
- // This is used during regionck to decide whether we need to
- // impose any additional constraints to ensure that region
- // variables in `concrete_ty` wind up being constrained to
- // something from `substs` (or, at minimum, things that outlive
- // the fn body). (Ultimately, writeback is responsible for this
- // check.)
- let bounds = tcx.explicit_item_bounds(def_id);
- debug!("{:#?}", bounds);
- let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs));
- debug!("{:#?}", bounds);
- let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
-
- let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
- if !required_region_bounds.is_empty() {
- for required_region in required_region_bounds {
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx,
- op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
- });
- }
- if let GenerateMemberConstraints::IfNoStaticBound = mode {
- self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- return;
- }
-
- // There were no `required_region_bounds`,
- // so we have to search for a `least_region`.
- // Go through all the regions used as arguments to the
- // opaque type. These are the parameters to the opaque
- // type; so in our example above, `substs` would contain
- // `['a]` for the first impl trait and `'b` for the
- // second.
- let mut least_region = None;
-
- for subst_arg in &opaque_type_key.substs[first_own_region..] {
- let subst_region = match subst_arg.unpack() {
- GenericArgKind::Lifetime(r) => r,
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
- };
-
- // Compute the least upper bound of it with the other regions.
- debug!(?least_region);
- debug!(?subst_region);
- match least_region {
- None => least_region = Some(subst_region),
- Some(lr) => {
- if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) {
- // keep the current least region
- } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) {
- // switch to `subst_region`
- least_region = Some(subst_region);
- } else {
- // There are two regions (`lr` and
- // `subst_region`) which are not relatable. We
- // can't find a best choice. Therefore,
- // instead of creating a single bound like
- // `'r: 'a` (which is our preferred choice),
- // we will create a "in bound" like `'r in
- // ['a, 'b, 'c]`, where `'a..'c` are the
- // regions that appear in the impl trait.
-
- return self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- }
- }
- }
-
- let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
- debug!(?least_region);
-
- if let GenerateMemberConstraints::IfNoStaticBound = mode {
- if least_region != tcx.lifetimes.re_static {
- self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
- }
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx,
- op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
- });
- }
-
- /// As a fallback, we sometimes generate an "in constraint". For
- /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be
- /// related, we would generate a constraint `'r in ['a, 'b,
- /// 'static]` for each region `'r` that appears in the hidden type
- /// (i.e., it must be equal to `'a`, `'b`, or `'static`).
- ///
- /// `conflict1` and `conflict2` are the two region bounds that we
- /// detected which were unrelated. They are used for diagnostics.
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region: usize,
- ) {
- // Create the set of choice regions: each region in the hidden
- // type can be equal to any of the region parameters of the
- // opaque type definition.
- let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
- opaque_type_key.substs[first_own_region..]
- .iter()
- .filter_map(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => Some(r),
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
- })
- .chain(std::iter::once(self.tcx.lifetimes.re_static))
- .collect(),
- );
-
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx: self.tcx,
- op: |r| {
- self.member_constraint(
- opaque_type_key.def_id,
- opaque_defn.definition_span,
- concrete_ty,
- r,
- &choice_regions,
- )
- },
- });
- }
-
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
- /// `constrain_opaque_types`. Read that comment for more context.
+ /// `constrain_opaque_type`. Read that comment for more context.
///
/// # Parameters
///
}
}
-// Visitor that requires that (almost) all regions in the type visited outlive
-// `least_region`. We cannot use `push_outlives_components` because regions in
-// closure signatures are not included in their outlives components. We need to
-// ensure all regions outlive the given bound so that we don't end up with,
-// say, `ReVar` appearing in a return type and causing ICEs when other
-// functions end up with region constraints involving regions from other
-// functions.
-//
-// We also cannot use `for_each_free_region` because for closures it includes
-// the regions parameters from the enclosing item.
-//
-// We ignore any type parameters because impl trait values are assumed to
-// capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
- tcx: TyCtxt<'tcx>,
- op: OP,
-}
-
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
-where
- OP: FnMut(ty::Region<'tcx>),
-{
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
- fn visit_binder<T: TypeFoldable<'tcx>>(
- &mut self,
- t: &ty::Binder<'tcx, T>,
- ) -> ControlFlow<Self::BreakTy> {
- t.as_ref().skip_binder().visit_with(self);
- ControlFlow::CONTINUE
- }
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match *r {
- // ignore bound regions, keep visiting
- ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
- _ => {
- (self.op)(r);
- ControlFlow::CONTINUE
- }
- }
- }
-
- fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- // We're only interested in types involving regions
- if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
- return ControlFlow::CONTINUE;
- }
-
- match ty.kind() {
- ty::Closure(_, ref substs) => {
- // Skip lifetime parameters of the enclosing item(s)
-
- substs.as_closure().tupled_upvars_ty().visit_with(self);
- substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
- }
-
- ty::Generator(_, ref substs, _) => {
- // Skip lifetime parameters of the enclosing item(s)
- // Also skip the witness type, because that has no free regions.
-
- substs.as_generator().tupled_upvars_ty().visit_with(self);
- substs.as_generator().return_ty().visit_with(self);
- substs.as_generator().yield_ty().visit_with(self);
- substs.as_generator().resume_ty().visit_with(self);
- }
- _ => {
- ty.super_visit_with(self);
- }
- }
-
- ControlFlow::CONTINUE
- }
-}
-
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
}
}
-struct Instantiator<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value_span: Span,
- obligations: Vec<PredicateObligation<'tcx>>,
-}
-
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
- fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let tcx = self.infcx.tcx;
- value.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- if let Some(def_id) = def_id.as_local() {
- let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.infcx.defining_use_anchor;
- let def_scope_default = || {
- let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
- };
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
- };
- if in_definition_scope {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
- }
-
- debug!(
- "instantiate_opaque_types_in_map: \
- encountered opaque outside its definition scope \
- def_id={:?}",
- def_id,
- );
- }
- }
-
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- }
-
- #[instrument(skip(self), level = "debug")]
- fn fold_opaque_ty(
- &mut self,
- ty: Ty<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- origin: hir::OpaqueTyOrigin,
- ) -> Ty<'tcx> {
- let infcx = self.infcx;
- let tcx = infcx.tcx;
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
- // Use the same type variable if the exact same opaque type appears more
- // than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
- debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
- return opaque_defn.concrete_ty;
- }
-
- let ty_var = infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span: self.value_span,
- });
-
- // Ideally, we'd get the span where *this specific `ty` came
- // from*, but right now we just use the span from the overall
- // value being folded. In simple cases like `-> impl Foo`,
- // these are the same span, but not in cases like `-> (impl
- // Foo, impl Bar)`.
- let definition_span = self.value_span;
-
- {
- let mut infcx = self.infcx.inner.borrow_mut();
- infcx.opaque_types.insert(
- OpaqueTypeKey { def_id, substs },
- OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
- );
- infcx.opaque_types_vars.insert(ty_var, ty);
- }
-
- debug!("generated new type inference var {:?}", ty_var.kind());
-
- let item_bounds = tcx.explicit_item_bounds(def_id);
-
- self.obligations.reserve(item_bounds.len());
- for (predicate, _) in item_bounds {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
- debug!(?predicate);
-
- // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
- let predicate = predicate.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| match ty.kind() {
- ty::Projection(projection_ty) => infcx.infer_projection(
- self.param_env,
- *projection_ty,
- ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
- debug!(?predicate);
-
- if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
- if projection.ty.references_error() {
- // No point on adding these obligations since there's a type error involved.
- return tcx.ty_error();
- }
- }
- // Change the predicate to refer to the type variable,
- // which will be the concrete type instead of the opaque type.
- // This also instantiates nested instances of `impl Trait`.
- let predicate = self.instantiate_opaque_types_in_map(predicate);
-
- let cause =
- traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
-
- // Require that the predicate holds for the concrete type.
- debug!(?predicate);
- self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
- }
-
- ty_var
- }
-}
-
-/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
-///
-/// Example:
-/// ```rust
-/// pub mod foo {
-/// pub mod bar {
-/// pub trait Bar { .. }
-///
-/// pub type Baz = impl Bar;
-///
-/// fn f1() -> Baz { .. }
-/// }
-///
-/// fn f2() -> bar::Baz { .. }
-/// }
-/// ```
-///
-/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
-/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
-/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
- let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- // Named opaque types can be defined by any siblings or children of siblings.
- let scope = tcx.hir().get_defining_scope(opaque_hir_id);
- // We walk up the node tree until we hit the root or the scope of the opaque type.
- while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().get_parent_item(hir_id);
- }
- // Syntactically, we are allowed to define the concrete type if:
- let res = hir_id == scope;
- trace!(
- "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
- tcx.hir().find(hir_id),
- tcx.hir().get(opaque_hir_id),
- res
- );
- res
-}
-
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
substs: infcx.tcx.mk_substs_trait(ty, &[]),
},
constness: ty::BoundConstness::NotConst,
+ // Auto traits are positive
+ polarity: ty::ImplPolarity::Positive,
}));
let computed_preds = param_env.caller_bounds().iter();
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::SkipLeakCheck;
-use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
+use crate::traits::{
+ self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Option<OverlapResult<'tcx>> {
+ fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ !selcx.predicate_may_hold_fatal(o)
+ }
+
+ fn strict_check(selcx: &SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ let infcx = selcx.infcx();
+ let tcx = infcx.tcx;
+ o.flip_polarity(tcx)
+ .as_ref()
+ .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
+ .unwrap_or(false)
+ }
+
// For the purposes of this check, we don't bring any placeholder
// types into scope; instead, we replace the generic types with
// fresh type variables, and hence we do our evaluations in an
debug!("overlap: unification check succeeded");
- // Are any of the obligations unsatisfiable? If so, no overlap.
+ // There's no overlap if obligations are unsatisfiable or if the obligation negated is
+ // satisfied.
+ //
+ // For example, given these two impl headers:
+ //
+ // `impl<'a> From<&'a str> for Box<dyn Error>`
+ // `impl<E> From<E> for Box<dyn Error> where E: Error`
+ //
+ // So we have:
+ //
+ // `Box<dyn Error>: From<&'?a str>`
+ // `Box<dyn Error>: From<?E>`
+ //
+ // After equating the two headers:
+ //
+ // `Box<dyn Error> = Box<dyn Error>`
+ // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
+ //
+ // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
+ // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
+ // at some point an impl for `&'?a str: Error` could be added.
let infcx = selcx.infcx();
+ let tcx = infcx.tcx;
let opt_failing_obligation = a_impl_header
.predicates
.iter()
predicate: p,
})
.chain(obligations)
- .find(|o| !selcx.predicate_may_hold_fatal(o));
+ .find(|o| {
+ // if both impl headers are set to strict coherence it means that this will be accepted
+ // only if it's stated that T: !Trait. So only prove that the negated obligation holds.
+ if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
+ && tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
+ {
+ strict_check(selcx, o)
+ } else {
+ loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
+ }
+ });
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
// to the canonical trait query form, `infcx.predicate_may_hold`, once
// the new system supports intercrate mode (which coherence needs).
Concrete,
}
let mut failure_kind = FailureKind::Concrete;
- walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() {
+ walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
Node::Leaf(leaf) => {
- let leaf = leaf.subst(tcx, ct.substs);
if leaf.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
} else if leaf.definitely_has_param_types_or_consts(tcx) {
ControlFlow::CONTINUE
}
Node::Cast(_, _, ty) => {
- let ty = ty.subst(tcx, ct.substs);
if ty.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
} else if ty.definitely_has_param_types_or_consts(tcx) {
pub struct AbstractConst<'tcx> {
// FIXME: Consider adding something like `IndexSlice`
// and use this here.
- pub inner: &'tcx [Node<'tcx>],
- pub substs: SubstsRef<'tcx>,
+ inner: &'tcx [Node<'tcx>],
+ substs: SubstsRef<'tcx>,
}
impl<'tcx> AbstractConst<'tcx> {
}
#[inline]
- pub fn root(self) -> Node<'tcx> {
- self.inner.last().copied().unwrap()
+ pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
+ let node = self.inner.last().copied().unwrap();
+ match node {
+ Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)),
+ Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)),
+ // Don't perform substitution on the following as they can't directly contain generic params
+ Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
+ }
}
}
f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
) -> ControlFlow<R> {
f(ct)?;
- let root = ct.root();
+ let root = ct.root(tcx);
match root {
Node::Leaf(_) => ControlFlow::CONTINUE,
Node::Binop(_, l, r) => {
// We substitute generics repeatedly to allow AbstractConsts to unify where a
// ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
- while let Node::Leaf(a_ct) = a.root() {
- let a_ct = a_ct.subst(tcx, a.substs);
+ while let Node::Leaf(a_ct) = a.root(tcx) {
match AbstractConst::from_const(tcx, a_ct) {
Ok(Some(a_act)) => a = a_act,
Ok(None) => break,
Err(_) => return true,
}
}
- while let Node::Leaf(b_ct) = b.root() {
- let b_ct = b_ct.subst(tcx, b.substs);
+ while let Node::Leaf(b_ct) = b.root(tcx) {
match AbstractConst::from_const(tcx, b_ct) {
Ok(Some(b_act)) => b = b_act,
Ok(None) => break,
}
}
- match (a.root(), b.root()) {
+ match (a.root(tcx), b.root(tcx)) {
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
- let a_ct = a_ct.subst(tcx, a.substs);
- let b_ct = b_ct.subst(tcx, b.substs);
if a_ct.ty != b_ct.ty {
return false;
}
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
use on_unimplemented::InferCtxtExt as _;
use suggestions::InferCtxtExt as _;
let mut span = obligation.cause.span;
let mut err = match *error {
+ SelectionError::Ambiguous(ref impls) => {
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
+ );
+ self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
+ err.emit();
+ return;
+ }
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking.
obligation: &PredicateObligation<'tcx>,
);
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ );
+
fn maybe_suggest_unsized_generics(
&self,
err: &mut DiagnosticBuilder<'tcx>,
}
}
}
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ self.get_parent_trait_ref(&parent_code)
+ }
_ => None,
}
}
?predicate, ?obligation.cause.code,
);
- // Ambiguity errors are often caused as fallout from earlier
- // errors. So just ignore them if this infcx is tainted.
- if self.is_tainted_by_errors() {
- return;
- }
+ // Ambiguity errors are often caused as fallout from earlier errors.
+ // We ignore them if this `infcx` is tainted in some cases below.
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+ if !self.is_tainted_by_errors() {
+ self.emit_inference_failure_err(
+ body_id,
+ span,
+ subst,
+ vec![],
+ ErrorCode::E0282,
+ )
.emit();
+ }
return;
}
+
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
let mut err = self.emit_inference_failure_err(
body_id,
impl_candidates,
ErrorCode::E0283,
);
- err.note(&format!("cannot satisfy `{}`", predicate));
+
+ let obligation = Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ trait_ref.to_poly_trait_predicate(),
+ );
+ let mut selcx = SelectionContext::with_query_mode(
+ &self,
+ crate::traits::TraitQueryMode::Standard,
+ );
+ match selcx.select_from_obligation(&obligation) {
+ Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ }
+ _ => {
+ if self.is_tainted_by_errors() {
+ err.cancel();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ }
+
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
} else if let (
ty::PredicateKind::WellFormed(arg) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
- if arg.references_error() || self.tcx.sess.has_errors() {
+ if arg.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
return;
}
}
ty::PredicateKind::Subtype(data) => {
- if data.references_error() || self.tcx.sess.has_errors() {
+ if data.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
// no need to overload user in such cases
return;
}
ty::PredicateKind::Projection(data) => {
let self_ty = data.projection_ty.self_ty();
let ty = data.ty;
- if predicate.references_error() {
+ if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
if self_ty.needs_infer() && ty.needs_infer() {
}
_ => {
- if self.tcx.sess.has_errors() {
+ if self.tcx.sess.has_errors() || self.is_tainted_by_errors() {
return;
}
let mut err = struct_span_err!(
err.emit();
}
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ ) {
+ let mut spans = vec![];
+ let mut crates = vec![];
+ let mut post = vec![];
+ for def_id in impls {
+ match self.tcx.span_of_impl(*def_id) {
+ Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+ post.push(header);
+ }
+ }
+ }
+ }
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+ crate_names.sort();
+ crate_names.dedup();
+ post.sort();
+ post.dedup();
+
+ if self.is_tainted_by_errors()
+ && crate_names.len() == 1
+ && crate_names[0] == "`core`"
+ && spans.len() == 0
+ {
+ // Avoid complaining about other inference issues for expressions like
+ // `42 >> 1`, where the types are still `{integer}`, but we want to
+ // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+ err.cancel();
+ return;
+ }
+ let post = if post.len() > 4 {
+ format!(
+ ":\n{}\nand {} more",
+ post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
+ post.len() - 4,
+ )
+ } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+ format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
+ } else if post.len() == 1 {
+ format!(": `{}`", post[0])
+ } else {
+ String::new()
+ };
+
+ match (spans.len(), crates.len(), crate_names.len()) {
+ (0, 0, 0) => {
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ (0, _, 1) => {
+ err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ }
+ (0, _, _) => {
+ err.note(&format!(
+ "{} in the following crates: {}{}",
+ msg,
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ (_, 0, 0) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ }
+ (_, 1, 1) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(
+ &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
+ );
+ }
+ _ => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(&format!(
+ "and more `impl`s found in the following crates: {}{}",
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ }
+ }
+
/// Returns `true` if the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
generics,
trait_ref.without_const().to_predicate(tcx).to_string(),
),
- (None, Some((ident, []))) => (
- ident.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (_, Some((_, [.., bounds]))) => (
- bounds.span().shrink_to_hi(),
- format!(" + {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (Some(_), Some((_, []))) => (
- generics.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
+ (None, Some((ident, []))) => {
+ (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+ }
+ (_, Some((_, [.., bounds]))) => {
+ (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
+ }
+ (Some(_), Some((_, []))) => {
+ (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+ }
};
err.span_suggestion_verbose(
let hir = self.tcx.hir();
let parent_node = hir.get_parent_node(obligation.cause.body_id);
let node = hir.find(parent_node);
- let (sig, body_id) = if let Some(hir::Node::Item(hir::Item {
+ let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(sig, _, body_id),
..
})) = node
- {
- (sig, body_id)
- } else {
+ else {
return false;
};
let body = hir.body(*body_id);
while let Some(code) = next_code {
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ next_code = Some(parent_code.as_ref());
+ }
ObligationCauseCode::DerivedObligation(derived_obligation)
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
}
// Only continue if a generator was found.
- debug!(
- "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
- target_ty={:?}",
- generator, trait_ref, target_ty
- );
+ debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
(generator_did, trait_ref, target_ty)
let span = self.tcx.def_span(generator_did);
- // Do not ICE on closure typeck (#66868).
- if !generator_did.is_local() {
- return false;
- }
-
- // Get the typeck results from the infcx if the generator is the function we are
- // currently type-checking; otherwise, get them by performing a query.
- // This is needed to avoid cycles.
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
let generator_did_root = self.tcx.closure_base_def_id(generator_did);
debug!(
in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
span
);
- let query_typeck_results;
- let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
- _ => {
- query_typeck_results = self.tcx.typeck(generator_did.expect_local());
- &query_typeck_results
- }
- };
let generator_body = generator_did
.as_local()
let mut interior_or_upvar_span = None;
let mut interior_extra_info = None;
- if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
- interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
- if ty_matches(ty::Binder::dummy(upvar_ty)) {
- Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
- } else {
- None
- }
- });
+ // Get the typeck results from the infcx if the generator is the function we are currently
+ // type-checking; otherwise, get them by performing a query. This is needed to avoid
+ // cycles. If we can't use resolved types because the generator comes from another crate,
+ // we still provide a targeted error but without all the relevant spans.
+ let query_typeck_results;
+ let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+ _ if generator_did.is_local() => {
+ query_typeck_results = self.tcx.typeck(generator_did.expect_local());
+ Some(&query_typeck_results)
+ }
+ _ => None, // Do not ICE on closure typeck (#66868).
};
+ if let Some(typeck_results) = typeck_results {
+ if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
+ interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ });
+ };
- // The generator interior types share the same binders
- if let Some(cause) =
- typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
- |ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(typeck_results.generator_interior_types.rebind(ty))
- },
- )
- {
- // Check to see if any awaited expressions have the target type.
- let from_awaited_ty = visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- let ty = typeck_results.expr_ty_adjusted(&await_expr);
- debug!(
- "maybe_note_obligation_cause_for_async_await: await_expr={:?}",
- await_expr
- );
- ty_matches(ty::Binder::dummy(ty))
- })
- .map(|expr| expr.span);
- let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
+ // The generator interior types share the same binders
+ if let Some(cause) =
+ typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+ |ty::GeneratorInteriorTypeCause { ty, .. }| {
+ ty_matches(typeck_results.generator_interior_types.rebind(ty))
+ },
+ )
+ {
+ // Check to see if any awaited expressions have the target type.
+ let from_awaited_ty = visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span);
+ let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
+ cause;
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
- interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
- };
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
+ interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
+ };
+ } else {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
- debug!(
- "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
- generator_interior_types={:?}",
- interior_or_upvar_span, typeck_results.generator_interior_types
- );
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
self.note_obligation_cause_for_async_await(
err,
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
) {
// Look at the last interior type to get a span for the `.await`.
debug!(
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
- typeck_results.generator_interior_types
+ typeck_results.as_ref().map(|t| &t.generator_interior_types)
);
explain_yield(interior_span, yield_span, scope_span);
}
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
// ```
//
- let is_region_borrow = typeck_results
- .expr_adjustments(expr)
- .iter()
- .any(|adj| adj.is_region_borrow());
+ let is_region_borrow = if let Some(typeck_results) = typeck_results {
+ typeck_results
+ .expr_adjustments(expr)
+ .iter()
+ .any(|adj| adj.is_region_borrow())
+ } else {
+ false
+ };
// ```rust
// struct Foo(*const u8);
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
_ => false,
};
-
- if (typeck_results.is_method_call(e) && is_region_borrow)
- || is_raw_borrow_inside_fn_like_call
- {
- err.span_help(
- parent_span,
- "consider moving this into a `let` \
+ if let Some(typeck_results) = typeck_results {
+ if (typeck_results.is_method_call(e) && is_region_borrow)
+ || is_raw_borrow_inside_fn_like_call
+ {
+ err.span_help(
+ parent_span,
+ "consider moving this into a `let` \
binding to create a shorter lived borrow",
- );
+ );
+ }
}
}
}
) -> usize {
let (trait_to_be_found, trait_owning_vtable) = key;
+ // #90177
+ let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
let vtable_segment_callback = {
let mut vtable_base = 0;
vtable_base += COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
- if trait_ref == trait_to_be_found {
+ if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
return ControlFlow::Break(vtable_base);
}
vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
- let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
- (u, cu)
- } else {
+ let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
return false;
};
// constants which are not considered const evaluatable.
use rustc_middle::thir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
- const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
- Node::Leaf(leaf) => {
- let leaf = leaf.subst(self.tcx, ct.substs);
- self.visit_const(leaf)
- }
- Node::Cast(_, _, ty) => self.visit_ty(ty),
- Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
- ControlFlow::CONTINUE
+ const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
+ match node.root(self.tcx) {
+ Node::Leaf(leaf) => self.visit_const(leaf),
+ Node::Cast(_, _, ty) => self.visit_ty(ty),
+ Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+ ControlFlow::CONTINUE
+ }
}
})
} else {
) -> Result<Option<Self>, ErrorReported> {
let attrs = tcx.get_attrs(impl_def_id);
- let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) {
- item
- } else {
+ let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
return Ok(None);
};
ty: ret_type,
});
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ confirm_param_env_candidate(selcx, obligation, predicate, true)
}
fn confirm_param_env_candidate<'cx, 'tcx>(
);
let cache_projection = cache_entry.projection_ty;
- let obligation_projection = obligation.predicate;
let mut nested_obligations = Vec::new();
+ let obligation_projection = obligation.predicate;
+ let obligation_projection = ensure_sufficient_stack(|| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_projection,
+ &mut nested_obligations,
+ )
+ });
let cache_projection = if potentially_unnormalized_candidate {
ensure_sufficient_stack(|| {
normalize_with_depth_to(
cache_projection
};
+ debug!(?cache_projection, ?obligation_projection);
+
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: predicate.constness,
+ polarity: predicate.polarity,
})
})
.to_predicate(infcx.tcx),
use crate::traits::coherence::Conflict;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{util, SelectionResult};
-use crate::traits::{ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
use super::BuiltinImplConditions;
use super::IntercrateAmbiguityCause;
return Ok(None);
}
- let mut candidates = candidate_set.vec;
+ let candidates = candidate_set.vec;
debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
// candidate which assumes $0 == int, one that assumes `$0 ==
// usize`, etc. This spells an ambiguity.
+ let mut candidates = self.filter_impls(candidates, stack.obligation);
+
// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// forth). We don't winnow if there is exactly one
// Instead, we select the right impl now but report "`Bar` does
// not implement `Clone`".
if candidates.len() == 1 {
- return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
+ return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
// and report ambiguity.
if i > 1 {
debug!("multiple matches, ambig");
- return Ok(None);
+ return Err(Ambiguous(
+ candidates
+ .into_iter()
+ .filter_map(|c| match c.candidate {
+ SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+ _ => None,
+ })
+ .collect(),
+ ));
}
}
}
}
// Just one candidate left.
- self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
+ self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
#[instrument(skip(self, stack), level = "debug")]
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
-
- // Other bounds. Consider both in-scope bounds from fn decl
- // and applicable impls. There is a certain set of precedence rules here.
- let def_id = obligation.predicate.def_id();
- let lang_items = self.tcx().lang_items();
-
- if lang_items.copy_trait() == Some(def_id) {
- debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
-
- // User-defined copy impls are permitted, but only for
- // structs and enums.
+ // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
+ // There are no compiler built-in rules for this.
+ if obligation.polarity() == ty::ImplPolarity::Negative {
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
-
- // For other types, we'll use the builtin rules.
- let copy_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
- } else if lang_items.discriminant_kind_trait() == Some(def_id) {
- // `DiscriminantKind` is automatically implemented for every type.
- candidates.vec.push(DiscriminantKindCandidate);
- } else if lang_items.pointee_trait() == Some(def_id) {
- // `Pointee` is automatically implemented for every type.
- candidates.vec.push(PointeeCandidate);
- } else if lang_items.sized_trait() == Some(def_id) {
- // Sized is never implementable by end-users, it is
- // always automatically computed.
- let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
- } else if lang_items.unsize_trait() == Some(def_id) {
- self.assemble_candidates_for_unsizing(obligation, &mut candidates);
- } else if lang_items.drop_trait() == Some(def_id)
- && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
- {
- if self.is_in_const_context {
- self.assemble_const_drop_candidates(obligation, &mut candidates)?;
- } else {
- debug!("passing ~const Drop bound; in non-const context");
- // `~const Drop` when we are not in a const context has no effect.
- candidates.vec.push(ConstDropCandidate)
- }
} else {
- if lang_items.clone_trait() == Some(def_id) {
- // Same builtin conditions as `Copy`, i.e., every type which has builtin support
- // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
- // types have builtin support for `Clone`.
- let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
- }
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+
+ // Other bounds. Consider both in-scope bounds from fn decl
+ // and applicable impls. There is a certain set of precedence rules here.
+ let def_id = obligation.predicate.def_id();
+ let lang_items = self.tcx().lang_items();
+
+ if lang_items.copy_trait() == Some(def_id) {
+ debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+ // For other types, we'll use the builtin rules.
+ let copy_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+ } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+ // `DiscriminantKind` is automatically implemented for every type.
+ candidates.vec.push(DiscriminantKindCandidate);
+ } else if lang_items.pointee_trait() == Some(def_id) {
+ // `Pointee` is automatically implemented for every type.
+ candidates.vec.push(PointeeCandidate);
+ } else if lang_items.sized_trait() == Some(def_id) {
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
+ let sized_conditions = self.sized_conditions(obligation);
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
+ } else if lang_items.unsize_trait() == Some(def_id) {
+ self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+ } else if lang_items.drop_trait() == Some(def_id)
+ && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+ {
+ if self.is_in_const_context {
+ self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+ } else {
+ debug!("passing ~const Drop bound; in non-const context");
+ // `~const Drop` when we are not in a const context has no effect.
+ candidates.vec.push(ConstDropCandidate)
+ }
+ } else {
+ if lang_items.clone_trait() == Some(def_id) {
+ // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+ // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+ // types have builtin support for `Clone`.
+ let clone_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+ }
- self.assemble_generator_candidates(obligation, &mut candidates);
- self.assemble_closure_candidates(obligation, &mut candidates);
- self.assemble_fn_pointer_candidates(obligation, &mut candidates);
- self.assemble_candidates_from_impls(obligation, &mut candidates);
- self.assemble_candidates_from_object_ty(obligation, &mut candidates);
- }
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+ }
- self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
- self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
- // Auto implementations have lower priority, so we only
- // consider triggering a default if there is no other impl that can apply.
- if candidates.vec.is_empty() {
- self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+ // Auto implementations have lower priority, so we only
+ // consider triggering a default if there is no other impl that can apply.
+ if candidates.vec.is_empty() {
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ }
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
for bound in matching_bounds {
let wc = self.evaluate_where_clause(stack, bound.value)?;
if wc.may_apply() {
- candidates.vec.push(ParamCandidate(bound));
+ candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
}
}
cause.clone(),
);
- let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() {
- data
- } else {
+ let ty::Dynamic(data, ..) = normalized_ty.kind() else {
return None;
};
substs: self.tcx().mk_substs_trait(ty, &[]),
},
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}));
copy_obligation.recursion_depth = depth + 1;
self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
}
ParamCandidate(param) => {
- let obligations = self.confirm_param_candidate(obligation, param.value);
- Ok(ImplSource::Param(obligations, param.constness))
+ let obligations = self.confirm_param_candidate(obligation, param.0.value);
+ Ok(ImplSource::Param(obligations, param.0.constness))
}
ImplCandidate(impl_def_id) => {
_ => bug!("closure candidate for non-closure {:?}", obligation),
};
+ let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+ let Normalized { value: obligation_predicate, mut obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_predicate,
+ )
+ });
+
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
- let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
- normalize_with_depth(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- trait_ref,
- )
- });
+ let Normalized { value: trait_ref, obligations: trait_ref_obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ trait_ref,
+ )
+ });
debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
+ obligations.extend(trait_ref_obligations);
obligations.extend(self.confirm_poly_trait_refs(
obligation.cause.clone(),
obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
+ obligation_predicate,
trait_ref,
)?);
let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty();
- if tcx.features().relaxed_struct_unsize {
- for arg in tail_field_ty.walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- }
- }
-
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.remove(i);
- }
- }
+ for arg in tail_field_ty.walk(tcx) {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.insert(i);
}
+ }
- if unsizing_params.is_empty() {
- return Err(Unimplemented);
- }
- } else {
- let mut found = false;
- for arg in tail_field_ty.walk(tcx) {
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- found = true;
+ unsizing_params.remove(i);
}
}
- if !found {
- return Err(Unimplemented);
- }
+ }
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- // FIXME(eddyb) cache this (including computing `unsizing_params`)
- // by putting it in a query; it would only need the `DefId` as it
- // looks at declared field types, not anything substituted.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- if unsizing_params.contains(i) {
- return Err(Unimplemented);
- }
- }
- }
- }
+ if unsizing_params.is_empty() {
+ return Err(Unimplemented);
}
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
use super::Selection;
use super::SelectionResult;
use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
&mut self,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
- debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
- let pec = &ProvisionalEvaluationCache::default();
- let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
- let candidate = match self.candidate_from_obligation(&stack) {
+ let candidate = match self.select_from_obligation(obligation) {
Err(SelectionError::Overflow) => {
// In standard mode, overflow must have been caught and reported
// earlier.
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow);
}
+ Err(SelectionError::Ambiguous(_)) => {
+ return Ok(None);
+ }
Err(e) => {
return Err(e);
}
}
}
+ crate fn select_from_obligation(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+ let pec = &ProvisionalEvaluationCache::default();
+ let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+ self.candidate_from_obligation(&stack)
+ }
+
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
debug!(?fresh_trait_ref);
- if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
+ if let Some(result) = self.check_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ ) {
debug!(?result, "CACHE HIT");
return Ok(result);
}
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
debug!(?result, "CACHE MISS");
- self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+ self.insert_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ dep_node,
+ result,
+ );
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
self.insert_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
+ obligation.polarity(),
dep_node,
provisional_result.max(result),
);
// precise still.
let unbound_input_types =
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
- // This check was an imperfect workaround for a bug in the old
- // intercrate mode; it should be removed when that goes away.
- if unbound_input_types && self.intercrate {
- debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
- // Heuristics: show the diagnostics when there are no candidates in crate.
- if self.intercrate_ambiguity_causes.is_some() {
- debug!("evaluate_stack: intercrate_ambiguity_causes is some");
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause =
- with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.print_only_trait_path().to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
+
+ if stack.obligation.polarity() != ty::ImplPolarity::Negative {
+ // This check was an imperfect workaround for a bug in the old
+ // intercrate mode; it should be removed when that goes away.
+ if unbound_input_types && self.intercrate {
+ debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = with_no_trimmed_paths(|| {
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.print_only_trait_path().to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ }
});
- debug!(?cause, "evaluate_stack: pushing cause");
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ debug!(?cause, "evaluate_stack: pushing cause");
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
}
+ return Ok(EvaluatedToAmbig);
}
- return Ok(EvaluatedToAmbig);
}
+
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+ Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
&self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
+ if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+ {
return Some(res);
}
}
- self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx)
+ self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
- self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.tcx().evaluation_cache.insert(
+ (param_env.and(trait_ref), polarity),
+ dep_node,
+ result,
+ );
return;
}
}
debug!(?trait_ref, ?result, "insert_evaluation_cache");
- self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
(result, dep_node)
}
+ /// filter_impls filters constant trait obligations and candidates that have a positive impl
+ /// for a negative goal and a negative impl for a positive goal
#[instrument(level = "debug", skip(self))]
fn filter_impls(
&mut self,
- candidate: SelectionCandidate<'tcx>,
+ candidates: Vec<SelectionCandidate<'tcx>>,
obligation: &TraitObligation<'tcx>,
- ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ ) -> Vec<SelectionCandidate<'tcx>> {
let tcx = self.tcx();
- // Respect const trait obligations
- if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
- match candidate {
- // const impl
- ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
- // const param
- ParamCandidate(ty::ConstnessAnd {
- constness: ty::BoundConstness::ConstIfConst,
- ..
- }) => {}
- // auto trait impl
- AutoImplCandidate(..) => {}
- // generator, this will raise error in other places
- // or ignore error with const_async_blocks feature
- GeneratorCandidate => {}
- // FnDef where the function is const
- FnPointerCandidate { is_const: true } => {}
- ConstDropCandidate => {}
- _ => {
- // reject all other types of candidates
- return Err(Unimplemented);
+ let mut result = Vec::with_capacity(candidates.len());
+
+ for candidate in candidates {
+ // Respect const trait obligations
+ if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id)
+ if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate((
+ ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+ _,
+ )) => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ // FnDef where the function is const
+ FnPointerCandidate { is_const: true } => {}
+ ConstDropCandidate => {}
+ _ => {
+ // reject all other types of candidates
+ continue;
+ }
}
}
+
+ if let ImplCandidate(def_id) = candidate {
+ if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+ || obligation.polarity() == tcx.impl_polarity(def_id)
+ || self.allow_negative_impls
+ {
+ result.push(candidate);
+ }
+ } else {
+ result.push(candidate);
+ }
}
- // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+
+ result
+ }
+
+ /// filter_reservation_impls filter reservation impl for any goal as ambiguous
+ #[instrument(level = "debug", skip(self))]
+ fn filter_reservation_impls(
+ &mut self,
+ candidate: SelectionCandidate<'tcx>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ // Treat reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
- match tcx.impl_polarity(def_id) {
- ty::ImplPolarity::Negative if !self.allow_negative_impls => {
- return Err(Unimplemented);
- }
- ty::ImplPolarity::Reservation => {
- if let Some(intercrate_ambiguity_clauses) =
- &mut self.intercrate_ambiguity_causes
- {
- let attrs = tcx.get_attrs(def_id);
- let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
- let value = attr.and_then(|a| a.value_str());
- if let Some(value) = value {
- debug!(
- "filter_impls: \
+ if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
+ if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+ let attrs = tcx.get_attrs(def_id);
+ let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
+ let value = attr.and_then(|a| a.value_str());
+ if let Some(value) = value {
+ debug!(
+ "filter_reservation_impls: \
reservation impl ambiguity on {:?}",
- def_id
- );
- intercrate_ambiguity_clauses.push(
- IntercrateAmbiguityCause::ReservationImpl {
- message: value.to_string(),
- },
- );
- }
+ def_id
+ );
+ intercrate_ambiguity_clauses.push(
+ IntercrateAmbiguityCause::ReservationImpl {
+ message: value.to_string(),
+ },
+ );
}
- return Ok(None);
}
- _ => {}
- };
+ return Ok(None);
+ }
}
Ok(Some(candidate))
}
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
- if !self.intercrate {
+ if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
return None;
}
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
return Some(res);
}
}
self.infcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
}
/// Determines whether can we safely cache the result
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global =
- |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
+ let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
+ cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+ };
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else.
| ConstDropCandidate,
) => false,
- (ParamCandidate(other), ParamCandidate(victim)) => {
+ (
+ ParamCandidate((other, other_polarity)),
+ ParamCandidate((victim, victim_polarity)),
+ ) => {
let same_except_bound_vars = other.value.skip_binder()
== victim.value.skip_binder()
&& other.constness == victim.constness
+ && other_polarity == victim_polarity
&& !other.value.skip_binder().has_escaping_bound_vars();
if same_except_bound_vars {
// See issue #84398. In short, we can generate multiple ParamCandidates which are
other.value.bound_vars().len() <= victim.value.bound_vars().len()
} else if other.value == victim.value
&& victim.constness == ty::BoundConstness::NotConst
+ && other_polarity == victim_polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
- ) => !is_global(&cand.value),
+ ) => !is_global(&cand.0.value),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value)
+ is_global(&cand.0.value)
}
(
ImplCandidate(_)
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
+ is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
/// string.
-fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
use std::fmt::Write;
let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
Dynamic,
Foreign,
Opaque,
+ Closure,
Generator,
Projection,
}
ty::Projection(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Projection);
}
+ ty::Closure(..) => {
+ return ControlFlow::Break(NonStructuralMatchTy::Closure);
+ }
ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Generator);
}
// First check all contained types and then tell the caller to continue searching.
return ty.super_visit_with(self);
}
- ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+ ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
ty::Error(_) => {
type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- let adt_components =
- move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
-
// If we don't know a type doesn't need drop, for example if it's a type
// parameter without a `Copy` bound, then we conservatively return that it
// needs drop.
- let res =
- NeedsDropTypes::new(tcx, query.param_env, query.value, adt_components).next().is_some();
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+ let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
debug!("needs_drop_raw({:?}) = {:?}", query, res);
res
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
- tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
- };
- let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
- .next()
- .is_some();
+ let res =
+ drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
+ .next()
+ .is_some();
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
res
}
Ok(tys) => tys,
};
for required_ty in tys {
- let subst_ty = tcx.normalize_erasing_regions(
- self.param_env,
- required_ty.subst(tcx, substs),
- );
+ let subst_ty =
+ tcx.normalize_erasing_regions(self.param_env, required_ty);
queue_type(self, subst_ty);
}
}
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
// ADT has a destructor or if the ADT only has a significant destructor. For
// understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper<'tcx>(
+fn drop_tys_helper<'tcx>(
tcx: TyCtxt<'tcx>,
- def_id: DefId,
+ ty: Ty<'tcx>,
+ param_env: rustc_middle::ty::ParamEnv<'tcx>,
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
-) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
- debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
+ debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
} else if let Some(dtor_info) = adt_has_dtor(adt_def) {
match dtor_info {
DtorType::Significant => {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
return Err(AlwaysRequiresDrop);
}
DtorType::Insignificant => {
- debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+ debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
}
}
} else if adt_def.is_union() {
- debug!("adt_drop_tys: `{:?}` is a union", adt_def);
+ debug!("drop_tys_helper: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
}
- Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
+ Ok(adt_def
+ .all_fields()
+ .map(|field| {
+ let r = tcx.type_of(field.did).subst(tcx, substs);
+ debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
+ r
+ })
+ .collect::<Vec<_>>()
+ .into_iter())
};
- let adt_ty = tcx.type_of(def_id);
- let param_env = tcx.param_env(def_id);
- let res: Result<Vec<_>, _> =
- NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
-
- debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
- res.map(|components| tcx.intern_type_list(&components))
+ NeedsDropTypes::new(tcx, param_env, ty, adt_components)
}
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
- // significant.
- let adt_has_dtor =
- |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
- adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
-}
-
-fn adt_significant_drop_tys(
- tcx: TyCtxt<'_>,
- def_id: DefId,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_has_dtor = |adt_def: &ty::AdtDef| {
+fn adt_consider_insignificant_dtor<'tcx>(
+ tcx: TyCtxt<'tcx>,
+) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
+ move |adt_def: &ty::AdtDef| {
let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
if is_marked_insig {
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
// treat this as the simple case of Drop impl for type.
None
}
- };
- adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
+ }
+}
+
+fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+ // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
+ // significant.
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+ drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
+ .collect::<Result<Vec<_>, _>>()
+ .map(|components| tcx.intern_type_list(&components))
+}
+
+fn adt_significant_drop_tys(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+ drop_tys_helper(
+ tcx,
+ tcx.type_of(def_id),
+ tcx.param_env(def_id),
+ adt_consider_insignificant_dtor(tcx),
+ )
+ .collect::<Result<Vec<_>, _>>()
+ .map(|components| tcx.intern_type_list(&components))
}
pub(crate) fn provide(providers: &mut ty::query::Providers) {
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
}
/// See `ParamEnv` struct definition for details.
+#[instrument(level = "debug", skip(tcx))]
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// The param_env of an impl Trait type is its defining function's param_env
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
predicates.extend(environment);
}
+ // It's important that we include the default substs in unevaluated
+ // constants, since `Unevaluated` instances in predicates whose substs are None
+ // can lead to "duplicate" caller bounds candidates during trait selection,
+ // duplicate in the sense that both have their default substs, but the
+ // candidate that resulted from a superpredicate still uses `None` in its
+ // `substs_` field of `Unevaluated` to indicate that it has its default substs,
+ // whereas the other candidate has `substs_: Some(default_substs)`, see
+ // issue #89334
+ predicates = tcx.expose_default_const_substs(predicates);
+
let unnormalized_env =
ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
+ debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
let body_id = def_id
.as_local()
.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
let node = tcx.hir().get(hir_id);
- let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
+ let fn_kind = node.fn_kind().unwrap_or_else(|| {
bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
});
- fn_like.asyncness()
+ fn_kind.asyncness()
}
/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
"reorder the arguments: {}: `<{}>`",
param_types_present
.into_iter()
- .map(|ord| format!("{}s", ord.to_string()))
+ .map(|ord| format!("{}s", ord))
.collect::<Vec<String>>()
.join(", then "),
ordered_params
debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
- let self_ty = if let Some(ty) = opt_self_ty {
- ty
- } else {
+ let Some(self_ty) = opt_self_ty else {
let path_str = tcx.def_path_str(trait_def_id);
let def_id = self.item_def_id();
})
});
- self.region_bounds
- .iter()
- .map(|&(region_bound, span)| {
+ sized_predicate
+ .into_iter()
+ .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
(
region_bound
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
.to_predicate(tcx),
span,
)
- })
+ }))
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span)
.iter()
.map(|&(projection, span)| (projection.to_predicate(tcx), span)),
)
- .chain(sized_predicate.into_iter())
.collect()
}
}
use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
use rustc_span::{MultiSpan, Span};
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
},
constness: t.constness,
+ polarity: t.polarity,
}));
let obl = Obligation::new(
o.cause.clone(),
let end = callee_span.shrink_to_hi();
err.multipart_suggestion(
"if you meant to create this closure and immediately call it, surround the \
- closure with parenthesis",
+ closure with parentheses",
vec![(start, "(".to_string()), (end, ")".to_string())],
Applicability::MaybeIncorrect,
);
call_expr.span,
&format!(
"`{}` is a unit variant, you need to write it \
- without the parenthesis",
+ without the parentheses",
path
),
path.to_string(),
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_ty_utils::representability::{self, Representability};
debug!("coerce: unsize not object safe");
return Err(TypeError::ObjectUnsafeCoercion(did));
}
- Err(_) => {}
+ Err(error) => {
+ debug!(?error, "coerce: unsize failed");
+ }
}
- debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
match *b.kind() {
let traits =
(self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
- let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
- (u, cu)
- } else {
+ let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {
debug!("missing Unsize or CoerceUnsized traits");
return Err(TypeError::Mismatch);
};
return false;
}
- let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
- src
- } else {
+ let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else {
return false;
};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+ final_arg_types.push((i, checked_ty, coerce_ty));
+
// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This is otherwise redundant with the `demand_coerce`
// call immediately after, but it lets us customize the span pointed to in the
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
coerce_ty,
|errors| {
- // This is not coming from a macro or a `derive`.
- if sp.desugaring_kind().is_none()
- && !arg.span.from_expansion()
- // Do not change the spans of `async fn`s.
- && !matches!(
- expr.kind,
- hir::ExprKind::Call(
- hir::Expr {
- kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
- ..
- },
- _
- )
- ) {
- for error in errors {
- error.obligation.cause.make_mut().span = arg.span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: arg.hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
- }
- }
+ self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+ self.point_at_arg_instead_of_call_if_possible(
+ errors,
+ &final_arg_types,
+ expr,
+ sp,
+ args,
+ );
},
);
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
- final_arg_types.push((i, checked_ty, coerce_ty));
// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
continue;
}
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
- {
- // Collect the argument position for all arguments that could have caused this
- // `FulfillmentError`.
- let mut referenced_in = final_arg_types
- .iter()
- .map(|&(i, checked_ty, _)| (i, checked_ty))
- .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
- .flat_map(|(i, ty)| {
- let ty = self.resolve_vars_if_possible(ty);
- // We walk the argument type because the argument's type could have
- // been `Option<T>`, but the `FulfillmentError` references `T`.
- if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) {
- Some(i)
- } else {
- None
- }
- })
- .collect::<Vec<usize>>();
-
- // Both checked and coerced types could have matched, thus we need to remove
- // duplicates.
-
- // We sort primitive type usize here and can use unstable sort
- referenced_in.sort_unstable();
- referenced_in.dedup();
-
- if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
- // We make sure that only *one* argument matches the obligation failure
- // and we assign the obligation's span to its expression's.
- error.obligation.cause.make_mut().span = args[ref_in].span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: args[ref_in].hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
+ // Peel derived obligation, because it's the type that originally
+ // started this inference chain that matters, not the one we wound
+ // up with at the end.
+ fn unpeel_to_top(
+ mut code: Lrc<ObligationCauseCode<'_>>,
+ ) -> Lrc<ObligationCauseCode<'_>> {
+ let mut result_code = code.clone();
+ loop {
+ let parent = match &*code {
+ ObligationCauseCode::BuiltinDerivedObligation(c)
+ | ObligationCauseCode::ImplDerivedObligation(c)
+ | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
+ _ => break,
+ };
+ result_code = std::mem::replace(&mut code, parent);
+ }
+ result_code
+ }
+ let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) {
+ ObligationCauseCode::BuiltinDerivedObligation(code) |
+ ObligationCauseCode::ImplDerivedObligation(code) |
+ ObligationCauseCode::DerivedObligation(code) => {
+ code.parent_trait_ref.self_ty().skip_binder().into()
+ }
+ _ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder() => {
+ predicate.self_ty().into()
+ }
+ _ => continue,
+ };
+ let self_ = self.resolve_vars_if_possible(self_);
+
+ // Collect the argument position for all arguments that could have caused this
+ // `FulfillmentError`.
+ let mut referenced_in = final_arg_types
+ .iter()
+ .map(|&(i, checked_ty, _)| (i, checked_ty))
+ .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+ .flat_map(|(i, ty)| {
+ let ty = self.resolve_vars_if_possible(ty);
+ // We walk the argument type because the argument's type could have
+ // been `Option<T>`, but the `FulfillmentError` references `T`.
+ if ty.walk(self.tcx).any(|arg| arg == self_) { Some(i) } else { None }
+ })
+ .collect::<Vec<usize>>();
+
+ // Both checked and coerced types could have matched, thus we need to remove
+ // duplicates.
+
+ // We sort primitive type usize here and can use unstable sort
+ referenced_in.sort_unstable();
+ referenced_in.dedup();
+
+ if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+ // Do not point at the inside of a macro.
+ // That would often result in poor error messages.
+ if args[ref_in].span.from_expansion() {
+ return;
+ }
+ // We make sure that only *one* argument matches the obligation failure
+ // and we assign the obligation's span to its expression's.
+ error.obligation.cause.make_mut().span = args[ref_in].span;
+ let code = error.obligation.cause.code.clone();
+ error.obligation.cause.make_mut().code =
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id: args[ref_in].hir_id,
+ call_hir_id: expr.hir_id,
+ parent_code: Lrc::new(code),
+ };
+ } else if error.obligation.cause.make_mut().span == call_sp {
+ // Make function calls point at the callee, not the whole thing.
+ if let hir::ExprKind::Call(callee, _) = expr.kind {
+ error.obligation.cause.make_mut().span = callee.span;
}
}
}
..
},
method,
- )) if Some(recv_ty.def_id()) == pin_did && method.ident.name == sym::new => {
+ )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
err.span_suggestion(
fn_name.span,
"use `Box::pin` to pin and box this expression",
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{FulfillmentError, Obligation};
let mut candidates = valid_out_of_scope_traits;
candidates.sort();
candidates.dedup();
+
+ // `TryFrom` and `FromIterator` have no methods
+ let edition_fix = candidates
+ .iter()
+ .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+ .map(|&d| d);
+
err.help("items from traits can only be used if the trait is in scope");
let msg = format!(
"the following {traits_are} implemented but not in scope; \
);
self.suggest_use_candidates(err, msg, candidates);
+ if let Some(did) = edition_fix {
+ err.note(&format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ with_crate_prefix(|| self.tcx.def_path_str(did))
+ ));
+ }
+
true
} else {
false
self.tcx.lang_items().deref_trait(),
self.tcx.lang_items().deref_mut_trait(),
self.tcx.lang_items().drop_trait(),
+ self.tcx.get_diagnostic_item(sym::AsRef),
];
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
- let skip = skippable.contains(&did);
+ // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
+ // implement the `AsRef` trait.
+ let skip = skippable.contains(&did)
+ || (("Pin::new" == *pre)
+ && (Symbol::intern("as_ref") == item_name.name));
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
other_ty: Ty<'tcx>,
op: hir::BinOp,
is_assign: IsAssign,
- ) -> bool /* did we suggest to call a function because of missing parenthesis? */ {
+ ) -> bool /* did we suggest to call a function because of missing parentheses? */ {
err.span_label(span, ty.to_string());
if let FnDef(def_id, _) = *ty.kind() {
let source_map = self.tcx.sess.source_map();
// FIXME: Instead of exiting early when encountering bound vars in
// the function signature, consider keeping the binder here and
// propagating it downwards.
- let fn_sig = if let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() {
- fn_sig
- } else {
+ let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else {
return false;
};
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
// Resolve the path and check the definition for errors.
- let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id)
- {
- variant_ty
- } else {
+ let Some((variant, pat_ty)) = self.check_struct_path(qpath, pat.hir_id) else {
let err = self.tcx.ty_error();
for field in fields {
let ti = TopInfo { parent_pat: Some(pat), ..ti };
debug!("convert_place_op_to_mutable: method={:?}", method);
self.write_method_call(expr.hir_id, method);
- let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() {
- r
- } else {
+ let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else {
span_bug!(expr.span, "input to mutable place op is not a mut ref?");
};
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use std::ops::Deref;
// a variation on try that just returns unit
self.link_fn_params(body.params);
self.visit_body(body);
self.visit_region_obligations(body_id.hir_id);
-
- self.constrain_opaque_types(self.outlives_environment.free_region_map());
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
/// Intermediate format to store the hir_id pointing to the use that resulted in the
/// corresponding place being captured and a String which contains the captured value's
/// name (i.e: a.b.c)
-type CapturesInfo = (Option<hir::HirId>, String);
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+enum UpvarMigrationInfo {
+ /// We previously captured all of `x`, but now we capture some sub-path.
+ CapturingPrecise { source_expr: Option<hir::HirId>, var_name: String },
+ CapturingNothing {
+ // where the variable appears in the closure (but is not captured)
+ use_span: Span,
+ },
+}
+
+/// Reasons that we might issue a migration warning.
+#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct MigrationWarningReason {
+ /// When we used to capture `x` in its entirety, we implemented the auto-trait(s)
+ /// in this vec, but now we don't.
+ auto_traits: Vec<&'static str>,
+
+ /// When we used to capture `x` in its entirety, we would execute some destructors
+ /// at a different time.
+ drop_order: bool,
+}
+
+impl MigrationWarningReason {
+ fn migration_message(&self) -> String {
+ let base = "changes to closure capture in Rust 2021 will affect";
+ if !self.auto_traits.is_empty() && self.drop_order {
+ format!("{} drop order and which traits the closure implements", base)
+ } else if self.drop_order {
+ format!("{} drop order", base)
+ } else {
+ format!("{} which traits the closure implements", base)
+ }
+ }
+}
+
+/// Intermediate format to store information needed to generate a note in the migration lint.
+struct MigrationLintNote {
+ captures_info: UpvarMigrationInfo,
-/// Intermediate format to store information needed to generate migration lint. The tuple
-/// contains the hir_id pointing to the use that resulted in the
-/// corresponding place being captured, a String which contains the captured value's
-/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that
-/// capture
-type MigrationNeededForCapture = (Option<hir::HirId>, String, String);
+ /// reasons why migration is needed for this capture
+ reason: MigrationWarningReason,
+}
/// Intermediate format to store the hir id of the root variable and a HashSet containing
/// information on why the root variable should be fully captured
-type MigrationDiagnosticInfo = (hir::HirId, Vec<MigrationNeededForCapture>);
+struct NeededMigration {
+ var_hir_id: hir::HirId,
+ diagnostics_info: Vec<MigrationLintNote>,
+}
struct InferBorrowKindVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
closure_head_span,
|lint| {
let mut diagnostics_builder = lint.build(
- format!(
- "changes to closure capture in Rust 2021 will affect {}",
- reasons
- )
- .as_str(),
+ &reasons.migration_message(),
);
- for (var_hir_id, diagnostics_info) in need_migrations.iter() {
+ for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible
// for migration being needed
- for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() {
- if let Some(captured_hir_id) = captured_hir_id {
- let cause_span = self.tcx.hir().span(*captured_hir_id);
- diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
- self.tcx.hir().name(*var_hir_id),
- captured_name,
- ));
+ for lint_note in diagnostics_info.iter() {
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
+ let cause_span = self.tcx.hir().span(*capture_expr_id);
+ diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+ self.tcx.hir().name(*var_hir_id),
+ captured_name,
+ ));
+ }
+ UpvarMigrationInfo::CapturingNothing { use_span } => {
+ diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+ self.tcx.hir().name(*var_hir_id),
+ ));
+ }
+
+ _ => { }
}
// Add a label pointing to where a captured variable affected by drop order
// is dropped
- if reasons.contains("drop order") {
+ if lint_note.reason.drop_order {
let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
- self.tcx.hir().name(*var_hir_id),
- captured_name,
- ));
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+ diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+ self.tcx.hir().name(*var_hir_id),
+ captured_name,
+ ));
+ }
+ UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
+ diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+ v = self.tcx.hir().name(*var_hir_id),
+ ));
+ }
+ }
}
// Add a label explaining why a closure no longer implements a trait
- if reasons.contains("trait implementation") {
- let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1];
-
- diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}",
- missing_trait,
- self.tcx.hir().name(*var_hir_id),
- missing_trait,
- missing_trait,
- captured_name,
- missing_trait,
- ));
+ for &missing_trait in &lint_note.reason.auto_traits {
+ // not capturing something anymore cannot cause a trait to fail to be implemented:
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+ let var_name = self.tcx.hir().name(*var_hir_id);
+ diagnostics_builder.span_label(closure_head_span, format!("\
+ in Rust 2018, this closure implements {missing_trait} \
+ as `{var_name}` implements {missing_trait}, but in Rust 2021, \
+ this closure will no longer implement {missing_trait} \
+ because `{var_name}` is not fully captured \
+ and `{captured_name}` does not implement {missing_trait}"));
+ }
+
+ // Cannot happen: if we don't capture a variable, we impl strictly more traits
+ UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"),
+ }
}
}
}
/// Combines all the reasons for 2229 migrations
fn compute_2229_migrations_reasons(
&self,
- auto_trait_reasons: FxHashSet<&str>,
- drop_reason: bool,
- ) -> String {
- let mut reasons = String::new();
-
- if !auto_trait_reasons.is_empty() {
- reasons = format!(
- "{} trait implementation for closure",
- auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ")
- );
- }
+ auto_trait_reasons: FxHashSet<&'static str>,
+ drop_order: bool,
+ ) -> MigrationWarningReason {
+ let mut reasons = MigrationWarningReason::default();
- if !auto_trait_reasons.is_empty() && drop_reason {
- reasons = format!("{} and ", reasons);
+ for auto_trait in auto_trait_reasons {
+ reasons.auto_traits.push(auto_trait);
}
- if drop_reason {
- reasons = format!("{}drop order", reasons);
- }
+ reasons.drop_order = drop_order;
reasons
}
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
var_hir_id: hir::HirId,
closure_clause: hir::CaptureBy,
- ) -> Option<FxHashMap<CapturesInfo, FxHashSet<&str>>> {
+ ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> {
let auto_traits_def_id = vec![
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().sync_trait(),
self.tcx.get_diagnostic_item(sym::unwind_safe_trait),
self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait),
];
- let auto_traits =
- vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
+ const AUTO_TRAITS: [&str; 6] =
+ ["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
// by the root variable but not by the capture
for (idx, _) in obligations_should_hold.iter().enumerate() {
if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] {
- capture_problems.insert(auto_traits[idx]);
+ capture_problems.insert(AUTO_TRAITS[idx]);
}
}
if !capture_problems.is_empty() {
problematic_captures.insert(
- (capture.info.path_expr_id, capture.to_string(self.tcx)),
+ UpvarMigrationInfo::CapturingPrecise {
+ source_expr: capture.info.path_expr_id,
+ var_name: capture.to_string(self.tcx),
+ },
capture_problems,
);
}
///
/// This function only returns a HashSet of CapturesInfo for significant drops. If there
/// are no significant drops than None is returned
+ #[instrument(level = "debug", skip(self))]
fn compute_2229_migrations_for_drop(
&self,
closure_def_id: DefId,
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
closure_clause: hir::CaptureBy,
var_hir_id: hir::HirId,
- ) -> Option<FxHashSet<CapturesInfo>> {
+ ) -> Option<FxHashSet<UpvarMigrationInfo>> {
let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+ debug!("does not have significant drop");
return None;
}
- let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
- min_captures.and_then(|m| m.get(&var_hir_id))
- {
- root_var_min_capture_list
- } else {
+ let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else {
// The upvar is mentioned within the closure but no path starting from it is
- // used.
+ // used. This occurs when you have (e.g.)
+ //
+ // ```
+ // let x = move || {
+ // let _ = y;
+ // });
+ // ```
+ debug!("no path starting from it is used");
+
match closure_clause {
// Only migrate if closure is a move closure
- hir::CaptureBy::Value => return Some(FxHashSet::default()),
+ hir::CaptureBy::Value => {
+ let mut diagnostics_info = FxHashSet::default();
+ let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
+ let upvar = upvars[&var_hir_id];
+ diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
+ return Some(diagnostics_info);
+ }
hir::CaptureBy::Ref => {}
}
return None;
};
+ debug!(?root_var_min_capture_list);
let mut projections_list = Vec::new();
let mut diagnostics_info = FxHashSet::default();
// Only care about captures that are moved into the closure
ty::UpvarCapture::ByValue(..) => {
projections_list.push(captured_place.place.projections.as_slice());
- diagnostics_info.insert((
- captured_place.info.path_expr_id,
- captured_place.to_string(self.tcx),
- ));
+ diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
+ source_expr: captured_place.info.path_expr_id,
+ var_name: captured_place.to_string(self.tcx),
+ });
}
ty::UpvarCapture::ByRef(..) => {}
}
}
+ debug!(?projections_list);
+ debug!(?diagnostics_info);
+
let is_moved = !projections_list.is_empty();
+ debug!(?is_moved);
let is_not_completely_captured =
root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty());
+ debug!(?is_not_completely_captured);
if is_moved
&& is_not_completely_captured
/// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String
/// containing the reason why root variables whose HirId is contained in the vector should
/// be captured
+ #[instrument(level = "debug", skip(self))]
fn compute_2229_migrations(
&self,
closure_def_id: DefId,
closure_span: Span,
closure_clause: hir::CaptureBy,
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
- ) -> (Vec<MigrationDiagnosticInfo>, String) {
- let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
- upvars
- } else {
- return (Vec::new(), format!(""));
+ ) -> (Vec<NeededMigration>, MigrationWarningReason) {
+ let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else {
+ return (Vec::new(), MigrationWarningReason::default());
};
let mut need_migrations = Vec::new();
// Perform auto-trait analysis
for (&var_hir_id, _) in upvars.iter() {
- let mut responsible_captured_hir_ids = Vec::new();
+ let mut diagnostics_info = Vec::new();
let auto_trait_diagnostic = if let Some(diagnostics_info) =
self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
let mut capture_diagnostic = capture_diagnostic.into_iter().collect::<Vec<_>>();
capture_diagnostic.sort();
- for captured_info in capture_diagnostic.iter() {
+ for captures_info in capture_diagnostic {
// Get the auto trait reasons of why migration is needed because of that capture, if there are any
let capture_trait_reasons =
- if let Some(reasons) = auto_trait_diagnostic.get(captured_info) {
+ if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) {
reasons.clone()
} else {
FxHashSet::default()
};
// Check if migration is needed because of drop reorder as a result of that capture
- let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info);
+ let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info);
// Combine all the reasons of why the root variable should be captured as a result of
// auto trait implementation issues
auto_trait_migration_reasons.extend(capture_trait_reasons.clone());
- responsible_captured_hir_ids.push((
- captured_info.0,
- captured_info.1.clone(),
- self.compute_2229_migrations_reasons(
+ diagnostics_info.push(MigrationLintNote {
+ captures_info,
+ reason: self.compute_2229_migrations_reasons(
capture_trait_reasons,
capture_drop_reorder_reason,
),
- ));
+ });
}
- if !capture_diagnostic.is_empty() {
- need_migrations.push((var_hir_id, responsible_captured_hir_ids));
+ if !diagnostics_info.is_empty() {
+ need_migrations.push(NeededMigration { var_hir_id, diagnostics_info });
}
}
(
diag_expr_id: hir::HirId,
) {
let tcx = self.fcx.tcx;
- let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
- upvar_id
- } else {
+ let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
return;
};
tcx.hir().name(var_hir_id)
}
+#[instrument(level = "debug", skip(tcx))]
fn should_do_rust_2021_incompatible_closure_captures_analysis(
tcx: TyCtxt<'_>,
closure_id: hir::HirId,
/// - s2: Comma separated names of the variables being migrated.
fn migration_suggestion_for_2229(
tcx: TyCtxt<'_>,
- need_migrations: &Vec<MigrationDiagnosticInfo>,
+ need_migrations: &Vec<NeededMigration>,
) -> (String, String) {
- let need_migrations_variables =
- need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::<Vec<_>>();
+ let need_migrations_variables = need_migrations
+ .iter()
+ .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v))
+ .collect::<Vec<_>>();
let migration_ref_concat =
need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", ");
for item in list.iter() {
if item.has_name(sym::address) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+ } else if item.has_name(sym::cfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::memory) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::thread) {
// Getting this wrong can lead to ICE and unsoundness, so we assert it here.
for arg in substs.iter() {
let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
- | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE
+ | ty::TypeFlags::HAS_ERROR;
assert!(!arg.has_type_flags(!allowed_flags));
}
substs
} else {
err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
} else {
diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
ty::PredicateKind::Trait(_)
| ty::PredicateKind::RegionOutlives(_)
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(min_specialization)]
#![feature(nll)]
#![feature(try_blocks)]
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance_i)
}
}
}
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
}
- ty::Array(typ, _) => {
+ ty::Array(typ, len) => {
+ self.add_constraints_from_const(current, len, variance);
self.add_constraints_from_ty(current, typ, variance);
}
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance)
}
}
}
}
+ /// Adds constraints appropriate for a const expression `val`
+ /// in a context with ambient variance `variance`
+ fn add_constraints_from_const(
+ &mut self,
+ current: &CurrentItem,
+ val: &ty::Const<'tcx>,
+ variance: VarianceTermPtr<'a>,
+ ) {
+ debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+
+ match &val.val {
+ ty::ConstKind::Unevaluated(uv) => {
+ let substs = uv.substs(self.tcx());
+ self.add_constraints_from_invariant_substs(current, substs, variance);
+ }
+ _ => {}
+ }
+ }
+
/// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance`
fn add_constraints_from_sig(
# Indicates whether the LLVM assertions are enabled or not
#assertions = false
+# Indicates whether the LLVM testsuite is enabled in the build or not. Does
+# not execute the tests as part of the build as part of x.py build et al,
+# just makes it possible to do `ninja check-llvm` in the staged LLVM build
+# directory when doing LLVM development as part of Rust development.
+#tests = false
+
# Indicates whether the LLVM plugin is enabled or not
#plugins = false
# Enable symbol-mangling-version v0. This can be helpful when profiling rustc,
# as generics will be preserved in symbols (rather than erased into opaque T).
-#new-symbol-mangling = false
+# When no setting is given, the new scheme will be used when compiling the
+# compiler and its tools and the legacy scheme will be used when compiling the
+# standard library.
+# If an explicit setting is given, it will be used for all parts of the codebase.
+#new-symbol-mangling = true|false (see comment)
# =============================================================================
# Options for specific targets
let mut c = 0;
for i in 0..BENCH_RANGE_SIZE {
for j in i + 1..BENCH_RANGE_SIZE {
- black_box(map.range(f(i, j)));
+ let _ = black_box(map.range(f(i, j)));
c += 1;
}
}
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
b.iter(|| {
for _ in 0..repeats {
- black_box(map.iter());
+ let _ = black_box(map.iter());
}
});
}
/// }
/// ```
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
unsafe { __rust_alloc(layout.size(), layout.align()) }
///
/// See [`GlobalAlloc::realloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
/// }
/// ```
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
/// item's ordering relative to any other item, as determined by the [`Ord`]
/// trait, changes while it is in the heap. This is normally only possible
/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect
-/// results, aborts, memory leaks, and non-termination.
+/// behavior resulting from such a logic error is not specified (it
+/// could include panics, incorrect results, aborts, memory leaks, or
+/// non-termination) but will not be undefined behavior.
///
/// # Examples
///
/// let vec = heap.into_sorted_vec();
/// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
pub fn into_sorted_vec(mut self) -> Vec<T> {
let mut end = self.len();
///
/// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
/// ```
- #[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
IntoIterSorted { inner: self }
/// # Time complexity
///
/// Cost is *O*(1) in the worst case.
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
/// assert!(heap.capacity() >= 100);
/// heap.push(4);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
self.data.capacity()
///
/// assert_eq!(heap.len(), 2);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.data.len()
///
/// assert!(!heap.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.len() == 0
/// documentation for more.
///
/// [`iter`]: BinaryHeap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
}
}
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
#[derive(Clone, Debug)]
pub struct IntoIterSorted<T> {
/// performance on *small* nodes of elements which are cheap to compare. However in the future we
/// would like to further explore choosing the optimal search strategy based on the choice of B,
/// and possibly other factors. Using linear search, searching for a random element is expected
-/// to take O(B * log(n)) comparisons, which is generally worse than a BST. In practice,
+/// to take B * log(n) comparisons, which is generally worse than a BST. In practice,
/// however, performance is excellent.
///
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
///
/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree
/// [`Cell`]: core::cell::Cell
/// documentation for more.
///
/// [`iter`]: BTreeMap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, K: 'a, V: 'a> {
range: LazyLeafRange<marker::Immut<'a>, K, V>,
_marker: PhantomData<&'a mut (K, V)>,
}
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// documentation for more.
///
/// [`keys`]: BTreeMap::keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Keys<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
/// documentation for more.
///
/// [`values`]: BTreeMap::values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Values<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
/// documentation for more.
///
/// [`values_mut`]: BTreeMap::values_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_values_mut", since = "1.10.0")]
pub struct ValuesMut<'a, K: 'a, V: 'a> {
inner: IterMut<'a, K, V>,
/// See its documentation for more.
///
/// [`into_keys`]: BTreeMap::into_keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub struct IntoKeys<K, V> {
inner: IntoIter<K, V>,
/// See its documentation for more.
///
/// [`into_values`]: BTreeMap::into_values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub struct IntoValues<K, V> {
inner: IntoIter<K, V>,
/// documentation for more.
///
/// [`range`]: BTreeMap::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, K: 'a, V: 'a> {
inner: LeafRange<marker::Immut<'a>, K, V>,
/// documentation for more.
///
/// [`range_mut`]: BTreeMap::range_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct RangeMut<'a, K: 'a, V: 'a> {
inner: LeafRange<marker::ValMut<'a>, K, V>,
/// assert_eq!(keys, [1, 2]);
/// ```
#[inline]
- #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
/// assert_eq!(values, ["hello", "goodbye"]);
/// ```
#[inline]
- #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
/// a.insert(1, "a");
/// assert_eq!(a.len(), 1);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
/// a.insert(1, "a");
/// assert!(!a.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn is_empty(&self) -> bool {
/// map.entry("poneyland").or_insert(12);
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
/// ```
+ #[must_use]
#[stable(feature = "map_entry_keys", since = "1.10.0")]
pub fn key(&self) -> &K {
self.handle.reborrow().into_kv().0
/// assert_eq!(o.get(), &12);
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> &V {
self.handle.reborrow().into_kv().1
#[should_panic]
fn test_range_equal_excluded() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(2), Excluded(2)));
+ let _ = map.range((Excluded(2), Excluded(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_1() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Included(3), Included(2)));
+ let _ = map.range((Included(3), Included(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_2() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Included(3), Excluded(2)));
+ let _ = map.range((Included(3), Excluded(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_3() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(3), Included(2)));
+ let _ = map.range((Excluded(3), Included(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_4() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(3), Excluded(2)));
+ let _ = map.range((Excluded(3), Excluded(2)));
}
#[test]
// we cause a different panic than `test_range_backwards_1` does.
// A more refined `should_panic` would be welcome.
if Cyclic3::C < Cyclic3::A {
- map.range(Cyclic3::C..=Cyclic3::A);
+ let _ = map.range(Cyclic3::C..=Cyclic3::A);
}
}
}
let map = (0..12).map(|i| (CompositeKey(i, EvilTwin(i)), ())).collect::<BTreeMap<_, _>>();
- map.range(EvilTwin(5)..=EvilTwin(7));
+ let _ = map.range(EvilTwin(5)..=EvilTwin(7));
}
#[test]
#[allow(dead_code)]
fn get<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.get(t);
+ let _ = v.get(t);
}
#[allow(dead_code)]
fn get_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) {
- v.get_mut(t);
+ let _ = v.get_mut(t);
}
#[allow(dead_code)]
fn get_key_value<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.get_key_value(t);
+ let _ = v.get_key_value(t);
}
#[allow(dead_code)]
fn contains_key<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.contains_key(t);
+ let _ = v.contains_key(t);
}
#[allow(dead_code)]
fn range<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: T) {
- v.range(t..);
+ let _ = v.range(t..);
}
#[allow(dead_code)]
fn range_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: T) {
- v.range_mut(t..);
+ let _ = v.range_mut(t..);
}
#[allow(dead_code)]
/// It is a logic error for an item to be modified in such a way that the item's ordering relative
/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
///
/// [`Ord`]: core::cmp::Ord
/// [`Cell`]: core::cell::Cell
/// See its documentation for more.
///
/// [`iter`]: BTreeSet::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: Keys<'a, T, ()>,
/// See its documentation for more.
///
/// [`range`]: BTreeSet::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug)]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, T: 'a> {
/// See its documentation for more.
///
/// [`difference`]: BTreeSet::difference
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Difference<'a, T: 'a> {
inner: DifferenceInner<'a, T>,
/// [`BTreeSet`]. See its documentation for more.
///
/// [`symmetric_difference`]: BTreeSet::symmetric_difference
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
/// See its documentation for more.
///
/// [`intersection`]: BTreeSet::intersection
+#[must_use = "this returns the intersection as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Intersection<'a, T: 'a> {
inner: IntersectionInner<'a, T>,
/// See its documentation for more.
///
/// [`union`]: BTreeSet::union
+#[must_use = "this returns the union as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
/// set.insert(2);
/// assert_eq!(set.first(), Some(&1));
/// ```
+ #[must_use]
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn first(&self) -> Option<&T>
where
/// set.insert(2);
/// assert_eq!(set.last(), Some(&2));
/// ```
+ #[must_use]
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn last(&self) -> Option<&T>
where
/// v.insert(1);
/// assert_eq!(v.len(), 1);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
/// v.insert(1);
/// assert!(!v.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn is_empty(&self) -> bool {
#[test]
fn test_ord_absence() {
fn set<K>(mut set: BTreeSet<K>) {
- set.is_empty();
- set.len();
+ let _ = set.is_empty();
+ let _ = set.len();
set.clear();
- set.iter();
- set.into_iter();
+ let _ = set.iter();
+ let _ = set.into_iter();
}
fn set_debug<K: Debug>(set: BTreeSet<K>) {
///
/// This `struct` is created by [`LinkedList::iter()`]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
head: Option<NonNull<Node<T>>>,
///
/// This `struct` is created by [`LinkedList::iter_mut()`]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
head: Option<NonNull<Node<T>>>,
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front(&self) -> Cursor<'_, T> {
Cursor { index: 0, current: self.head, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
CursorMut { index: 0, current: self.head, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back(&self) -> Cursor<'_, T> {
Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
/// assert!(!dl.is_empty());
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.head.is_none()
/// assert_eq!(dl.len(), 3);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.len
/// assert_eq!(dl.front(), Some(&1));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn front(&self) -> Option<&T> {
unsafe { self.head.as_ref().map(|node| &node.as_ref().element) }
/// assert_eq!(dl.front(), Some(&5));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn front_mut(&mut self) -> Option<&mut T> {
unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) }
/// assert_eq!(dl.back(), Some(&1));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn back(&self) -> Option<&T> {
unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) }
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn index(&self) -> Option<usize> {
let _ = self.current?;
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn current(&self) -> Option<&'a T> {
unsafe { self.current.map(|current| &(*current.as_ptr()).element) }
/// If the cursor is pointing to the "ghost" non-element then this returns
/// the first element of the `LinkedList`. If it is pointing to the last
/// element of the `LinkedList` then this returns `None`.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn peek_next(&self) -> Option<&'a T> {
unsafe {
/// If the cursor is pointing to the "ghost" non-element then this returns
/// the last element of the `LinkedList`. If it is pointing to the first
/// element of the `LinkedList` then this returns `None`.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn peek_prev(&self) -> Option<&'a T> {
unsafe {
/// Provides a reference to the front element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front(&self) -> Option<&'a T> {
self.list.front()
/// Provides a reference to the back element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back(&self) -> Option<&'a T> {
self.list.back()
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn index(&self) -> Option<usize> {
let _ = self.current?;
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn current(&mut self) -> Option<&mut T> {
unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) }
/// Provides a reference to the front element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front(&self) -> Option<&T> {
self.list.front()
/// Provides a mutable reference to the front element of the cursor's
/// parent list, or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front_mut(&mut self) -> Option<&mut T> {
self.list.front_mut()
/// Provides a reference to the back element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back(&self) -> Option<&T> {
self.list.back()
/// assert_eq!(contents.next(), Some(0));
/// assert_eq!(contents.next(), None);
/// ```
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back_mut(&mut self) -> Option<&mut T> {
self.list.back_mut()
impl TryReserveError {
/// Details about the allocation that caused the error
#[inline]
+ #[must_use]
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
+ assert!(capacity < 1_usize << usize::BITS - 1, "capacity overflow");
// +1 since the ringbuffer always leaves one space empty
let cap = cmp::max(capacity + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
- assert!(cap > capacity, "capacity overflow");
VecDeque { tail: 0, head: 0, buf: RawVec::with_capacity_in(cap, alloc) }
}
/// [`format_args!`]: core::format_args
/// [`format!`]: crate::format
#[cfg(not(no_global_oom_handling))]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn format(args: Arguments<'_>) -> string::String {
let capacity = args.estimated_capacity();
)]
#![no_std]
#![needs_allocator]
+//
+// Lints:
+#![deny(unsafe_op_in_unsafe_fn)]
#![warn(deprecated_in_future)]
-#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
+#![warn(missing_docs)]
#![allow(explicit_outlives_requirements)]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(not(test), feature(generator_trait))]
-#![cfg_attr(test, feature(test))]
-#![cfg_attr(test, feature(new_uninit))]
+//
+// Library features:
+#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_windows)]
-#![feature(allow_internal_unstable)]
-#![feature(arbitrary_self_types)]
#![feature(async_stream)]
-#![feature(box_patterns)]
-#![feature(box_syntax)]
-#![feature(cfg_sanitize)]
-#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
-#![feature(const_fn_trait_bound)]
-#![feature(cow_is_borrowed)]
#![feature(const_cow_is_borrowed)]
-#![feature(const_trait_impl)]
-#![feature(destructuring_assignment)]
-#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
-#![feature(dropck_eyepatch)]
+#![feature(dispatch_from_dyn)]
#![feature(exact_size_is_empty)]
-#![feature(exclusive_range_pattern)]
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
-#![feature(fundamental)]
+#![feature(inherent_ascii_escape)]
#![feature(inplace_iteration)]
-// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
-// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
-// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
-// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
-#![feature(intra_doc_pointers)]
#![feature(iter_advance_by)]
#![feature(iter_zip)]
-#![feature(lang_items)]
#![feature(layout_for_ptr)]
-#![feature(negative_impls)]
-#![feature(never_type)]
-#![feature(nll)]
+#![feature(maybe_uninit_extra)]
+#![feature(maybe_uninit_slice)]
+#![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)]
-#![feature(auto_traits)]
-#![feature(option_result_unwrap_unchecked)]
#![feature(pattern)]
#![feature(ptr_internals)]
-#![feature(rustc_attrs)]
#![feature(receiver_trait)]
-#![feature(min_specialization)]
#![feature(set_ptr_value)]
+#![feature(slice_group_by)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(slice_range)]
-#![feature(staged_api)]
#![feature(str_internals)]
#![feature(trusted_len)]
-#![feature(unboxed_closures)]
+#![feature(trusted_random_access)]
+#![feature(try_trait_v2)]
#![feature(unicode_internals)]
#![feature(unsize)]
-#![feature(unsized_fn_params)]
+//
+// Language features:
#![feature(allocator_internals)]
-#![feature(slice_partition_dedup)]
-#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
-#![feature(alloc_layout_extra)]
-#![feature(trusted_random_access)]
-#![feature(try_trait_v2)]
+#![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)]
-#![feature(slice_group_by)]
-#![feature(decl_macro)]
+#![feature(box_syntax)]
+#![feature(cfg_sanitize)]
+#![feature(cfg_target_has_atomic)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+#![feature(destructuring_assignment)]
+#![feature(dropck_eyepatch)]
+#![feature(exclusive_range_pattern)]
+#![feature(fundamental)]
+#![cfg_attr(not(test), feature(generator_trait))]
+#![feature(lang_items)]
+#![feature(min_specialization)]
+#![feature(negative_impls)]
+#![feature(never_type)]
+#![feature(nll)] // Not necessary, but here to test the `nll` feature.
+#![feature(rustc_allow_const_fn_unstable)]
+#![feature(rustc_attrs)]
+#![feature(staged_api)]
+#![cfg_attr(test, feature(test))]
+#![feature(unboxed_closures)]
+#![feature(unsized_fn_params)]
+//
+// Rustdoc features:
#![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
-// Allow testing this library
+#![feature(doc_cfg_hide)]
+// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
+// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
+// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
+// from other crates, but since this can only appear for lang items, it doesn't seem worth fixing.
+#![feature(intra_doc_pointers)]
+// Allow testing this library
#[cfg(test)]
#[macro_use]
extern crate std;
//! use std::rc::Rc;
//!
//! let my_rc = Rc::new(());
-//! Rc::downgrade(&my_rc);
+//! let my_weak = Rc::downgrade(&my_rc);
//! ```
//!
//! `Rc<T>`'s implementations of traits like `Clone` may also be called using
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
+#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
+impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for Rc<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
///
/// let weak_five = Rc::downgrade(&five);
/// ```
+ #[must_use = "this returns a new `Weak` pointer, \
+ without modifying the original `Rc`"]
#[stable(feature = "rc_weak", since = "1.4.0")]
pub fn downgrade(this: &Self) -> Weak<T> {
this.inner().inc_weak();
/// Gets the number of strong (`Rc`) pointers pointing to this allocation.
///
/// If `self` was created using [`Weak::new`], this will return 0.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn strong_count(&self) -> usize {
if let Some(inner) = self.inner() { inner.strong() } else { 0 }
/// Gets the number of `Weak` pointers pointing to this allocation.
///
/// If no strong pointers remain, this will return zero.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn weak_count(&self) -> usize {
self.inner()
/// assert!(!first.ptr_eq(&third));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.ptr.as_ptr() == other.ptr.as_ptr()
pub use core::slice::ArrayChunksMut;
#[unstable(feature = "array_windows", issue = "75027")]
pub use core::slice::ArrayWindows;
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+pub use core::slice::EscapeAscii;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
pub use core::slice::{RSplit, RSplitMut};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut};
+#[stable(feature = "split_inclusive", since = "1.51.0")]
+pub use core::slice::{SplitInclusive, SplitInclusiveMut};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
pub use core::str::EncodeUtf16;
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
pub use core::str::SplitAsciiWhitespace;
-#[stable(feature = "split_inclusive", since = "1.53.0")]
+#[stable(feature = "split_inclusive", since = "1.51.0")]
pub use core::str::SplitInclusive;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::SplitWhitespace;
/// assert_eq!(*boxed_bytes, *s.as_bytes());
/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
self.into()
/// assert_eq!(boxed_str.into_string(), string);
/// ```
#[stable(feature = "box_str", since = "1.4.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_string(self: Box<str>) -> String {
let slice = Box::<[u8]>::from(self);
///
/// ```should_panic
/// // this will panic at runtime
- /// "0123456789abcdef".repeat(usize::MAX);
+ /// let huge = "0123456789abcdef".repeat(usize::MAX);
/// ```
#[cfg(not(no_global_oom_handling))]
+ #[must_use]
#[stable(feature = "repeat_str", since = "1.16.0")]
pub fn repeat(&self, n: usize) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
///
/// assert_eq!("Hello �World", output);
/// ```
+ #[must_use]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
/// String::from_utf16_lossy(v));
/// ```
#[cfg(not(no_global_oom_handling))]
+ #[must_use]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf16_lossy(v: &[u16]) -> String {
/// assert!(s.capacity() >= 10);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
self.vec.capacity()
///
/// # Safety
///
- /// This function is unsafe because it does not check that the bytes passed
- /// to it are valid UTF-8. If this constraint is violated, it may cause
- /// memory unsafety issues with future users of the `String`, as the rest of
- /// the standard library assumes that `String`s are valid UTF-8.
+ /// This function is unsafe because the returned `&mut Vec` allows writing
+ /// bytes which are not valid UTF-8. If this constraint is violated, using
+ /// the original `String` after dropping the `&mut Vec` may violate memory
+ /// safety, as the rest of the standard library assumes that `String`s are
+ /// valid UTF-8.
///
/// # Examples
///
/// assert_eq!(fancy_f.chars().count(), 3);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.vec.len()
/// assert!(!v.is_empty());
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.len() == 0
/// // the first byte is invalid here
/// assert_eq!(1, error.valid_up_to());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn utf8_error(&self) -> Utf8Error {
self.error
/// let x_ptr = Arc::into_raw(x);
/// assert_eq!(unsafe { &*x_ptr }, "hello");
/// ```
+ #[must_use = "losing the pointer will leak memory"]
#[stable(feature = "rc_raw", since = "1.17.0")]
pub fn into_raw(this: Self) -> *const T {
let ptr = Self::as_ptr(&this);
/// assert_eq!(1, Arc::weak_count(&five));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "arc_counts", since = "1.15.0")]
pub fn weak_count(this: &Self) -> usize {
let cnt = this.inner().weak.load(SeqCst);
/// assert_eq!(2, Arc::strong_count(&five));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "arc_counts", since = "1.15.0")]
pub fn strong_count(this: &Self) -> usize {
this.inner().strong.load(SeqCst)
drop(Weak { ptr: self.ptr });
}
- #[inline]
- #[stable(feature = "ptr_eq", since = "1.17.0")]
/// Returns `true` if the two `Arc`s point to the same allocation
/// (in a vein similar to [`ptr::eq`]).
///
/// ```
///
/// [`ptr::eq`]: core::ptr::eq "ptr::eq"
+ #[inline]
+ #[must_use]
+ #[stable(feature = "ptr_eq", since = "1.17.0")]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
/// Gets the number of strong (`Arc`) pointers pointing to this allocation.
///
/// If `self` was created using [`Weak::new`], this will return 0.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn strong_count(&self) -> usize {
if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 }
/// Due to implementation details, the returned value can be off by 1 in
/// either direction when other threads are manipulating any `Arc`s or
/// `Weak`s pointing to the same allocation.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn weak_count(&self) -> usize {
self.inner()
///
/// [`ptr::eq`]: core::ptr::eq "ptr::eq"
#[inline]
+ #[must_use]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.ptr.as_ptr() == other.ptr.as_ptr()
/// Returns a reference to the underlying allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[must_use]
#[inline]
pub fn allocator(&self) -> &A {
unsafe { self.vec.as_ref().allocator() }
// We replace self[index] with the last element. Note that if the
// bounds check above succeeds there must be a last element (which
// can be self[index] itself).
- let last = ptr::read(self.as_ptr().add(len - 1));
- let hole = self.as_mut_ptr().add(index);
+ let value = ptr::read(self.as_ptr().add(index));
+ let base_ptr = self.as_mut_ptr();
+ ptr::copy(base_ptr.add(len - 1), base_ptr.add(index), 1);
self.set_len(len - 1);
- ptr::replace(hole, last)
+ value
}
}
#[should_panic]
fn test_split_at_boundscheck() {
let s = "ศไทย中华Việt Nam";
- s.split_at(1);
+ let _ = s.split_at(1);
}
#[test]
-Subproject commit cc89bb66f91b2b4a640b0b525ca5d753e3346d7e
+Subproject commit 7f14f76c8ba6945c052fab77022e6e768b58e0b4
/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
+ #[must_use]
#[inline]
pub const fn size(&self) -> usize {
self.size_
/// allocate backing structure for `T` (which could be a trait
/// or other unsized type like a slice).
#[stable(feature = "alloc_layout", since = "1.28.0")]
+ #[must_use]
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
#[unstable(feature = "layout_for_ptr", issue = "69835")]
+ #[must_use]
pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
// SAFETY: we pass along the prerequisites of these functions to the caller
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
/// some other means.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")]
+ #[must_use]
#[inline]
pub const fn dangling(&self) -> NonNull<u8> {
// SAFETY: align is guaranteed to be non-zero
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
/// "core::option::Option<alloc::string::String>",
/// );
/// ```
+#[must_use]
#[stable(feature = "type_name", since = "1.38.0")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
/// let y = 1.0;
/// println!("{}", type_name_of_val(&y));
/// ```
+#[must_use]
#[unstable(feature = "type_name_of_val", issue = "66359")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_ref<T>(s: &T) -> &[T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T; 1] {
// SAFETY: Converting `&T` to `&[T; 1]` is sound.
unsafe { &*(s as *const T).cast::<[T; 1]>() }
}
/// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
// SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound.
unsafe { &mut *(s as *mut T).cast::<[T; 1]>() }
}
}
#[stable(feature = "try_from_slice_error", since = "1.36.0")]
-impl From<Infallible> for TryFromSliceError {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<Infallible> for TryFromSliceError {
fn from(x: Infallible) -> TryFromSliceError {
match x {}
}
// items.
unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
}
+
+ /// Divides one array reference into two at an index.
+ ///
+ /// The first will contain all indices from `[0, M)` (excluding
+ /// the index `M` itself) and the second will contain all
+ /// indices from `[M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = [1, 2, 3, 4, 5, 6];
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<0>();
+ /// assert_eq!(left, &[]);
+ /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<2>();
+ /// assert_eq!(left, &[1, 2]);
+ /// assert_eq!(right, &[3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<6>();
+ /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, &[]);
+ /// }
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) {
+ (&self[..]).split_array_ref::<M>()
+ }
+
+ /// Divides one mutable array reference into two at an index.
+ ///
+ /// The first will contain all indices from `[0, M)` (excluding
+ /// the index `M` itself) and the second will contain all
+ /// indices from `[M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// let (left, right) = v.split_array_mut::<2>();
+ /// assert_eq!(left, &mut [1, 0][..]);
+ /// assert_eq!(right, &mut [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
+ (&mut self[..]).split_array_mut::<M>()
+ }
}
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
///
/// This `struct` is created by the [`escape_default`] function. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct EscapeDefault {
}
#[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for Cell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Cell<T> {
fn from(t: T) -> Cell<T> {
Cell::new(t)
}
}
#[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for RefCell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for RefCell<T> {
fn from(t: T) -> RefCell<T> {
RefCell::new(t)
}
/// with the widespread use of `r.borrow().clone()` to clone the contents of
/// a `RefCell`.
#[stable(feature = "cell_extras", since = "1.15.0")]
+ #[must_use]
#[inline]
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
Ref { value: orig.value, borrow: orig.borrow.clone() }
}
#[stable(feature = "cell_from", since = "1.12.0")]
-impl<T> From<T> for UnsafeCell<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for UnsafeCell<T> {
fn from(t: T) -> UnsafeCell<T> {
UnsafeCell::new(t)
}
}
#[stable(feature = "char_convert", since = "1.13.0")]
-impl From<char> for u32 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u32 {
/// Converts a [`char`] into a [`u32`].
///
/// # Examples
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
-impl From<char> for u64 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u64 {
/// Converts a [`char`] into a [`u64`].
///
/// # Examples
}
#[stable(feature = "more_char_conversions", since = "1.51.0")]
-impl From<char> for u128 {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<char> for u128 {
/// Converts a [`char`] into a [`u128`].
///
/// # Examples
/// for a superset of Windows-1252 that fills the remaining blanks with corresponding
/// C0 and C1 control codes.
#[stable(feature = "char_convert", since = "1.13.0")]
-impl From<u8> for char {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<u8> for char {
/// Converts a [`u8`] into a [`char`].
///
/// # Examples
impl DecodeUtf16Error {
/// Returns the unpaired surrogate which caused this error.
+ #[must_use]
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub fn unpaired_surrogate(&self) -> u16 {
self.code
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "clone"]
#[rustc_diagnostic_item = "Clone"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
pub trait Clone: Sized {
/// Returns a copy of the value.
///
/// ```
#[derive(Clone, Copy, PartialEq, Debug, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
+#[repr(i8)]
pub enum Ordering {
/// An ordering where a compared value is less than another.
#[stable(feature = "rust1", since = "1.0.0")]
// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> From<T> for T {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for T {
fn from(t: T) -> T {
t
}
#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
#[rustc_reservation_impl = "permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
-impl<T> From<!> for T {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<!> for T {
fn from(t: !) -> T {
t
}
}
#[stable(feature = "convert_infallible", since = "1.34.0")]
-impl From<!> for Infallible {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<!> for Infallible {
fn from(x: !) -> Self {
x
}
macro_rules! nzint_impl_from {
($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
#[$attr]
- impl From<$Small> for $Large {
+ #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+ impl const From<$Small> for $Large {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
fn from(small: $Small) -> Self {
// SAFETY: input type guarantees the value is non-zero
unsafe {
- Self::new_unchecked(small.get().into())
+ Self::new_unchecked(From::from(small.get()))
}
}
}
/// }
/// ```
#[unstable(feature = "default_free_fn", issue = "73014")]
+#[must_use]
#[inline]
pub fn default<T: Default>() -> T {
Default::default()
use crate::num::flt2dec;
use crate::num::fmt as numfmt;
+#[doc(hidden)]
+trait GeneralFormat: PartialOrd {
+ /// Determines if a value should use exponential based on its magnitude, given the precondition
+ /// that it will not be rounded any further before it is displayed.
+ fn already_rounded_value_should_use_exponential(&self) -> bool;
+}
+
+macro_rules! impl_general_format {
+ ($($t:ident)*) => {
+ $(impl GeneralFormat for $t {
+ fn already_rounded_value_should_use_exponential(&self) -> bool {
+ let abs = $t::abs_private(*self);
+ (abs != 0.0 && abs < 1e-4) || abs >= 1e+16
+ }
+ })*
+ }
+}
+
+impl_general_format! { f32 f64 }
+
// Don't inline this so callers don't use the stack space this function
// requires unless they have to.
#[inline(never)]
fmt.pad_formatted_parts(&formatted)
}
-// Common code of floating point Debug and Display.
-fn float_to_decimal_common<T>(fmt: &mut Formatter<'_>, num: &T, min_precision: usize) -> Result
+fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
where
T: flt2dec::DecodableFloat,
{
if let Some(precision) = fmt.precision {
float_to_decimal_common_exact(fmt, num, sign, precision)
} else {
+ let min_precision = 0;
float_to_decimal_common_shortest(fmt, num, sign, min_precision)
}
}
}
}
+fn float_to_general_debug<T>(fmt: &mut Formatter<'_>, num: &T) -> Result
+where
+ T: flt2dec::DecodableFloat + GeneralFormat,
+{
+ let force_sign = fmt.sign_plus();
+ let sign = match force_sign {
+ false => flt2dec::Sign::Minus,
+ true => flt2dec::Sign::MinusPlus,
+ };
+
+ if let Some(precision) = fmt.precision {
+ // this behavior of {:.PREC?} predates exponential formatting for {:?}
+ float_to_decimal_common_exact(fmt, num, sign, precision)
+ } else {
+ // since there is no precision, there will be no rounding
+ if num.already_rounded_value_should_use_exponential() {
+ let upper = false;
+ float_to_exponential_common_shortest(fmt, num, sign, upper)
+ } else {
+ let min_precision = 1;
+ float_to_decimal_common_shortest(fmt, num, sign, min_precision)
+ }
+ }
+}
+
macro_rules! floating {
($ty:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for $ty {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
- float_to_decimal_common(fmt, self, 1)
+ float_to_general_debug(fmt, self)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Display for $ty {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
- float_to_decimal_common(fmt, self, 0)
+ float_to_decimal_display(fmt, self)
}
}
/// valid index of `args`.
/// 3. Every [`Count::Param`] within `fmt` must contain a valid index of
/// `args`.
- #[cfg(not(bootstrap))]
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
Arguments { pieces, fmt: Some(fmt), args }
}
- #[cfg(bootstrap)]
- #[doc(hidden)]
- #[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
- pub const unsafe fn new_v1_formatted(
- pieces: &'a [&'static str],
- args: &'a [ArgumentV1<'a>],
- fmt: &'a [rt::v1::Argument],
- ) -> Arguments<'a> {
- Arguments { pieces, fmt: Some(fmt), args }
- }
-
/// Estimates the length of the formatted text.
///
/// This is intended to be used for setting initial `String` capacity
)]
#[doc(alias = "{:?}")]
#[rustc_diagnostic_item = "Debug"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
pub trait Debug {
/// Formats the value using the given formatter.
///
}
/// Flags for formatting
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(
since = "1.24.0",
/// assert_eq!(&format!("{:G>3}", Foo), "GGG");
/// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn fill(&self) -> char {
self.fill
/// assert_eq!(&format!("{:^}", Foo), "center");
/// assert_eq!(&format!("{}", Foo), "into the void");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> {
match self.align {
/// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23) ");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn width(&self) -> Option<usize> {
self.width
/// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)");
/// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn precision(&self) -> Option<usize> {
self.precision
/// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool {
self.flags & (1 << FlagV1::SignPlus as u32) != 0
/// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool {
self.flags & (1 << FlagV1::SignMinus as u32) != 0
/// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)");
/// assert_eq!(&format!("{}", Foo(23)), "23");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool {
self.flags & (1 << FlagV1::Alternate as u32) != 0
///
/// assert_eq!(&format!("{:04}", Foo(23)), "23");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_aware_zero_pad(&self) -> bool {
self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
#[lang = "get_context"]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
+#[must_use]
#[inline]
pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
// SAFETY: the caller must guarantee that `cx.0` is a valid pointer
forward_ref_unop!(impl $imp, $method for $t,
#[stable(feature = "rust1", since = "1.0.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty) => {
+ forward_ref_unop!(impl const $imp, $method for $t,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp for &$t {
+ type Output = <$t as $imp>::Output;
+
+ #[inline]
+ fn $method(self) -> <$t as $imp>::Output {
+ $imp::$method(*self)
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
#[$attr]
impl $imp for &$t {
forward_ref_binop!(impl $imp, $method for $t, $u,
#[stable(feature = "rust1", since = "1.0.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ forward_ref_binop!(impl const $imp, $method for $t, $u,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl<'a> const $imp<$u> for &'a $t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, other)
+ }
+ }
+
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for $t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(self, *other)
+ }
+ }
+
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for &$t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, *other)
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl<'a> $imp<$u> for &'a $t {
forward_ref_op_assign!(impl $imp, $method for $t, $u,
#[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ forward_ref_op_assign!(impl const $imp, $method for $t, $u,
+ #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for $t {
+ #[inline]
+ fn $method(&mut self, other: &$u) {
+ $imp::$method(self, *other);
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl $imp<&$u> for $t {
/// or have any other observable side-effects, the behavior is undefined.
///
/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
-#[cfg(not(bootstrap))]
#[unstable(
feature = "const_eval_select",
issue = "none",
called_at_rt.call_once(arg)
}
-#[cfg(not(bootstrap))]
#[unstable(
feature = "const_eval_select",
issue = "none",
}
}
+// Since SourceIter forwards the left hand side we do the same here
#[unstable(issue = "none", feature = "inplace_iteration")]
-// Limited to Item: Copy since interaction between Zip's use of TrustedRandomAccess
-// and Drop implementation of the source is unclear.
-//
-// An additional method returning the number of times the source has been logically advanced
-// (without calling next()) would be needed to properly drop the remainder of the source.
-unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> where A::Item: Copy {}
+unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Debug, B: Debug> Debug for Zip<A, B> {
/// An iterator that yields nothing.
///
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iter_empty", since = "1.2.0")]
pub struct Empty<T>(marker::PhantomData<T>);
/// Basic usage:
///
/// ```
- /// let a = [(1, 2), (3, 4)];
+ /// let a = [(1, 2), (3, 4), (5, 6)];
///
/// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip();
///
- /// assert_eq!(left, [1, 3]);
- /// assert_eq!(right, [2, 4]);
+ /// assert_eq!(left, [1, 3, 5]);
+ /// assert_eq!(right, [2, 4, 6]);
///
/// // you can also unzip multiple nested tuples at once
/// let a = [(1, (2, 3)), (4, (5, 6))];
impl<T: Eq> Eq for OnceCell<T> {}
#[unstable(feature = "once_cell", issue = "74465")]
-impl<T> From<T> for OnceCell<T> {
+impl<T> const From<T> for OnceCell<T> {
fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) }
}
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_discriminant)]
+#![cfg_attr(not(bootstrap), feature(const_eval_select))]
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
+#![feature(const_fmt_arguments_new)]
#![feature(const_heap)]
#![feature(const_inherent_unchecked_arith)]
#![feature(const_int_unchecked_arith)]
#![feature(const_likely)]
#![feature(const_maybe_uninit_as_ptr)]
#![feature(const_maybe_uninit_assume_init)]
+#![feature(const_num_from_num)]
+#![feature(const_ops)]
#![feature(const_option)]
#![feature(const_pin)]
#![feature(const_replace)]
#![feature(ptr_metadata)]
#![feature(slice_ptr_get)]
#![feature(variant_count)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
//
// Language features:
#![feature(abi_unadjusted)]
#![feature(const_fn_trait_bound)]
#![feature(const_impl_trait)]
#![feature(const_mut_refs)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(const_precise_live_drops)]
#![feature(const_raw_ptr_deref)]
#![feature(const_refs_to_cell)]
#![feature(doc_notable_trait)]
#![feature(doc_primitive)]
#![feature(exhaustive_patterns)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(if_let_guard)]
#![feature(llvm_asm)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(no_core)]
/// [arc]: ../../std/sync/struct.Arc.html
/// [ub]: ../../reference/behavior-considered-undefined.html
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")]
-#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Send")]
#[rustc_on_unimplemented(
message = "`{Self}` cannot be sent between threads safely",
label = "`{Self}` cannot be sent between threads safely"
///
/// [alignment]: align_of
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_size_of", since = "1.24.0")]
/// assert_eq!(13, mem::size_of_val(y));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")]
/// assert_eq!(13, unsafe { mem::size_of_val_raw(y) });
/// ```
#[inline]
+#[must_use]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")]
pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
/// assert_eq!(4, mem::min_align_of::<i32>());
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
pub fn min_align_of<T>() -> usize {
/// assert_eq!(4, mem::min_align_of_val(&5i32));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
/// assert_eq!(4, mem::align_of::<i32>());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
/// assert_eq!(4, mem::align_of_val(&5i32));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
#[allow(deprecated)]
/// assert_eq!(4, unsafe { mem::align_of_val_raw(&5i32) });
/// ```
#[inline]
+#[must_use]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")]
pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
/// }
/// ```
#[inline]
+#[must_use]
#[stable(feature = "needs_drop", since = "1.21.0")]
#[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
#[rustc_diagnostic_item = "needs_drop"]
/// let _y: fn() = unsafe { mem::zeroed() }; // And again!
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated_in_future)]
#[allow(deprecated)]
/// [assume_init]: MaybeUninit::assume_init
/// [inv]: MaybeUninit#initialization-invariant
#[inline(always)]
+#[must_use]
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated_in_future)]
/// assert_eq!(foo_array, [10]);
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
/// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
/// ```
#[inline(always)]
+#[must_use]
#[unstable(feature = "variant_count", issue = "73662")]
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_diagnostic_item = "mem_variant_count"]
}
#[stable(feature = "try_from", since = "1.34.0")]
-impl From<Infallible> for TryFromIntError {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<Infallible> for TryFromIntError {
fn from(x: Infallible) -> TryFromIntError {
match x {}
}
}
#[unstable(feature = "never_type", issue = "35121")]
-impl From<!> for TryFromIntError {
+impl const From<!> for TryFromIntError {
fn from(never: !) -> TryFromIntError {
// Match rather than coerce to make sure that code like
// `From<Infallible> for TryFromIntError` above will keep working
impl ParseIntError {
/// Outputs the detailed cause of parsing an integer failing.
+ #[must_use]
#[stable(feature = "int_error_matching", since = "1.55.0")]
pub fn kind(&self) -> &IntErrorKind {
&self.kind
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn abs_private(self) -> f32 {
+ pub(crate) const fn abs_private(self) -> f32 {
f32::from_bits(self.to_bits() & 0x7fff_ffff)
}
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
+ #[must_use]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i32;
// private use internally.
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn abs_private(self) -> f64 {
+ pub(crate) const fn abs_private(self) -> f64 {
f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff)
}
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
+ #[must_use]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i64;
} else {
3
}
- } else if v < 10_000 {
- 4
} else {
- 5
+ if v < 10_000 { 4 } else { 5 }
}
}
Part::Copy(buf) => buf.len(),
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- // Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- // Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
/// Basic usage:
///
/// ```
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_div(-1), ", stringify!($SelfT), "::MIN + 1);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_div(-1), ", stringify!($SelfT), "::MAX);")]
/// ```
///
/// ```should_panic
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
///
/// ```
- #[unstable(feature = "saturating_div", issue = "87920")]
- #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+ #[stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
}
macro_rules! widening_impl {
- ($SelfT:ty, $WideT:ty, $BITS:literal) => {
+ ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => {
+ widening_impl!($SelfT, $WideT, $BITS, "");
+ };
+ ($SelfT:ty, $WideT:ty, $BITS:literal, signed) => {
+ widening_impl!($SelfT, $WideT, $BITS, "# //");
+ };
+ ($SelfT:ty, $WideT:ty, $BITS:literal, $AdaptiveTestPrefix:literal) => {
/// Calculates the complete product `self * rhs` without the possibility to overflow.
///
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
/// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
+ #[doc = concat!($AdaptiveTestPrefix, "assert_eq!(",
+ stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ",
+ "(0, ", stringify!($SelfT), "::MAX));"
+ )]
+ /// ```
+ ///
+ /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
+ /// except that it gives the value of the overflow instead of just whether one happened:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ /// let r = u8::carrying_mul(7, 13, 0);
+ /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13));
+ /// let r = u8::carrying_mul(13, 42, 0);
+ /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
+ /// ```
+ ///
+ /// The value of the first field in the returned tuple matches what you'd get
+ /// by combining the [`wrapping_mul`](Self::wrapping_mul) and
+ /// [`wrapping_add`](Self::wrapping_add) methods:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ /// assert_eq!(
+ /// 789_u16.carrying_mul(456, 123).0,
+ /// 789_u16.wrapping_mul(456).wrapping_add(123),
+ /// );
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
#[lang = "i8"]
impl i8 {
- widening_impl! { i8, i16, 8 }
int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
"[0x12]", "[0x12]", "", "" }
+ widening_impl! { i8, i16, 8, signed }
}
#[lang = "i16"]
impl i16 {
- widening_impl! { i16, i32, 16 }
int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
"0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ widening_impl! { i16, i32, 16, signed }
}
#[lang = "i32"]
impl i32 {
- widening_impl! { i32, i64, 32 }
int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]", "", "" }
+ widening_impl! { i32, i64, 32, signed }
}
#[lang = "i64"]
impl i64 {
- widening_impl! { i64, i128, 64 }
int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
"0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+ widening_impl! { i64, i128, 64, signed }
}
#[lang = "i128"]
#[cfg(target_pointer_width = "16")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i32, 16 }
int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
"0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i32, 16, signed }
}
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i64, 32 }
int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i64, 32, signed }
}
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i128, 64 }
int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807,
12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i128, 64, signed }
}
/// If 6th bit set ascii is upper case.
#[lang = "u8"]
impl u8 {
- widening_impl! { u8, u16, 8 }
uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
"[0x12]", "", "" }
+ widening_impl! { u8, u16, 8, unsigned }
/// Checks if the value is within the ASCII range.
///
#[lang = "u16"]
impl u16 {
- widening_impl! { u16, u32, 16 }
uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ widening_impl! { u16, u32, 16, unsigned }
}
#[lang = "u32"]
impl u32 {
- widening_impl! { u32, u64, 32 }
uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
+ widening_impl! { u32, u64, 32, unsigned }
}
#[lang = "u64"]
impl u64 {
- widening_impl! { u64, u128, 64 }
uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
"", ""}
+ widening_impl! { u64, u128, 64, unsigned }
}
#[lang = "u128"]
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u32, 16 }
uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u32, 16, unsigned }
}
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u64, 32 }
uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u64, 32, unsigned }
}
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u128, 64 }
uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u128, 64, unsigned }
}
/// A classification of floating point numbers.
}
#[stable(feature = "from_nonzero", since = "1.31.0")]
- impl From<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+ impl const From<$Ty> for $Int {
#[doc = concat!("Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`")]
#[inline]
fn from(nonzero: $Ty) -> Self {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Int> for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr<$Int> for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: $Int) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr<$Ty> for $Int {
type Output = $Ty;
#[inline]
fn bitor(self, rhs: $Ty) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign<$Int> for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign<$Int> for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: $Int) {
*self = *self | rhs;
( $( $Ty: ident($Int: ty); )+ ) => {
$(
#[stable(feature = "nonzero_div", since = "1.51.0")]
- impl Div<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div<$Ty> for $Int {
type Output = $Int;
/// This operation rounds towards zero,
/// truncating any fractional part of the exact result, and cannot panic.
}
#[stable(feature = "nonzero_div", since = "1.51.0")]
- impl Rem<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem<$Ty> for $Int {
type Output = $Int;
/// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
#[inline]
/// Basic usage:
///
/// ```
- /// #![feature(saturating_int_impl, saturating_div)]
+ /// #![feature(saturating_int_impl)]
/// use std::num::Saturating;
///
#[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")]
/// ```
///
/// ```should_panic
- /// #![feature(saturating_int_impl, saturating_div)]
+ /// #![feature(saturating_int_impl)]
/// use std::num::Saturating;
///
#[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")]
/// Basic usage:
///
/// ```
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
///
/// ```
///
/// ```should_panic
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
///
/// ```
- #[unstable(feature = "saturating_div", issue = "87920")]
- #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+ #[stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// additional bit of overflow. This allows for chaining together multiple additions
/// to create "big integers" which represent larger values.
///
+ #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")]
+ ///
/// # Examples
///
/// Basic usage
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
+ #[doc = concat!("assert_eq!(",
+ stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+ "(", stringify!($SelfT), "::MAX, true));"
+ )]
+ /// ```
+ ///
+ /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
let (a, b) = self.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as $SelfT);
- (c, b | d)
+ (c, b || d)
}
/// Calculates `self` + `rhs` with a signed `rhs`
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
let (a, b) = self.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as $SelfT);
- (c, b | d)
+ (c, b || d)
}
/// Computes the absolute difference between `self` and `other`.
macro_rules! sh_impl_signed {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
}
}
}
- forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
}
}
}
- forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
macro_rules! sh_impl_unsigned {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
macro_rules! wrapping_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Add for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Add for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_add(other.0))
}
}
- forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Add, add for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl AddAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign for Wrapping<$t> {
#[inline]
fn add_assign(&mut self, other: Wrapping<$t>) {
*self = *self + other;
}
}
- forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Sub for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Sub for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_sub(other.0))
}
}
- forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Sub, sub for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl SubAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign for Wrapping<$t> {
#[inline]
fn sub_assign(&mut self, other: Wrapping<$t>) {
*self = *self - other;
}
}
- forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Mul for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Mul for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl MulAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign for Wrapping<$t> {
#[inline]
fn mul_assign(&mut self, other: Wrapping<$t>) {
*self = *self * other;
}
}
- forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_div", since = "1.3.0")]
- impl Div for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_div(other.0))
}
}
- forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Div, div for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl DivAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign for Wrapping<$t> {
#[inline]
fn div_assign(&mut self, other: Wrapping<$t>) {
*self = *self / other;
}
}
- forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_impls", since = "1.7.0")]
- impl Rem for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_rem(other.0))
}
}
- forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Rem, rem for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl RemAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign for Wrapping<$t> {
#[inline]
fn rem_assign(&mut self, other: Wrapping<$t>) {
*self = *self % other;
}
}
- forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Not for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Not for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(!self.0)
}
}
- forward_ref_unop! { impl Not, not for Wrapping<$t>,
+ forward_ref_unop! { impl const Not, not for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitXor for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXor for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 ^ other.0)
}
}
- forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitXorAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign for Wrapping<$t> {
#[inline]
fn bitxor_assign(&mut self, other: Wrapping<$t>) {
*self = *self ^ other;
}
}
- forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitOr for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 | other.0)
}
}
- forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitOrAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for Wrapping<$t> {
#[inline]
fn bitor_assign(&mut self, other: Wrapping<$t>) {
*self = *self | other;
}
}
- forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitAnd for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAnd for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 & other.0)
}
}
- forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitAndAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign for Wrapping<$t> {
#[inline]
fn bitand_assign(&mut self, other: Wrapping<$t>) {
*self = *self & other;
}
}
- forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_neg", since = "1.10.0")]
- impl Neg for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Neg for Wrapping<$t> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Wrapping(0) - self
}
}
- forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
+ forward_ref_unop! { impl const Neg, neg for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
)*)
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Add for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
- forward_ref_binop! { impl Add, add for $t, $t }
+ forward_ref_binop! { impl const Add, add for $t, $t }
)*)
}
macro_rules! sub_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Sub for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Sub for $t {
type Output = $t;
#[inline]
fn sub(self, other: $t) -> $t { self - other }
}
- forward_ref_binop! { impl Sub, sub for $t, $t }
+ forward_ref_binop! { impl const Sub, sub for $t, $t }
)*)
}
macro_rules! mul_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Mul for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Mul for $t {
type Output = $t;
#[inline]
fn mul(self, other: $t) -> $t { self * other }
}
- forward_ref_binop! { impl Mul, mul for $t, $t }
+ forward_ref_binop! { impl const Mul, mul for $t, $t }
)*)
}
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- impl Div for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl Div, div for $t, $t }
+ forward_ref_binop! { impl const Div, div for $t, $t }
)*)*)
}
macro_rules! div_impl_float {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Div for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl Div, div for $t, $t }
+ forward_ref_binop! { impl const Div, div for $t, $t }
)*)
}
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- impl Rem for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl Rem, rem for $t, $t }
+ forward_ref_binop! { impl const Rem, rem for $t, $t }
)*)*)
}
/// assert_eq!(x % y, remainder);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- impl Rem for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl Rem, rem for $t, $t }
+ forward_ref_binop! { impl const Rem, rem for $t, $t }
)*)
}
macro_rules! neg_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Neg for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Neg for $t {
type Output = $t;
#[inline]
fn neg(self) -> $t { -self }
}
- forward_ref_unop! { impl Neg, neg for $t }
+ forward_ref_unop! { impl const Neg, neg for $t }
)*)
}
macro_rules! add_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl AddAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn add_assign(&mut self, other: $t) { *self += other }
}
- forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for $t, $t }
)+)
}
macro_rules! sub_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl SubAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn sub_assign(&mut self, other: $t) { *self -= other }
}
- forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for $t, $t }
)+)
}
macro_rules! mul_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl MulAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn mul_assign(&mut self, other: $t) { *self *= other }
}
- forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for $t, $t }
)+)
}
macro_rules! div_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl DivAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign for $t {
#[inline]
fn div_assign(&mut self, other: $t) { *self /= other }
}
- forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for $t, $t }
)+)
}
macro_rules! rem_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl RemAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign for $t {
#[inline]
fn rem_assign(&mut self, other: $t) { *self %= other }
}
- forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for $t, $t }
)+)
}
macro_rules! not_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Not for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Not for $t {
type Output = $t;
#[inline]
fn not(self) -> $t { !self }
}
- forward_ref_unop! { impl Not, not for $t }
+ forward_ref_unop! { impl const Not, not for $t }
)*)
}
macro_rules! bitand_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitAnd for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAnd for $t {
type Output = $t;
#[inline]
fn bitand(self, rhs: $t) -> $t { self & rhs }
}
- forward_ref_binop! { impl BitAnd, bitand for $t, $t }
+ forward_ref_binop! { impl const BitAnd, bitand for $t, $t }
)*)
}
macro_rules! bitor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitOr for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for $t {
type Output = $t;
#[inline]
fn bitor(self, rhs: $t) -> $t { self | rhs }
}
- forward_ref_binop! { impl BitOr, bitor for $t, $t }
+ forward_ref_binop! { impl const BitOr, bitor for $t, $t }
)*)
}
macro_rules! bitxor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitXor for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXor for $t {
type Output = $t;
#[inline]
fn bitxor(self, other: $t) -> $t { self ^ other }
}
- forward_ref_binop! { impl BitXor, bitxor for $t, $t }
+ forward_ref_binop! { impl const BitXor, bitxor for $t, $t }
)*)
}
macro_rules! shl_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for $t {
type Output = $t;
#[inline]
}
}
- forward_ref_binop! { impl Shl, shl for $t, $f }
+ forward_ref_binop! { impl const Shl, shl for $t, $f }
};
}
macro_rules! shr_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for $t {
type Output = $t;
#[inline]
}
}
- forward_ref_binop! { impl Shr, shr for $t, $f }
+ forward_ref_binop! { impl const Shr, shr for $t, $f }
};
}
macro_rules! bitand_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitAndAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign for $t {
#[inline]
fn bitand_assign(&mut self, other: $t) { *self &= other }
}
- forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for $t, $t }
)+)
}
macro_rules! bitor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitOrAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for $t {
#[inline]
fn bitor_assign(&mut self, other: $t) { *self |= other }
}
- forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for $t, $t }
)+)
}
macro_rules! bitxor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitXorAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign for $t {
#[inline]
fn bitxor_assign(&mut self, other: $t) { *self ^= other }
}
- forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for $t, $t }
)+)
}
macro_rules! shl_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shl_assign(&mut self, other: $f) {
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for $t, $f }
};
}
macro_rules! shr_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shr_assign(&mut self, other: $f) {
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for $t, $f }
};
}
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
+/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
+/// to return immediately if the [`Break`] variant is present or otherwise continue normally
+/// with the value inside the [`Continue`] variant.
+///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
///
/// A basic tree traversal:
-/// ```no_run
+/// ```
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
/// }
///
/// impl<T> TreeNode<T> {
-/// pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
+/// pub fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
/// if let Some(left) = &self.left {
-/// left.traverse_inorder(&mut f)?;
+/// left.traverse_inorder(f)?;
/// }
/// f(&self.value)?;
/// if let Some(right) = &self.right {
-/// right.traverse_inorder(&mut f)?;
+/// right.traverse_inorder(f)?;
/// }
/// ControlFlow::Continue(())
/// }
+/// fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
+/// Some(Box::new(Self { value, left: None, right: None }))
+/// }
/// }
+///
+/// let node = TreeNode {
+/// value: 0,
+/// left: TreeNode::leaf(1),
+/// right: Some(Box::new(TreeNode {
+/// value: -1,
+/// left: TreeNode::leaf(5),
+/// right: TreeNode::leaf(2),
+/// }))
+/// };
+/// let mut sum = 0;
+///
+/// let res = node.traverse_inorder(&mut |val| {
+/// if *val < 0 {
+/// ControlFlow::Break(*val)
+/// } else {
+/// sum += *val;
+/// ControlFlow::Continue(())
+/// }
+/// });
+/// assert_eq!(res, ControlFlow::Break(-1));
+/// assert_eq!(sum, 6);
/// ```
+///
+/// [`Break`]: ControlFlow::Break
+/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
/// assert_eq!((1..12).start_bound(), Included(&1));
/// assert_eq!((1..12).start_bound().cloned(), Included(1));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "bound_cloned", since = "1.55.0")]
pub fn cloned(self) -> Bound<T> {
match self {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn as_mut(&mut self) -> Option<&mut T> {
+ #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+ pub const fn as_mut(&mut self) -> Option<&mut T> {
match *self {
Some(ref mut x) => Some(x),
None => None,
/// # Examples
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x = Some("air");
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
/// ```
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Option<&str> = None;
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
/// let copied = opt_x.copied();
/// assert_eq!(copied, Some(12));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "copied", since = "1.35.0")]
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
pub const fn copied(self) -> Option<T> {
}
#[stable(since = "1.12.0", feature = "option_from")]
-impl<T> From<T> for Option<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Option<T> {
/// Moves `val` into a new [`Some`].
///
/// # Examples
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<'a, T> const From<&'a Option<T>> for Option<&'a T> {
/// Converts from `&Option<T>` to `Option<&T>`.
///
/// # Examples
}
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
-impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<'a, T> const From<&'a mut Option<T>> for Option<&'a mut T> {
/// Converts from `&mut Option<T>` to `Option<&mut T>`
///
/// # Examples
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T> ops::FromResidual for Option<T> {
+impl<T> const ops::FromResidual for Option<T> {
#[inline]
fn from_residual(residual: Option<convert::Infallible>) -> Self {
match residual {
/// assert_ne!(this_location.line(), another_location.line());
/// assert_ne!(this_location.column(), another_location.column());
/// ```
+ #[must_use]
#[stable(feature = "track_caller", since = "1.46.0")]
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
#[track_caller]
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn file(&self) -> &str {
self.file
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn line(&self) -> u32 {
self.line
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_col", since = "1.25.0")]
pub fn column(&self) -> u32 {
self.col
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn payload(&self) -> &(dyn Any + Send) {
self.payload
/// If the `panic!` macro from the `core` crate (not from `std`)
/// was used with a formatting string and some additional arguments,
/// returns that message ready to be used for example with [`fmt::write`]
+ #[must_use]
#[unstable(feature = "panic_info_message", issue = "66745")]
pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
self.message
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn location(&self) -> Option<&Location<'_>> {
// NOTE: If this is changed to sometimes return None,
- // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
+ // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
Some(&self.location)
}
}
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
-pub fn panic(expr: &'static str) -> ! {
- if cfg!(feature = "panic_immediate_abort") {
- super::intrinsics::abort()
- }
-
+pub const fn panic(expr: &'static str) -> ! {
// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
// reduce size overhead. The format_args! macro uses str's Display trait to
// write expr, which calls Formatter::pad, which must accommodate string
#[inline]
#[track_caller]
-#[lang = "panic_str"] // needed for const-evaluated panics
-pub fn panic_str(expr: &str) -> ! {
- panic_fmt(format_args!("{}", expr));
+#[lang = "panic_str"] // needed for `non-fmt-panics` lint
+pub const fn panic_str(expr: &str) -> ! {
+ panic_display(&expr);
}
#[inline]
#[track_caller]
-#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics
-pub fn panic_display<T: fmt::Display>(x: &T) -> ! {
+#[lang = "panic_display"] // needed for const-evaluated panics
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
panic!("index out of bounds: the len is {} but the index is {}", len, index)
}
-/// The underlying implementation of libcore's `panic!` macro when formatting is used.
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
#[cold]
+// If panic_immediate_abort, inline the abort call,
+// otherwise avoid inlining because of it is cold path.
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
-pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
}
///
/// ["pinning projections"]: self#projections-and-structural-pinning
#[inline(always)]
+ #[must_use]
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn get_ref(self) -> &'a T {
/// assert!(p.is_null());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
/// assert!(p.is_null());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
/// ```
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")]
+ #[must_use]
#[inline]
pub const fn dangling() -> Self {
// SAFETY: mem::align_of() returns a non-zero usize which is then casted
/// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
#[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
#[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
+ #[must_use]
#[inline]
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
// SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
/// ```
#[unstable(feature = "slice_ptr_len", issue = "71146")]
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+ #[must_use]
#[inline]
pub const fn len(self) -> usize {
self.as_ptr().len()
}
#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<Unique<T>> for NonNull<T> {
#[inline]
fn from(unique: Unique<T>) -> Self {
// SAFETY: A Unique pointer cannot be null, so the conditions for
}
#[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&mut T> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<&mut T> for NonNull<T> {
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null.
}
#[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&T> for NonNull<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized> const From<&T> for NonNull<T> {
#[inline]
fn from(reference: &T) -> Self {
// SAFETY: A reference cannot be null, so the conditions for
/// a `T`, which means this must not be used as a "not yet initialized"
/// sentinel value. Types that lazily allocate must track initialization by
/// some other means.
+ #[must_use]
#[inline]
pub const fn dangling() -> Self {
// SAFETY: mem::align_of() returns a valid, non-null pointer. The
}
#[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<&mut T> for Unique<T> {
+impl<T: ?Sized> const From<&mut T> for Unique<T> {
#[inline]
fn from(reference: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn as_mut(&mut self) -> Result<&mut T, &mut E> {
+ #[rustc_const_unstable(feature = "const_result", issue = "82814")]
+ pub const fn as_mut(&mut self) -> Result<&mut T, &mut E> {
match *self {
Ok(ref mut x) => Ok(x),
Err(ref mut x) => Err(x),
/// # Examples
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
/// ```
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_ok());
match self {
/// # Examples
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
/// ```
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_err_unchecked(self) -> E {
debug_assert!(self.is_err());
match self {
impl [u8] {
/// Checks if all bytes in this slice are within the ASCII range.
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
is_ascii(self)
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
/// but without allocating and copying temporaries.
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
/// [`rsplit`]: slice::rsplit
/// [slices]: slice
#[stable(feature = "slice_rsplit", since = "1.27.0")]
-#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
pub struct RSplit<'a, T: 'a, P>
where
P: FnMut(&T) -> bool,
}
}
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> Clone for RSplit<'_, T, P>
+where
+ P: Clone + FnMut(&T) -> bool,
+{
+ fn clone(&self) -> Self {
+ RSplit { inner: self.inner.clone() }
+ }
+}
+
#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> Iterator for RSplit<'a, T, P>
where
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
+ #[must_use]
#[stable(feature = "chunks_exact", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
self.rem
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `N-1`
/// elements.
+ #[must_use]
#[unstable(feature = "array_chunks", issue = "74985")]
pub fn remainder(&self) -> &'a [T] {
self.rem
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
+ #[must_use]
#[stable(feature = "rchunks", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
self.rem
}
/// Returns the first index matching the byte `x` in `text`.
+#[must_use]
#[inline]
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices
}
/// Returns the last index matching the byte `x` in `text`.
+#[must_use]
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
/// # Examples
///
/// ```
- /// let mut v = ["a", "b", "c", "d"];
- /// v.swap(1, 3);
- /// assert!(v == ["a", "d", "c", "b"]);
+ /// let mut v = ["a", "b", "c", "d", "e"];
+ /// v.swap(2, 4);
+ /// assert!(v == ["a", "b", "e", "d", "c"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
}
+ /// Divides one slice into an array and a remainder slice at an index.
+ ///
+ /// The array will contain all indices from `[0, N)` (excluding
+ /// the index `N` itself) and the slice will contain all
+ /// indices from `[N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = &[1, 2, 3, 4, 5, 6][..];
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<0>();
+ /// assert_eq!(left, &[]);
+ /// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<2>();
+ /// assert_eq!(left, &[1, 2]);
+ /// assert_eq!(right, [3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<6>();
+ /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, []);
+ /// }
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
+ let (a, b) = self.split_at(N);
+ // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
+ unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
+ }
+
+ /// Divides one mutable slice into an array and a remainder slice at an index.
+ ///
+ /// The array will contain all indices from `[0, N)` (excluding
+ /// the index `N` itself) and the slice will contain all
+ /// indices from `[N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+ /// let (left, right) = v.split_array_mut::<2>();
+ /// assert_eq!(left, &mut [1, 0]);
+ /// assert_eq!(right, [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
+ let (a, b) = self.split_at_mut(N);
+ // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
+ unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
+ }
+
/// Returns an iterator over subslices separated by elements that match
/// `pred`. The matched element is not contained in the subslices.
///
///
/// The length of `src` must be the same as `self`.
///
- /// If `T` implements `Copy`, it can be more performant to use
- /// [`copy_from_slice`].
- ///
/// # Panics
///
/// This function will panic if the two slices have different lengths.
/// [`copy_from_slice`]: slice::copy_from_slice
/// [`split_at_mut`]: slice::split_at_mut
#[stable(feature = "clone_from_slice", since = "1.7.0")]
+ #[track_caller]
pub fn clone_from_slice(&mut self, src: &[T])
where
T: Clone,
/// [`split_at_mut`]: slice::split_at_mut
#[doc(alias = "memcpy")]
#[stable(feature = "copy_from_slice", since = "1.9.0")]
+ #[track_caller]
pub fn copy_from_slice(&mut self, src: &[T])
where
T: Copy,
///
/// [`split_at_mut`]: slice::split_at_mut
#[stable(feature = "swap_with_slice", since = "1.27.0")]
+ #[track_caller]
pub fn swap_with_slice(&mut self, other: &mut [T]) {
assert!(self.len() == other.len(), "destination and source slices have different lengths");
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
where
T: Clone,
{
+ #[track_caller]
default fn spec_clone_from(&mut self, src: &[T]) {
assert!(self.len() == src.len(), "destination and source slices have different lengths");
// NOTE: We need to explicitly slice them to the same length
where
T: Copy,
{
+ #[track_caller]
fn spec_clone_from(&mut self, src: &[T]) {
self.copy_from_slice(src);
}
//! Free functions to create `&[T]` and `&mut [T]`.
use crate::array;
-use crate::intrinsics::is_aligned_and_not_null;
-use crate::mem;
use crate::ptr;
/// Forms a slice from a pointer and a length.
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
- debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
- debug_assert!(
- mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
- "attempt to create slice covering at least half the address space"
- );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+ debug_check_data_len(data, len);
+
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe { &*ptr::slice_from_raw_parts(data, len) }
}
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
- debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
- debug_assert!(
- mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
- "attempt to create slice covering at least half the address space"
- );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+ debug_check_data_len(data as _, len);
+
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}
+// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
+#[cfg(all(not(bootstrap), debug_assertions))]
+#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+const fn debug_check_data_len<T>(data: *const T, len: usize) {
+ fn rt_check<T>(data: *const T) {
+ use crate::intrinsics::is_aligned_and_not_null;
+
+ assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+ }
+
+ const fn noop<T>(_: *const T) {}
+
+ // SAFETY:
+ //
+ // `rt_check` is just a debug assert to hint users that they are causing UB,
+ // it is not required for safety (the safety must be guatanteed by
+ // the `from_raw_parts[_mut]` caller).
+ //
+ // Since the checks are not required, we ignore them in CTFE as they can't
+ // be done there (alignment does not make much sense there).
+ unsafe {
+ crate::intrinsics::const_eval_select((data,), noop, rt_check);
+ }
+
+ assert!(
+ crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering at least half the address space"
+ );
+}
+
+#[cfg(not(all(not(bootstrap), debug_assertions)))]
+const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
+
/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_ref<T>(s: &T) -> &[T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T] {
array::from_ref(s)
}
/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
array::from_mut(s)
}
/// assert_eq!(1, error.valid_up_to());
/// ```
#[stable(feature = "utf8_error", since = "1.5.0")]
+ #[must_use]
#[inline]
pub fn valid_up_to(&self) -> usize {
self.valid_up_to
///
/// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
#[stable(feature = "utf8_error_error_len", since = "1.20.0")]
+ #[must_use]
#[inline]
pub fn error_len(&self) -> Option<usize> {
self.error_len.map(|len| len as usize)
/// [`char`]: prim@char
/// [`chars`]: str::chars
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chars<'a> {
pub(super) iter: slice::Iter<'a, u8>,
/// [`char`]: prim@char
/// [`char_indices`]: str::char_indices
#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CharIndices<'a> {
pub(super) front_offset: usize,
/// assert_eq!(chars.next(), None);
/// ```
#[inline]
+ #[must_use]
#[unstable(feature = "char_indices_offset", issue = "83871")]
pub fn offset(&self) -> usize {
self.front_offset
/// See its documentation for more.
///
/// [`bytes`]: str::bytes
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone, Debug)]
pub struct Bytes<'a>(pub(super) Copied<slice::Iter<'a, u8>>);
///
/// [`lines`]: str::lines
#[stable(feature = "rust1", since = "1.0.0")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
/// [`lines_any`]: str::lines_any
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
#[allow(deprecated)]
pub struct LinesAny<'a>(pub(super) Lines<'a>);
}
/// Iterator over lossy UTF-8 string
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "str_internals", issue = "none")]
#[allow(missing_debug_implementations)]
pub struct Utf8LossyChunksIter<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_len", since = "1.39.0")]
+ #[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.as_bytes().len()
/// let s = "not empty";
/// assert!(!s.is_empty());
/// ```
- #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")]
+ #[must_use]
+ #[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
+ #[must_use]
#[inline]
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
/// assert_eq!(" Martin-Löf", last);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
pub fn split_at(&self, mid: usize) -> (&str, &str) {
// is_char_boundary checks that the index is in [0, .len()]
/// assert_eq!("PER Martin-Löf", s);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
// is_char_boundary checks that the index is in [0, .len()]
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, the [`rmatch_indices`] method can be used.
///
- /// [`rmatch_indices`]: str::match_indices
+ /// [`rmatch_indices`]: str::rmatch_indices
///
/// # Examples
///
/// assert!(!non_ascii.is_ascii());
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
// We can treat each byte as character here: all multibyte characters
/// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
//! assert_eq!(s.find("you"), Some(4));
//! // char pattern
//! assert_eq!(s.find('n'), Some(2));
+//! // array of chars pattern
+//! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u']), Some(1));
//! // slice of chars pattern
//! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u'][..]), Some(1));
//! // closure pattern
/// assert_eq!("abaaa".find('b'), Some(1));
/// assert_eq!("abaaa".find('c'), None);
///
+/// // &[char; N]
+/// assert_eq!("ab".find(&['b', 'a']), Some(0));
+/// assert_eq!("abaaa".find(&['a', 'z']), Some(0));
+/// assert_eq!("abaaa".find(&['c', 'd']), None);
+///
/// // &[char]
/// assert_eq!("ab".find(&['b', 'a'][..]), Some(0));
/// assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0));
}
}
+impl<const N: usize> MultiCharEq for [char; N] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| m == c)
+ }
+}
+
+impl<const N: usize> MultiCharEq for &[char; N] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| m == c)
+ }
+}
+
impl MultiCharEq for &[char] {
#[inline]
fn matches(&mut self, c: char) -> bool {
};
}
+/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArraySearcher<'a, const N: usize>(
+ <MultiCharEqPattern<[char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
+ <MultiCharEqPattern<&'b [char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// ```
+impl<'a, const N: usize> Pattern<'a> for [char; N] {
+ pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
+}
+
+unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> {
+ searcher_methods!(forward);
+}
+
+unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N> {
+ searcher_methods!(reverse);
+}
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// ```
+impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
+ pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
+}
+
+unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+ searcher_methods!(forward);
+}
+
+unsafe impl<'a, 'b, const N: usize> ReverseSearcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+ searcher_methods!(reverse);
+}
+
/////////////////////////////////////////////////////////////////////////////
// Impl for &[char]
/////////////////////////////////////////////////////////////////////////////
/// Implements substring slicing with syntax `&self[.. end]` or `&mut
/// self[.. end]`.
///
-/// Returns a slice of the given string from the byte range [`0`, `end`).
+/// Returns a slice of the given string from the byte range \[0, `end`).
/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
///
/// This operation is *O*(1).
/// Implements substring slicing with syntax `&self[begin ..]` or `&mut
/// self[begin ..]`.
///
-/// Returns a slice of the given string from the byte range [`begin`,
-/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
-/// len]`.
+/// Returns a slice of the given string from the byte range \[`begin`, `len`).
+/// Equivalent to `&self[begin .. len]` or `&mut self[begin .. len]`.
///
/// This operation is *O*(1).
///
/// Implements substring slicing with syntax `&self[..= end]` or `&mut
/// self[..= end]`.
///
-/// Returns a slice of the given string from the byte range [0, `end`].
+/// Returns a slice of the given string from the byte range \[0, `end`\].
/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
/// value for `usize`.
///
// break if there is a nonascii byte
let zu = contains_nonascii(*block);
let zv = contains_nonascii(*block.offset(1));
- if zu | zv {
+ if zu || zv {
break;
}
}
/// Given a first byte, determines how many bytes are in this UTF-8 character.
#[unstable(feature = "str_internals", issue = "none")]
+#[must_use]
#[inline]
pub fn utf8_char_width(b: u8) -> usize {
UTF8_CHAR_WIDTH[b as usize] as usize
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "atomic_bool_from", since = "1.24.0")]
-impl From<bool> for AtomicBool {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl const From<bool> for AtomicBool {
/// Converts a `bool` into an `AtomicBool`.
///
/// # Examples
#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "atomic_from", since = "1.23.0")]
-impl<T> From<*mut T> for AtomicPtr<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<*mut T> for AtomicPtr<T> {
#[inline]
fn from(p: *mut T) -> Self {
Self::new(p)
}
#[$stable_from]
- impl From<$int_type> for $atomic_type {
+ #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
+ impl const From<$int_type> for $atomic_type {
#[doc = concat!("Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`.")]
#[inline]
fn from(v: $int_type) -> Self { Self::new(v) }
}
#[stable(feature = "futures_api", since = "1.36.0")]
-impl<T> From<T> for Poll<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const From<T> for Poll<T> {
/// Convert to a `Ready` variant.
///
/// # Example
/// Returns a reference to the `Waker` for the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
+ #[must_use]
#[inline]
pub fn waker(&self) -> &'a Waker {
&self.waker
///
/// This function is primarily used for optimization purposes.
#[inline]
+ #[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn will_wake(&self, other: &Waker) -> bool {
self.waker == other.waker
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
#[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_millis(&self) -> u32 {
self.nanos / NANOS_PER_MILLI
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
#[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_micros(&self) -> u32 {
self.nanos / NANOS_PER_MICRO
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_nanos(&self) -> u32 {
self.nanos
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f64(2.7);
} else if nanos >= MAX_NANOS_F64 {
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
} else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ Err(FromSecsError { kind: FromSecsErrorKind::Negative })
} else {
let nanos = nanos as u128;
Ok(Duration {
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f32(2.7);
} else if nanos >= MAX_NANOS_F32 {
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
} else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ Err(FromSecsError { kind: FromSecsErrorKind::Negative })
} else {
let nanos = nanos as u128;
Ok(Duration {
///
/// ```
/// #![feature(duration_checked_float)]
-///
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
impl FromSecsError {
const fn description(&self) -> &'static str {
match self.kind {
- FromSecsErrorKind::NonFinite => {
- "got non-finite value when converting float to duration"
- }
+ FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
FromSecsErrorKind::Overflow => "overflow when converting float to duration",
- FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+ FromSecsErrorKind::Negative => "negative value when converting float to duration",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum FromSecsErrorKind {
- // Value is not a finite value (either infinity or NaN).
+ // Value is not a finite value (either + or - infinity or NaN).
NonFinite,
// Value is too large to store in a `Duration`.
Overflow,
- // Value is less than `0.0`.
- Underflow,
+ // Value is negative.
+ Negative,
}
let value: String = "Hello World!".into();
let arr: &[String; 1] = array::from_ref(&value);
assert_eq!(&[value.clone()], arr);
+
+ const VALUE: &&str = &"Hello World!";
+ const ARR: &[&str; 1] = array::from_ref(VALUE);
+ assert_eq!(&[*VALUE], ARR);
+ assert!(core::ptr::eq(VALUE, &ARR[0]));
}
#[test]
std::panic::set_hook(prev_hook);
result
}
+
+#[test]
+fn array_split_array_mut() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_ref_out_of_bounds() {
+ let v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_mut_out_of_bounds() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_mut::<7>();
+}
#[test]
fn inference_works() {
let x = "a".to_string();
- x.eq_ignore_ascii_case("A");
+ let _ = x.eq_ignore_ascii_case("A");
}
// Shorthands used by the is_ascii_* tests.
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
}
+
+#[test]
+fn atomic_const_from() {
+ const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1);
+ const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true);
+ const _ATOMIC_PTR: AtomicPtr<u32> = AtomicPtr::from(core::ptr::null_mut());
+}
const CELL: Cell<i32> = Cell::new(3);
const _: i32 = CELL.into_inner();
+
+ const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
+ const _: i32 = UNSAFE_CELL.into_inner();
+
+ const REF_CELL_FROM: RefCell<i32> = RefCell::from(3);
+ const _: i32 = REF_CELL.into_inner();
+
+ const CELL_FROM: Cell<i32> = Cell::from(3);
+ const _: i32 = CELL.into_inner();
}
#[test]
fn test_convert() {
assert_eq!(u32::from('a'), 0x61);
+ assert_eq!(u64::from('b'), 0x62);
+ assert_eq!(u128::from('c'), 0x63);
assert_eq!(char::from(b'\0'), '\0');
assert_eq!(char::from(b'a'), 'a');
assert_eq!(char::from(b'\xFF'), '\u{FF}');
assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
}
+#[test]
+const fn test_convert_const() {
+ assert!(u32::from('a') == 0x61);
+ assert!(u64::from('b') == 0x62);
+ assert!(u128::from('c') == 0x63);
+ assert!(char::from(b'\0') == '\0');
+ assert!(char::from(b'a') == 'a');
+ assert!(char::from(b'\xFF') == '\u{FF}');
+}
+
#[test]
fn test_from_str() {
assert_eq!(char::from_str("a").unwrap(), 'a');
assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
assert_eq!("0.0", format!("{:?}", 0.0f64));
assert_eq!("1.01", format!("{:?}", 1.01f64));
+
+ let high_cutoff = 1e16_f64;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f64));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f64));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f64));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64));
}
#[test]
assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32));
assert_eq!("0.0", format!("{:?}", 0.0f32));
assert_eq!("1.01", format!("{:?}", 1.01f32));
+
+ let high_cutoff = 1e16_f32;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f32));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f32));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f32));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32));
+}
+
+fn is_exponential(s: &str) -> bool {
+ s.contains("e") || s.contains("E")
}
drop(x);
}
+#[test]
+const fn once_cell_const() {
+ let _once_cell: OnceCell<u32> = OnceCell::new();
+ let _once_cell: OnceCell<u32> = OnceCell::from(32);
+}
+
#[test]
fn clone() {
let s = OnceCell::new();
#![feature(cfg_target_has_atomic)]
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
+#![feature(const_convert)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_raw_ptr_deref)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
-#![feature(option_result_unwrap_unchecked)]
#![feature(result_into_ok_or_err)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
#![feature(unsized_tuple_coercion)]
#![feature(const_option)]
+#![feature(const_result)]
#![feature(integer_atomics)]
#![feature(int_roundings)]
#![feature(slice_group_by)]
+#![feature(split_array)]
#![feature(trusted_random_access)]
#![feature(unsize)]
#![feature(unzip_option)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
// test that the methods of `NonZeroX>` are usable in a const context
// Note: only tests NonZero8
- const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
+ const NONZERO_U8: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
- const GET: u8 = NONZERO.get();
+ const GET: u8 = NONZERO_U8.get();
assert_eq!(GET, 5);
const ZERO: Option<NonZeroU8> = NonZeroU8::new(0);
const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
assert!(ONE.is_some());
+
+ const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8);
+ assert_eq!(FROM_NONZERO_U8, 5);
+
+ const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8);
+ assert_eq!(NONZERO_CONVERT.get(), 5);
}
#[test]
// test that the methods of `Option` are usable in a const context
const OPTION: Option<usize> = Some(32);
+ assert_eq!(OPTION, Some(32));
+
+ const OPTION_FROM: Option<usize> = Option::from(32);
+ assert_eq!(OPTION_FROM, Some(32));
const REF: Option<&usize> = OPTION.as_ref();
assert_eq!(REF, Some(&32));
+ const REF_FROM: Option<&usize> = Option::from(&OPTION);
+ assert_eq!(REF_FROM, Some(&32));
+
const IS_SOME: bool = OPTION.is_some();
assert!(IS_SOME);
let _take = option.take();
let _replace = option.replace(42);
+
+ {
+ let as_mut = option.as_mut();
+ match as_mut {
+ Some(v) => *v = 32,
+ None => unreachable!(),
+ }
+ }
+
+ {
+ let as_mut: Option<&mut usize> = Option::from(&mut option);
+ match as_mut {
+ Some(v) => *v = 42,
+ None => unreachable!(),
+ }
+ }
}
#[test]
assert!(!IS_ERR)
}
+#[test]
+const fn result_const_mut() {
+ let mut result: Result<usize, bool> = Ok(32);
+
+ {
+ let as_mut = result.as_mut();
+ match as_mut {
+ Ok(v) => *v = 42,
+ Err(_) => unreachable!(),
+ }
+ }
+
+ let mut result_err: Result<usize, bool> = Err(false);
+
+ {
+ let as_mut = result_err.as_mut();
+ match as_mut {
+ Ok(_) => unreachable!(),
+ Err(v) => *v = true,
+ }
+ }
+}
+
#[test]
fn result_opt_conversions() {
#[derive(Copy, Clone, Debug, PartialEq)]
assert_eq!(x.get(), 1);
}
+#[test]
+fn test_const_from_ref() {
+ const VALUE: &i32 = &1;
+ const SLICE: &[i32] = core::slice::from_ref(VALUE);
+
+ assert!(core::ptr::eq(VALUE, &SLICE[0]))
+}
+
#[test]
fn test_slice_fill_with_uninit() {
// This should not UB. See #87891
x.swap(2, 5);
}
}
+
+#[test]
+fn slice_split_array_mut() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, []);
+ }
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_ref_out_of_bounds() {
+ let v = &[1, 2, 3, 4, 5, 6][..];
+
+ v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_mut_out_of_bounds() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ v.split_array_mut::<7>();
+}
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.44" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
+#[must_use]
pub struct Backtrace {
inner: Inner,
}
/// Returns the status of this backtrace, indicating whether this backtrace
/// request was unsupported, disabled, or a stack trace was actually
/// captured.
+ #[must_use]
pub fn status(&self) -> BacktraceStatus {
match self.inner {
Inner::Unsupported => BacktraceStatus::Unsupported,
impl<'a> Backtrace {
/// Returns an iterator over the backtrace frames.
+ #[must_use]
#[unstable(feature = "backtrace_frames", issue = "79676")]
pub fn frames(&'a self) -> &'a [BacktraceFrame] {
if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
/// Gets a reference to the key in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn key(&self) -> &K {
self.base.key()
/// Gets a mutable reference to the key in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn key_mut(&mut self) -> &mut K {
self.base.key_mut()
/// Gets a reference to the value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get(&self) -> &V {
self.base.get()
/// Gets a mutable reference to the value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get_mut(&mut self) -> &mut V {
self.base.get_mut()
/// Gets a reference to the key and value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get_key_value(&mut self) -> (&K, &V) {
self.base.get_key_value()
/// determined by the [`Eq`] trait, changes while it is in the set. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
/// unsafe code. The behavior resulting from such a logic error is not
-/// specified, but will not result in undefined behavior. This could include
-/// panics, incorrect results, aborts, memory leaks, and non-termination.
+/// specified (it could include panics, incorrect results, aborts, memory
+/// leaks, or non-termination) but will not be undefined behavior.
///
/// # Examples
///
///
/// let mut intersection = a.intersection(&b);
/// ```
+#[must_use = "this returns the intersection as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Intersection<'a, T: 'a, S: 'a> {
// iterator of the first set
///
/// let mut difference = a.difference(&b);
/// ```
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Difference<'a, T: 'a, S: 'a> {
// iterator of the first set
///
/// let mut intersection = a.symmetric_difference(&b);
/// ```
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
///
/// let mut union_iter = a.union(&b);
/// ```
+#[must_use = "this returns the union as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Union<'a, T: 'a, S: 'a> {
iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
/// ```
///
/// [`env::vars_os()`]: vars_os
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn vars() -> Vars {
Vars { inner: vars_os() }
/// println!("{:?}: {:?}", key, value);
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn vars_os() -> VarsOs {
VarsOs { inner: os_imp::env() }
/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
_var_os(key.as_ref())
/// documentation for more.
///
/// [`env::split_paths()`]: split_paths
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct SplitPaths<'a> {
inner: os_imp::SplitPaths<'a>,
reason = "This function's behavior is unexpected and probably not what you want. \
Consider using a crate from crates.io instead."
)]
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn home_dir() -> Option<PathBuf> {
os_imp::home_dir()
/// println!("Temporary directory: {}", dir.display());
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn temp_dir() -> PathBuf {
os_imp::temp_dir()
/// should not be relied upon for security purposes.
///
/// [`env::args()`]: args
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct Args {
inner: ArgsOs,
/// should not be relied upon for security purposes.
///
/// [`env::args_os()`]: args_os
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct ArgsOs {
inner: sys::args::Args,
pub fn atanh(self) -> f32 {
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
-
- /// Linear interpolation between `start` and `end`.
- ///
- /// This enables linear interpolation between `start` and `end`, where start is represented by
- /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
- /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
- /// at a given rate, the result will change from `start` to `end` at a similar rate.
- ///
- /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
- /// range from `start` to `end`. This also is useful for transition functions which might
- /// move slightly past the end or start for a desired effect. Mathematically, the values
- /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
- /// guarantees that are useful specifically to linear interpolation.
- ///
- /// These guarantees are:
- ///
- /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
- /// value at 1.0 is always `end`. (exactness)
- /// * If `start` and `end` are [finite], the values will always move in the direction from
- /// `start` to `end` (monotonicity)
- /// * If `self` is [finite] and `start == end`, the value at any point will always be
- /// `start == end`. (consistency)
- ///
- /// [finite]: #method.is_finite
- #[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "float_interpolation", issue = "86269")]
- pub fn lerp(self, start: f32, end: f32) -> f32 {
- // consistent
- if start == end {
- start
-
- // exact/monotonic
- } else {
- self.mul_add(end, (-self).mul_add(start, start))
- }
- }
}
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
-
-#[test]
-fn test_lerp_exact() {
- // simple values
- assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
- assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
-
- // boundary values
- assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
- assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
- assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
- assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
-
- // as long as t is finite, a/b can be infinite
- assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY);
- assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
- // non-finite t is not NaN if a/b different
- assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan());
- assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
- // just a few basic values
- assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
- assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
- assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
- // near 0
- let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX);
- let zero = f32::lerp(0.0, f32::MIN, f32::MAX);
- let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_zero <= zero);
- assert!(zero <= above_zero);
- assert!(below_zero <= above_zero);
-
- // near 0.5
- let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX);
- let half = f32::lerp(0.5, f32::MIN, f32::MAX);
- let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_half <= half);
- assert!(half <= above_half);
- assert!(below_half <= above_half);
-
- // near 1
- let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX);
- let one = f32::lerp(1.0, f32::MIN, f32::MAX);
- let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_one <= one);
- assert!(one <= above_one);
- assert!(below_one <= above_one);
-}
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
- /// Linear interpolation between `start` and `end`.
- ///
- /// This enables linear interpolation between `start` and `end`, where start is represented by
- /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
- /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
- /// at a given rate, the result will change from `start` to `end` at a similar rate.
- ///
- /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
- /// range from `start` to `end`. This also is useful for transition functions which might
- /// move slightly past the end or start for a desired effect. Mathematically, the values
- /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
- /// guarantees that are useful specifically to linear interpolation.
- ///
- /// These guarantees are:
- ///
- /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
- /// value at 1.0 is always `end`. (exactness)
- /// * If `start` and `end` are [finite], the values will always move in the direction from
- /// `start` to `end` (monotonicity)
- /// * If `self` is [finite] and `start == end`, the value at any point will always be
- /// `start == end`. (consistency)
- ///
- /// [finite]: #method.is_finite
- #[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "float_interpolation", issue = "86269")]
- pub fn lerp(self, start: f64, end: f64) -> f64 {
- // consistent
- if start == end {
- start
-
- // exact/monotonic
- } else {
- self.mul_add(end, (-self).mul_add(start, start))
- }
- }
-
// Solaris/Illumos requires a wrapper around log, log2, and log10 functions
// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
// of expected NaN).
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
-
-#[test]
-fn test_lerp_exact() {
- // simple values
- assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
- assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
-
- // boundary values
- assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
- assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
- assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
- assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
-
- // as long as t is finite, a/b can be infinite
- assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY);
- assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
- // non-finite t is not NaN if a/b different
- assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan());
- assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
- // just a few basic values
- assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
- assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
- assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
- // near 0
- let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX);
- let zero = f64::lerp(0.0, f64::MIN, f64::MAX);
- let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX);
- assert!(below_zero <= zero);
- assert!(zero <= above_zero);
- assert!(below_zero <= above_zero);
-
- // near 1
- let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX);
- let one = f64::lerp(1.0, f64::MIN, f64::MAX);
- let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX);
- assert!(below_one <= one);
- assert!(one <= above_one);
- assert!(below_one <= above_one);
-}
/// # Examples
///
/// ```
-/// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::{CString, FromVecWithNulError};
///
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub struct FromVecWithNulError {
error_kind: FromBytesWithNulErrorKind,
bytes: Vec<u8>,
}
}
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
impl FromVecWithNulError {
/// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
///
/// Basic usage:
///
/// ```
- /// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::CString;
///
/// // Some invalid bytes in a vector
/// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
/// ```
#[must_use]
+ #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
/// Basic usage:
///
/// ```
- /// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::CString;
///
/// // Some invalid bytes in a vector
/// assert_eq!(bytes, value.unwrap_err().into_bytes());
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
+ #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
/// # Example
///
/// ```
- /// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::CString;
/// assert_eq!(
/// unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
/// );
/// ```
#[must_use]
- #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+ #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
Self { inner: v.into_boxed_slice() }
}
/// when called without the ending nul byte.
///
/// ```
- /// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::CString;
/// assert_eq!(
/// CString::from_vec_with_nul(b"abc\0".to_vec())
/// An incorrectly formatted [`Vec`] will produce an error.
///
/// ```
- /// #![feature(cstring_from_vec_with_nul)]
/// use std::ffi::{CString, FromVecWithNulError};
/// // Interior nul byte
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
/// // No nul byte
/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
/// ```
- #[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+ #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
let nul_pos = memchr::memchr(0, &v);
match nul_pos {
/// let nul_error = CString::new("foo bar\0").unwrap_err();
/// assert_eq!(nul_error.nul_position(), 7);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn nul_position(&self) -> usize {
self.0
}
}
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
impl Error for FromVecWithNulError {}
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
impl fmt::Display for FromVecWithNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.error_kind {
}
/// Access the underlying UTF-8 error that was the cause of this error.
+ #[must_use]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn utf8_error(&self) -> Utf8Error {
self.error
/// }
/// # }
/// ```
+ #[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
#[inline]
#[must_use]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
+ #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
// SAFETY: Casting to CStr is safe because its internal representation
// is a [u8] too (safe only inside std).
/// let boxed = c_string.into_boxed_c_str();
/// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
pub fn into_c_string(self: Box<CStr>) -> CString {
let raw = Box::into_raw(self) as *mut [u8];
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub use self::c_str::FromBytesWithNulError;
-#[unstable(feature = "cstring_from_vec_with_nul", issue = "73179")]
+#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")]
pub use self::c_str::FromVecWithNulError;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::c_str::{CStr, CString, IntoStringError, NulError};
/// assert!(os_string.capacity() >= 10);
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
/// assert!(!os_str.is_empty());
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.inner.is_empty()
/// assert_eq!(os_str.len(), 3);
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn len(&self) -> usize {
self.inner.inner.len()
/// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
#[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
pub fn into_os_string(self: Box<OsStr>) -> OsString {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
OsString { inner: Buf::from_box(boxed) }
/// assert!(!non_ascii.is_ascii());
/// ```
#[stable(feature = "osstring_ascii", since = "1.53.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
self.inner.is_ascii()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[unstable(feature = "with_options", issue = "65439")]
pub fn with_options() -> OpenOptions {
OpenOptions::new()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "file_type", since = "1.1.0")]
pub fn file_type(&self) -> FileType {
FileType(self.0.file_type())
///
#[cfg_attr(unix, doc = "```no_run")]
#[cfg_attr(not(unix), doc = "```ignore")]
- /// #![feature(is_symlink)]
/// use std::fs;
/// use std::path::Path;
/// use std::os::unix::fs::symlink;
/// }
/// ```
#[must_use]
- #[unstable(feature = "is_symlink", issue = "85748")]
+ #[stable(feature = "is_symlink", since = "1.57.0")]
pub fn is_symlink(&self) -> bool {
self.file_type().is_symlink()
}
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> u64 {
self.0.size()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn permissions(&self) -> Permissions {
Permissions(self.0.perm())
/// Ok(())
/// }
/// ```
+ #[must_use = "call `set_readonly` to modify the readonly flag"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn readonly(&self) -> bool {
self.0.readonly()
/// ```
///
/// The exact text, of course, depends on what files you have in `.`.
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn path(&self) -> PathBuf {
self.0.path()
/// }
/// }
/// ```
+ #[must_use]
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub fn file_name(&self) -> OsString {
self.0.file_name()
// "hard_link" should still appear as a symlink.
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
}
+
+/// Ensure `fs::create_dir` works on Windows with longer paths.
+#[test]
+#[cfg(windows)]
+fn create_dir_long_paths() {
+ use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt};
+ const PATH_LEN: usize = 247;
+
+ let tmpdir = tmpdir();
+ let mut path = tmpdir.path().to_path_buf();
+ path.push("a");
+ let mut path = path.into_os_string();
+
+ let utf16_len = path.encode_wide().count();
+ if utf16_len >= PATH_LEN {
+ // Skip the test in the unlikely event the local user has a long temp directory path.
+ // This should not affect CI.
+ return;
+ }
+ // Increase the length of the path.
+ path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len));
+
+ // This should succeed.
+ fs::create_dir(&path).unwrap();
+
+ // This will fail if the path isn't converted to verbatim.
+ path.push("a");
+ fs::create_dir(&path).unwrap();
+}
/// println!("last OS error: {:?}", Error::last_os_error());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn last_os_error() -> Error {
Error::from_raw_os_error(sys::os::errno() as i32)
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
+ #[must_use]
#[inline]
pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
match self.repr {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
+ #[must_use]
#[inline]
pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
match self.repr {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn kind(&self) -> ErrorKind {
match self.repr {
const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
-pub(crate) fn cleanup() {
- stdio::cleanup()
-}
+pub(crate) use stdio::cleanup;
struct Guard<'a> {
buf: &'a mut Vec<u8>,
impl Initializer {
/// Returns a new `Initializer` which will zero out buffers.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub fn zeroing() -> Initializer {
Initializer(true)
/// the method accurately reflects the number of bytes that have been
/// written to the head of the buffer.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub unsafe fn nop() -> Initializer {
Initializer(false)
/// Indicates if a buffer should be initialized.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub fn should_initialize(&self) -> bool {
self.0
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
/// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
/// }
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "stdin_forwarders", issue = "87096")]
pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
self.into_locked().split(byte)
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
Stdout {
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
// Note that unlike `stdout()` we don't use `at_exit` here to register a
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
#![feature(const_cstr_unchecked)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
+#![feature(const_fn_trait_bound)]
#![feature(const_format_args)]
#![feature(const_io_structs)]
#![feature(const_ip)]
#![feature(custom_test_frameworks)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
#![feature(doc_keyword)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
#![feature(extend_one)]
-#![feature(float_interpolation)]
#![feature(fn_traits)]
#![feature(format_args_nl)]
#![feature(gen_future)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
#![feature(needs_panic_runtime)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
-#![feature(saturating_div)]
#![feature(saturating_int_impl)]
#![feature(slice_concat_ext)]
#![feature(slice_internals)]
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
/// ```
+ #[must_use]
#[stable(feature = "ip_addr", since = "1.7.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> IpAddr {
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv4Addr {
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
/// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv6Addr {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
/// assert_eq!(socket.flowinfo(), 10);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn flowinfo(&self) -> u32 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
/// assert_eq!(socket.scope_id(), 78);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn scope_id(&self) -> u32 {
///
/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
/// notation, divided by `.` (this is called "dot-decimal notation").
-/// Notably, octal numbers and hexadecimal numbers are not allowed per [IETF RFC 6943].
+/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
+/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
///
/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
/// [`FromStr`]: crate::str::FromStr
/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
/// assert_eq!(localhost.is_loopback(), true);
+/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
+/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
+/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
/// ```
#[derive(Copy)]
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 4] {
// This returns the order we want because s_addr is stored in big-endian.
/// ```
#[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub const fn segments(&self) -> [u16; 8] {
// All elements in `s6_addr` must be big endian.
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
+ #[must_use]
#[inline]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
/// ```
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
#[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+ #[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 16] {
self.inner.s6_addr
// no number between dots
let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
assert_eq!(None, none);
+ // octal
+ let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
+ assert_eq!(None, none);
+ // octal zero
+ let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
+ assert_eq!(None, none);
+ let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
+ assert_eq!(None, none);
}
#[test]
&mut self,
radix: u32,
max_digits: Option<usize>,
+ allow_zero_prefix: bool,
) -> Option<T> {
self.read_atomically(move |p| {
let mut result = T::ZERO;
let mut digit_count = 0;
+ let has_leading_zero = p.peek_char() == Some('0');
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
result = result.checked_mul(radix)?;
}
}
- if digit_count == 0 { None } else { Some(result) }
+ if digit_count == 0 {
+ None
+ } else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
+ None
+ } else {
+ Some(result)
+ }
})
}
*slot = p.read_separator('.', i, |p| {
// Disallow octal number in IP string.
// https://tools.ietf.org/html/rfc6943#section-3.1.1
- match (p.peek_char(), p.read_number(10, None)) {
- (Some('0'), Some(number)) if number != 0 => None,
- (_, number) => number,
- }
+ p.read_number(10, Some(3), false)
})?;
}
}
}
- let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
+ let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
match group {
Some(g) => *slot = g,
fn read_port(&mut self) -> Option<u16> {
self.read_atomically(|p| {
p.read_given_char(':')?;
- p.read_number(10, None)
+ p.read_number(10, None, true)
})
}
fn read_scope_id(&mut self) -> Option<u32> {
self.read_atomically(|p| {
p.read_given_char('%')?;
- p.read_number(10, None)
+ p.read_number(10, None, true)
})
}
impl FromStr for Ipv4Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+ // don't try to parse if too long
+ if s.len() > 15 {
+ Err(AddrParseError(()))
+ } else {
+ Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+ }
}
}
/// See its documentation for more.
///
/// [`accept`]: TcpListener::accept
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Incoming<'a> {
#[unstable(feature = "c_size_t", issue = "88345")]
pub type c_size_t = usize;
-/// Equivalent to C's `ssize_t` type, from `stddef.h` (or `cstddef` for C++).
+/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
+///
+/// This type is currently always [`isize`], however in the future there may be
+/// platforms where this is not the case.
+#[unstable(feature = "c_size_t", issue = "88345")]
+pub type c_ptrdiff_t = isize;
+
+/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
///
/// This type is currently always [`isize`], however in the future there may be
/// platforms where this is not the case.
}
/// Get the current PID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_pid(&self) -> libc::pid_t {
self.0.pid
}
/// Get the current UID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_uid(&self) -> libc::uid_t {
self.0.uid
}
/// Get the current GID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_gid(&self) -> libc::gid_t {
self.0.gid
}
/// This struct is used to iterate through the control messages.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct Messages<'a> {
buffer: &'a [u8],
}
/// Returns the capacity of the buffer.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn capacity(&self) -> usize {
self.buffer.len()
}
/// Returns `true` if the ancillary data is empty.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn is_empty(&self) -> bool {
self.length == 0
}
/// Returns the number of used bytes.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn len(&self) -> usize {
self.length
/// Ok(())
/// }
/// ```
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn truncated(&self) -> bool {
self.truncated
/// }
/// ```
#[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "unix_socket", since = "1.10.0")]
pub struct Incoming<'a> {
listener: &'a UnixListener,
fn signal(&self) -> Option<i32>;
/// If the process was terminated by a signal, says whether it dumped core.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn core_dumped(&self) -> bool;
/// If the process was stopped by a signal, returns that signal.
///
/// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from
/// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn stopped_signal(&self) -> Option<i32>;
/// Whether the process was continued from a stopped status.
///
/// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call
/// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn continued(&self) -> bool;
/// Returns the underlying raw `wait` status.
///
/// The returned integer is a **wait status, not an exit status**.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn into_raw(self) -> i32;
}
}
/// Returns the OS-assigned process identifier associated with this process's parent.
+#[must_use]
#[stable(feature = "unix_ppid", since = "1.27.0")]
pub fn parent_id() -> u32 {
crate::sys::os::getppid()
$crate::rt::panic_display(&$arg)
}),
($fmt:expr, $($arg:tt)+) => ({
- $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+))
+ $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
}),
}
///
/// panic!("Normal panic");
/// ```
+#[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
if thread::panicking() {
}
// Disregards ALWAYS_ABORT_FLAG
+ #[must_use]
pub fn get_count() -> usize {
LOCAL_PANIC_COUNT.with(|c| c.get())
}
// Disregards ALWAYS_ABORT_FLAG
+ #[must_use]
#[inline]
pub fn count_is_zero() -> bool {
if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 {
!panic_count::count_is_zero()
}
-/// The entry point for panicking with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
-#[cold]
-// If panic_immediate_abort, inline the abort call,
-// otherwise avoid inlining because of it is cold path.
-#[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)]
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cfg_attr(not(test), lang = "begin_panic_fmt")]
-pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
- if cfg!(feature = "panic_immediate_abort") {
- intrinsics::abort()
- }
-
- let info = PanicInfo::internal_constructor(Some(msg), Location::caller());
- begin_panic_handler(&info)
-}
-
/// Entry point of panics from the libcore crate (`panic_impl` lang item).
-#[cfg_attr(not(test), panic_handler)]
+#[cfg(not(test))]
+#[panic_handler]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
struct PanicPayload<'a> {
inner: &'a fmt::Arguments<'a>,
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cold]
#[track_caller]
-pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
if cfg!(feature = "panic_immediate_abort") {
intrinsics::abort()
}
/// See [`Prefix`]'s documentation for more information on the different
/// kinds of prefixes.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn kind(&self) -> Prefix<'a> {
self.parsed
///
/// [`components`]: Path::components
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Components<'a> {
// The path left to parse components from
///
/// [`iter`]: Path::iter
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a> {
inner: Components<'a>,
///
/// [`ancestors`]: Path::ancestors
#[derive(Copy, Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
/// * if `path` has a root but no prefix (e.g., `\windows`), it
/// replaces everything except for the prefix (if any) of `self`.
/// * if `path` has a prefix but no root, it replaces `self`.
+ /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
+ /// and `path` is not empty, the new path is normalized: all references
+ /// to `.` and `..` are removed.
///
/// # Examples
///
self.as_mut_vec().truncate(0);
// verbatim paths need . and .. removed
- } else if comps.prefix_verbatim() {
+ } else if comps.prefix_verbatim() && !path.inner.is_empty() {
let mut buf: Vec<_> = comps.collect();
for c in path.components() {
match c {
///
/// [`capacity`]: OsString::capacity
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
+ #[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
/// assert_eq!(grand_parent.parent(), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn parent(&self) -> Option<&Path> {
let mut comps = self.components();
let comp = comps.next_back();
/// assert_eq!(None, Path::new("/").file_name());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn file_name(&self) -> Option<&OsStr> {
self.components().next_back().and_then(|p| match p {
Component::Normal(p) => Some(p),
/// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
self._starts_with(base.as_ref())
}
/// assert!(!path.ends_with("conf")); // use .extension() instead
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
self._ends_with(child.as_ref())
}
/// [`Path::file_prefix`]: Path::file_prefix
///
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn file_stem(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
}
/// [`Path::file_stem`]: Path::file_stem
///
#[unstable(feature = "path_file_prefix", issue = "86319")]
+ #[must_use]
pub fn file_prefix(&self) -> Option<&OsStr> {
self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
}
/// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn extension(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
}
/// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
self._with_file_name(file_name.as_ref())
}
/// This is a convenience function that coerces errors to false. If you want to
/// check errors, call [`fs::metadata`].
#[stable(feature = "path_ext", since = "1.5.0")]
+ #[must_use]
#[inline]
pub fn exists(&self) -> bool {
fs::metadata(self).is_ok()
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
- /// Returns true if the path exists on disk and is pointing at a symbolic link.
+ /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
///
/// This function will not traverse symbolic links.
/// In case of a broken symbolic link this will also return true.
///
#[cfg_attr(unix, doc = "```no_run")]
#[cfg_attr(not(unix), doc = "```ignore")]
- /// #![feature(is_symlink)]
/// use std::path::Path;
/// use std::os::unix::fs::symlink;
///
/// assert_eq!(link_path.is_symlink(), true);
/// assert_eq!(link_path.exists(), false);
/// ```
- #[unstable(feature = "is_symlink", issue = "85748")]
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
+ /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
#[must_use]
+ #[stable(feature = "is_symlink", since = "1.57.0")]
pub fn is_symlink(&self) -> bool {
fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
}
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
/// allocating.
#[stable(feature = "into_boxed_path", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
let rw = Box::into_raw(self) as *mut OsStr;
let inner = unsafe { Box::from_raw(rw) };
tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo");
tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo");
tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo");
+ tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\");
}
}
/// let cmd = Command::new("echo");
/// assert_eq!(cmd.get_program(), "echo");
/// ```
+ #[must_use]
#[stable(feature = "command_access", since = "1.57.0")]
pub fn get_program(&self) -> &OsStr {
self.inner.get_program()
/// cmd.current_dir("/bin");
/// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")));
/// ```
+ #[must_use]
#[stable(feature = "command_access", since = "1.57.0")]
pub fn get_current_dir(&self) -> Option<&Path> {
self.inner.get_current_dir()
///
/// This struct is created by [`Command::get_args`]. See its documentation for
/// more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
#[derive(Debug)]
pub struct CommandArgs<'a> {
/// its entire stdin before writing more than a pipe buffer's worth of output.
/// The size of a pipe buffer varies on different targets.
///
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn piped() -> Stdio {
Stdio(imp::Stdio::MakePipe)
/// print!("You piped in the reverse of: ");
/// io::stdout().write_all(&output.stdout).unwrap();
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn inherit() -> Stdio {
Stdio(imp::Stdio::Inherit)
/// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
/// // Ignores any piped-in input
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn null() -> Stdio {
Stdio(imp::Stdio::Null)
/// println!("failed to create 'projects/' directory: {}", status);
/// }
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn success(&self) -> bool {
self.0.exit_ok().is_ok()
/// None => println!("Process terminated by signal")
/// }
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn code(&self) -> Option<i32> {
self.0.code()
/// assert_eq!(bad.code(), Some(1));
/// # } // #[cfg(unix)]
/// ```
+ #[must_use]
pub fn code(&self) -> Option<i32> {
self.code_nonzero().map(Into::into)
}
/// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap());
/// # } // cfg!(unix)
/// ```
+ #[must_use]
pub fn code_nonzero(&self) -> Option<NonZeroI32> {
self.0.code()
}
/// Converts an `ExitStatusError` (back) to an `ExitStatus`.
+ #[must_use]
pub fn into_status(&self) -> ExitStatus {
ExitStatus(self.0.into())
}
/// println!("ls command didn't start");
/// }
/// ```
+ #[must_use]
#[stable(feature = "process_id", since = "1.3.0")]
pub fn id(&self) -> u32 {
self.handle.id()
/// ```
///
///
+#[must_use]
#[stable(feature = "getpid", since = "1.26.0")]
pub fn id() -> u32 {
crate::sys::os::getpid()
use crate::ffi::CString;
// Re-export some of our utilities which are expected by other crates.
-pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};
-pub use core::panicking::panic_display;
+pub use crate::panicking::{begin_panic, panic_count};
+pub use core::panicking::{panic_display, panic_fmt};
use crate::sync::Once;
use crate::sys;
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
.map_err(move |e| {
mem::forget(e);
- rtprintpanic!("drop of the panic payload panicked");
- sys::abort_internal()
+ rtabort!("drop of the panic payload panicked");
});
panic::catch_unwind(cleanup).map_err(rt_abort)?;
ret_code
if lock.count < self.num_threads {
// We need a while loop to guard against spurious wakeups.
// https://en.wikipedia.org/wiki/Spurious_wakeup
- while local_gen == lock.generation_id && lock.count < self.num_threads {
+ while local_gen == lock.generation_id {
lock = self.cvar.wait(lock).unwrap();
}
BarrierWaitResult(false)
/// }
/// }
/// ```
+ #[must_use]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn timed_out(&self) -> bool {
self.0
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(align(64))]
-pub(super) struct Aligner;
-
-#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+pub(super) struct CacheAligned<T>(pub T);
impl<T> Deref for CacheAligned<T> {
type Target = T;
impl<T> CacheAligned<T> {
pub(super) fn new(t: T) -> Self {
- CacheAligned(t, Aligner)
+ CacheAligned(t)
}
}
/// // Let's see what that answer was
/// println!("{:?}", receiver.recv().unwrap());
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(oneshot::Packet::new());
/// assert_eq!(receiver.recv().unwrap(), 1);
/// assert_eq!(receiver.recv().unwrap(), 2);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(sync::Packet::new(bound));
mutex.lock();
}
- pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
- panic!("wait_timeout not supported on hermit");
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ self.counter.fetch_add(1, SeqCst);
+ mutex.unlock();
+ let millis = dur.as_millis().min(u32::MAX as u128) as u32;
+
+ let res = if millis > 0 {
+ abi::sem_timedwait(self.sem1, millis)
+ } else {
+ abi::sem_trywait(self.sem1)
+ };
+
+ abi::sem_post(self.sem2);
+ mutex.lock();
+ res == 0
}
pub unsafe fn destroy(&self) {
Ok(self.clone())
}
- pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+ pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
unsupported()
}
unsafe { crate::hint::unreachable_unchecked() };
}
-pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
super::unsupported()
}
pub use self::imp::init;
pub struct Handler {
- _data: *mut libc::c_void,
+ data: *mut libc::c_void,
}
impl Handler {
}
fn null() -> Handler {
- Handler { _data: crate::ptr::null_mut() }
+ Handler { data: crate::ptr::null_mut() }
}
}
impl Drop for Handler {
fn drop(&mut self) {
unsafe {
- drop_handler(self);
+ drop_handler(self.data);
}
}
}
}
let handler = make_handler();
- MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
+ MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
mem::forget(handler);
}
pub unsafe fn cleanup() {
- Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
+ drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed));
}
unsafe fn get_stackp() -> *mut libc::c_void {
if stack.ss_flags & SS_DISABLE != 0 {
stack = get_stack();
sigaltstack(&stack, ptr::null_mut());
- Handler { _data: stack.ss_sp as *mut libc::c_void }
+ Handler { data: stack.ss_sp as *mut libc::c_void }
} else {
Handler::null()
}
}
- pub unsafe fn drop_handler(handler: &mut Handler) {
- if !handler._data.is_null() {
+ pub unsafe fn drop_handler(data: *mut libc::c_void) {
+ if !data.is_null() {
let stack = libc::stack_t {
ss_sp: ptr::null_mut(),
ss_flags: SS_DISABLE,
sigaltstack(&stack, ptr::null_mut());
// We know from `get_stackp` that the alternate stack we installed is part of a mapping
// that started one page earlier, so walk back a page and unmap from there.
- munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
+ munmap(data.sub(page_size()), SIGSTKSZ + page_size());
}
}
}
super::Handler::null()
}
- pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
+ pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
}
pub fn actually_monotonic() -> bool {
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
|| (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
+ || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
|| cfg!(target_os = "fuchsia")
}
cchCount2: c_int,
bIgnoreCase: BOOL,
) -> c_int;
+ pub fn GetFullPathNameW(
+ lpFileName: LPCWSTR,
+ nBufferLength: DWORD,
+ lpBuffer: LPWSTR,
+ lpFilePart: *mut LPWSTR,
+ ) -> DWORD;
}
#[link(name = "ws2_32")]
use crate::sys::{c, cvt};
use crate::sys_common::{AsInner, FromInner, IntoInner};
+use super::path::maybe_verbatim;
use super::to_u16s;
pub struct File {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
- let path = to_u16s(path)?;
+ let path = maybe_verbatim(path)?;
let handle = unsafe {
c::CreateFileW(
path.as_ptr(),
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
cvt(unsafe { c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let root = p.to_path_buf();
let star = p.join("*");
- let path = to_u16s(&star)?;
+ let path = maybe_verbatim(&star)?;
unsafe {
let mut wfd = mem::zeroed();
}
pub fn unlink(p: &Path) -> io::Result<()> {
- let p_u16s = to_u16s(p)?;
+ let p_u16s = maybe_verbatim(p)?;
cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?;
Ok(())
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
- let old = to_u16s(old)?;
- let new = to_u16s(new)?;
+ let old = maybe_verbatim(old)?;
+ let new = maybe_verbatim(new)?;
cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?;
Ok(())
}
pub fn rmdir(p: &Path) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
Ok(())
}
pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> {
let original = to_u16s(original)?;
- let link = to_u16s(link)?;
+ let link = maybe_verbatim(link)?;
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
// Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
// Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
#[cfg(not(target_vendor = "uwp"))]
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
- let original = to_u16s(original)?;
- let link = to_u16s(link)?;
+ let original = maybe_verbatim(original)?;
+ let link = maybe_verbatim(link)?;
cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
}
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
unsafe {
cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
Ok(())
}
c::PROGRESS_CONTINUE
}
- let pfrom = to_u16s(from)?;
- let pto = to_u16s(to)?;
+ let pfrom = maybe_verbatim(from)?;
+ let pto = maybe_verbatim(to)?;
let mut size = 0i64;
cvt(unsafe {
c::CopyFileExW(
#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
unsafe {
+ // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
+ // instead of us having to go through these multiple steps to get a token. However this is
+ // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
+ // we can simplify this code. See #90144 for details.
use crate::sys::handle::Handle;
let me = c::GetCurrentProcess();
+use super::{c, fill_utf16_buf, to_u16s};
use crate::ffi::OsStr;
+use crate::io;
use crate::mem;
+use crate::path::Path;
use crate::path::Prefix;
+use crate::ptr;
#[cfg(test)]
mod tests;
None => (path, OsStr::new("")),
}
}
+
+/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
+///
+/// This path may or may not have a verbatim prefix.
+pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+ // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
+ // However, for APIs such as CreateDirectory[1], the limit is 248.
+ //
+ // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
+ const LEGACY_MAX_PATH: usize = 248;
+ // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
+ // All of these are in the ASCII range so they can be cast directly to `u16`.
+ const SEP: u16 = b'\\' as _;
+ const ALT_SEP: u16 = b'/' as _;
+ const QUERY: u16 = b'?' as _;
+ const COLON: u16 = b':' as _;
+ const DOT: u16 = b'.' as _;
+ const U: u16 = b'U' as _;
+ const N: u16 = b'N' as _;
+ const C: u16 = b'C' as _;
+
+ // \\?\
+ const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP];
+ // \??\
+ const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP];
+ // \\?\UNC\
+ const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
+
+ let mut path = to_u16s(path)?;
+ if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) {
+ // Early return for paths that are already verbatim.
+ return Ok(path);
+ } else if path.len() < LEGACY_MAX_PATH {
+ // Early return if an absolute path is less < 260 UTF-16 code units.
+ // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily.
+ match path.as_slice() {
+ // Starts with `D:`, `D:\`, `D:/`, etc.
+ // Does not match if the path starts with a `\` or `/`.
+ [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..]
+ if *drive != SEP && *drive != ALT_SEP =>
+ {
+ return Ok(path);
+ }
+ // Starts with `\\`, `//`, etc
+ [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path),
+ _ => {}
+ }
+ }
+
+ // Firstly, get the absolute path using `GetFullPathNameW`.
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+ let lpfilename = path.as_ptr();
+ fill_utf16_buf(
+ // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+ // `lpfilename` is a pointer to a null terminated string that is not
+ // invalidated until after `GetFullPathNameW` returns successfully.
+ |buffer, size| unsafe {
+ // While the docs for `GetFullPathNameW` have the standard note
+ // about needing a `\\?\` path for a long lpfilename, this does not
+ // appear to be true in practice.
+ // See:
+ // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
+ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+ c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
+ },
+ |mut absolute| {
+ path.clear();
+
+ // Secondly, add the verbatim prefix. This is easier here because we know the
+ // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
+ let prefix = match absolute {
+ // C:\ => \\?\C:\
+ [_, COLON, SEP, ..] => VERBATIM_PREFIX,
+ // \\.\ => \\?\
+ [SEP, SEP, DOT, SEP, ..] => {
+ absolute = &absolute[4..];
+ VERBATIM_PREFIX
+ }
+ // Leave \\?\ and \??\ as-is.
+ [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
+ // \\ => \\?\UNC\
+ [SEP, SEP, ..] => {
+ absolute = &absolute[2..];
+ UNC_PREFIX
+ }
+ // Anything else we leave alone.
+ _ => &[],
+ };
+
+ path.reserve_exact(prefix.len() + absolute.len() + 1);
+ path.extend_from_slice(prefix);
+ path.extend_from_slice(absolute);
+ path.push(0);
+ },
+ )?;
+ Ok(path)
+}
(OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share"))
);
}
+
+#[test]
+fn verbatim() {
+ use crate::path::Path;
+ fn check(path: &str, expected: &str) {
+ let verbatim = maybe_verbatim(Path::new(path)).unwrap();
+ let verbatim = String::from_utf16_lossy(verbatim.strip_suffix(&[0]).unwrap());
+ assert_eq!(&verbatim, expected, "{}", path);
+ }
+
+ // Ensure long paths are correctly prefixed.
+ check(
+ r"C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ check(
+ r"\\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\UNC\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ check(
+ r"\\.\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ // `\\?\` prefixed paths are left unchanged...
+ check(
+ r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ // But `//?/` is not a verbatim prefix so it will be normalized.
+ check(
+ r"//?/E:/verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\E:\verbatim\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+
+ // For performance, short absolute paths are left unchanged.
+ check(r"C:\Program Files\Rust", r"C:\Program Files\Rust");
+ check(r"\\server\share", r"\\server\share");
+ check(r"\\.\COM1", r"\\.\COM1");
+
+ // Check that paths of length 247 are converted to verbatim.
+ // This is necessary for `CreateDirectory`.
+ check(
+ r"C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ r"\\?\C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ );
+
+ // Make sure opening a drive will work.
+ check("Z:", "Z:");
+
+ // An empty path or a path that contains null are not valid paths.
+ assert!(maybe_verbatim(Path::new("")).is_err());
+ assert!(maybe_verbatim(Path::new("\0")).is_err());
+}
+//! Implements thread-local destructors that are not associated with any
+//! particular data.
+
#![unstable(feature = "thread_local_internals", issue = "none")]
#![cfg(target_thread_local)]
-pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
+// Using a per-thread list avoids the problems in synchronizing global state.
+#[thread_local]
+static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+ DESTRUCTORS.push((t, dtor));
+}
+
+/// Runs destructors. This should not be called until thread exit.
+pub unsafe fn run_keyless_dtors() {
+ // Drop all the destructors.
+ //
+ // Note: While this is potentially an infinite loop, it *should* be
+ // the case that this loop always terminates because we provide the
+ // guarantee that a TLS key cannot be set after it is flagged for
+ // destruction.
+ while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
+ (dtor)(ptr);
+ }
+ // We're done so free the memory.
+ DESTRUCTORS = Vec::new();
+}
unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
run_dtors();
+ #[cfg(target_thread_local)]
+ super::thread_local_dtor::run_keyless_dtors();
}
// See comments above for what this is doing. Note that we don't need this
/// This struct is created by
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
#[derive(Debug)]
pub struct CommandEnvs<'a> {
}
}
-/// Returns a slice of the given string for the byte range [`begin`..`end`).
+/// Returns a slice of the given string for the byte range \[`begin`..`end`).
///
/// # Panics
///
/// [`unwrap`]: crate::result::Result::unwrap
/// [naming-threads]: ./index.html#naming-threads
/// [stack-size]: ./index.html#stack-size
+#[must_use = "must eventually spawn the thread"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
///
/// handler.join().unwrap();
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn current() -> Thread {
thread_info::current_thread().expect(
///
/// [Mutex]: crate::sync::Mutex
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn panicking() -> bool {
panicking::panicking()
/// assert!(thread::current().id() != other_thread_id);
/// ```
#[stable(feature = "thread_id", since = "1.19.0")]
+ #[must_use]
pub fn id(&self) -> ThreadId {
self.inner.id
}
///
/// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn name(&self) -> Option<&str> {
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
}
/// println!("thread id: {:?}", thread.id());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn thread(&self) -> &Thread {
&self.0.thread
}
pub fn join(mut self) -> Result<T> {
self.0.join()
}
+
+ /// Checks if the the associated thread is still running its main function.
+ ///
+ /// This might return `false` for a brief moment after the thread's main
+ /// function has returned, but before the thread itself has stopped running.
+ #[unstable(feature = "thread_is_running", issue = "90470")]
+ pub fn is_running(&self) -> bool {
+ Arc::strong_count(&self.0.packet.0) > 1
+ }
}
impl<T> AsInner<imp::Thread> for JoinHandle<T> {
/// global state in order to more accurately query the amount of available
/// parallelism.
///
+/// Resource limits can be changed during the runtime of a program, therefore the value is
+/// not cached and instead recomputed every time this function is called. It should not be
+/// called from hot code.
+///
/// The value returned by this function should be considered a simplified
/// approximation of the actual amount of parallelism available at any given
/// time. To get a more detailed or precise overview of the amount of
use crate::any::Any;
use crate::mem;
use crate::result;
-use crate::sync::mpsc::{channel, Sender};
+use crate::sync::{
+ mpsc::{channel, Sender},
+ Arc, Barrier,
+};
use crate::thread::{self, ThreadId};
use crate::time::Duration;
+use crate::time::Instant;
// !!! These tests are dangerous. If something is buggy, they will hang, !!!
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
rx.recv().unwrap();
}
+#[test]
+fn test_is_running() {
+ let b = Arc::new(Barrier::new(2));
+ let t = thread::spawn({
+ let b = b.clone();
+ move || {
+ b.wait();
+ 1234
+ }
+ });
+
+ // Thread is definitely running here, since it's still waiting for the barrier.
+ assert_eq!(t.is_running(), true);
+
+ // Unblock the barrier.
+ b.wait();
+
+ // Now check that t.is_running() becomes false within a reasonable time.
+ let start = Instant::now();
+ while t.is_running() {
+ assert!(start.elapsed() < Duration::from_secs(2));
+ thread::sleep(Duration::from_millis(15));
+ }
+
+ // Joining the thread should not block for a significant time now.
+ let join_time = Instant::now();
+ assert_eq!(t.join().unwrap(), 1234);
+ assert!(join_time.elapsed() < Duration::from_secs(2));
+}
+
#[test]
fn test_join_panic() {
match thread::spawn(move || panic!()).join() {
///
/// let now = Instant::now();
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> Instant {
let os_now = time::Instant::now();
//
// To hopefully mitigate the impact of this, a few platforms are
// excluded as "these at least haven't gone backwards yet".
+ //
+ // While issues have been seen on arm64 platforms the Arm architecture
+ // requires that the counter monotonically increases and that it must
+ // provide a uniform view of system time (e.g. it must not be possible
+ // for a core to recieve a message from another core with a time stamp
+ // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
+ // there have been a few 64bit SoCs that have bugs which cause time to
+ // not monoticially increase, these have been fixed in the Linux kernel
+ // and we shouldn't penalize all Arm SoCs for those who refuse to
+ // update their kernels:
+ // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
+ // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
+ // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
+ // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
if time::Instant::actually_monotonic() {
return Instant(os_now);
}
/// let new_now = Instant::now();
/// println!("{:?}", new_now.duration_since(now));
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
/// println!("{:?}", new_now.checked_duration_since(now));
/// println!("{:?}", now.checked_duration_since(new_now)); // None
/// ```
+ #[must_use]
#[stable(feature = "checked_duration_since", since = "1.39.0")]
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
self.0.checked_sub_instant(&earlier.0)
/// println!("{:?}", new_now.saturating_duration_since(now));
/// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
/// ```
+ #[must_use]
#[stable(feature = "checked_duration_since", since = "1.39.0")]
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
/// sleep(three_secs);
/// assert!(instant.elapsed() >= three_secs);
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
///
/// let sys_time = SystemTime::now();
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> SystemTime {
SystemTime(time::SystemTime::now())
/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
/// }
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration(&self) -> Duration {
self.0
#[test]
fn instant_elapsed() {
let a = Instant::now();
- a.elapsed();
+ let _ = a.elapsed();
}
#[test]
#[should_panic]
fn instant_duration_since_panic() {
let a = Instant::now();
- (a - Duration::SECOND).duration_since(a);
+ let _ = (a - Duration::SECOND).duration_since(a);
}
#[test]
_stdout: &[u8],
_state: &ConsoleTestState,
) -> io::Result<()> {
- // Because the testsuit node holds some of the information as attributes, we can't write it
- // until all of the tests has ran. Instead of writting every result as they come in, we add
+ // Because the testsuite node holds some of the information as attributes, we can't write it
+ // until all of the tests have finished. Instead of writing every result as they come in, we add
// them to a Vec and write them all at once when run is complete.
let duration = exec_time.map(|t| t.0).unwrap_or_default();
self.results.push((desc.clone(), result.clone(), duration));
#![feature(native_link_modifiers_bundle)]
#![feature(nll)]
#![feature(staged_api)]
-#![feature(static_nobundle)]
#![feature(c_unwind)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
}
let is_test = args.iter().any(|a| a == "--test");
- if verbose > 1 {
+ if verbose > 2 {
let rust_env_vars =
env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
let prefix = if is_test { "[RUSTC-SHIM] rustc --test" } else { "[RUSTC-SHIM] rustc" };
def downloading_llvm(self):
opt = self.get_toml('download-ci-llvm', 'llvm')
- # This is currently all tier 1 targets (since others may not have CI
- # artifacts)
+ # This is currently all tier 1 targets and tier 2 targets with host tools
+ # (since others may not have CI artifacts)
# https://doc.rust-lang.org/rustc/platform-support.html#tier-1
supported_platforms = [
+ # tier 1
"aarch64-unknown-linux-gnu",
"i686-pc-windows-gnu",
"i686-pc-windows-msvc",
"x86_64-apple-darwin",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc",
+ # tier 2 with host tools
+ "aarch64-apple-darwin",
+ "aarch64-pc-windows-msvc",
+ "aarch64-unknown-linux-musl",
+ "arm-unknown-linux-gnueabi",
+ "arm-unknown-linux-gnueabihf",
+ "armv7-unknown-linux-gnueabihf",
+ "mips-unknown-linux-gnu",
+ "mips64-unknown-linux-gnuabi64",
+ "mips64el-unknown-linux-gnuabi64",
+ "mipsel-unknown-linux-gnu",
+ "powerpc-unknown-linux-gnu",
+ "powerpc64-unknown-linux-gnu",
+ "powerpc64le-unknown-linux-gnu",
+ "riscv64gc-unknown-linux-gnu",
+ "s390x-unknown-linux-gnu",
+ "x86_64-unknown-freebsd",
+ "x86_64-unknown-illumos",
+ "x86_64-unknown-linux-musl",
+ "x86_64-unknown-netbsd",
]
return opt == "true" \
or (opt == "if-available" and self.build in supported_platforms)
self.cargo()))
args = [self.cargo(), "build", "--manifest-path",
os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
- for _ in range(1, self.verbose):
+ for _ in range(0, self.verbose):
args.append("--verbose")
if self.use_locked_deps:
args.append("--locked")
if self.git_version >= distutils.version.LooseVersion("2.11.0"):
update_args.append("--progress")
update_args.append(module)
- run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+ try:
+ run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+ except RuntimeError:
+ print("Failed updating submodule. This is probably due to uncommitted local changes.")
+ print('Either stash the changes by running "git stash" within the submodule\'s')
+ print('directory, reset them by running "git reset --hard", or commit them.')
+ print("To reset all submodules' changes run", end=" ")
+ print('"git submodule foreach --recursive git reset --hard".')
+ raise SystemExit(1)
run(["git", "reset", "-q", "--hard"],
cwd=module_path, verbose=self.verbose)
doc::RustByExample,
doc::RustcBook,
doc::CargoBook,
+ doc::Clippy,
doc::EmbeddedBook,
doc::EditionGuide,
),
}
}
- if self.config.rust_new_symbol_mangling {
+ let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling {
+ Some(setting) => {
+ // If an explicit setting is given, use that
+ setting
+ }
+ None => {
+ if mode == Mode::Std {
+ // The standard library defaults to the legacy scheme
+ false
+ } else {
+ // The compiler and tools default to the new scheme
+ true
+ }
+ }
+ };
+
+ if use_new_symbol_mangling {
rustflags.arg("-Zsymbol-mangling-version=v0");
+ } else {
+ rustflags.arg("-Zsymbol-mangling-version=legacy");
}
// FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
}
- for _ in 1..self.verbosity {
+ for _ in 0..self.verbosity {
cargo.arg("-v");
}
t!(fs::create_dir_all(&libdir_self_contained));
let mut target_deps = vec![];
- // Copies the CRT objects.
+ // Copies the libc and CRT objects.
//
// rustc historically provides a more self-contained installation for musl targets
// not requiring the presence of a native musl toolchain. For example, it can fall back
let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
});
- for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
+ for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
copy_and_stamp(
builder,
&libdir_self_contained,
panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
})
.join("lib/wasm32-wasi");
- for &obj in &["crt1-command.o", "crt1-reactor.o"] {
+ for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
copy_and_stamp(
builder,
&libdir_self_contained,
// llvm codegen options
pub llvm_skip_rebuild: bool,
pub llvm_assertions: bool,
+ pub llvm_tests: bool,
pub llvm_plugins: bool,
pub llvm_optimize: bool,
pub llvm_thin_lto: bool,
pub rust_verify_llvm_ir: bool,
pub rust_thin_lto_import_instr_limit: Option<u32>,
pub rust_remap_debuginfo: bool,
- pub rust_new_symbol_mangling: bool,
+ pub rust_new_symbol_mangling: Option<bool>,
pub rust_profile_use: Option<String>,
pub rust_profile_generate: Option<String>,
pub llvm_profile_use: Option<String>,
thin_lto: Option<bool>,
release_debuginfo: Option<bool>,
assertions: Option<bool>,
+ tests: Option<bool>,
plugins: Option<bool>,
ccache: Option<StringOrBool>,
version_check: Option<bool>,
// Store off these values as options because if they're not provided
// we'll infer default values for them later
let mut llvm_assertions = None;
+ let mut llvm_tests = None;
let mut llvm_plugins = None;
let mut debug = None;
let mut debug_assertions = None;
}
set(&mut config.ninja_in_file, llvm.ninja);
llvm_assertions = llvm.assertions;
+ llvm_tests = llvm.tests;
llvm_plugins = llvm.plugins;
llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild);
set(&mut config.llvm_optimize, llvm.optimize);
config.llvm_from_ci = match llvm.download_ci_llvm {
Some(StringOrBool::String(s)) => {
assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
- // This is currently all tier 1 targets (since others may not have CI artifacts)
+ // This is currently all tier 1 targets and tier 2 targets with host tools
+ // (since others may not have CI artifacts)
// https://doc.rust-lang.org/rustc/platform-support.html#tier-1
// FIXME: this is duplicated in bootstrap.py
let supported_platforms = [
+ // tier 1
"aarch64-unknown-linux-gnu",
"i686-pc-windows-gnu",
"i686-pc-windows-msvc",
"x86_64-apple-darwin",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc",
+ // tier 2 with host tools
+ "aarch64-apple-darwin",
+ "aarch64-pc-windows-msvc",
+ "aarch64-unknown-linux-musl",
+ "arm-unknown-linux-gnueabi",
+ "arm-unknown-linux-gnueabihf",
+ "armv7-unknown-linux-gnueabihf",
+ "mips-unknown-linux-gnu",
+ "mips64-unknown-linux-gnuabi64",
+ "mips64el-unknown-linux-gnuabi64",
+ "mipsel-unknown-linux-gnu",
+ "powerpc-unknown-linux-gnu",
+ "powerpc64-unknown-linux-gnu",
+ "powerpc64le-unknown-linux-gnu",
+ "riscv64gc-unknown-linux-gnu",
+ "s390x-unknown-linux-gnu",
+ "x86_64-unknown-freebsd",
+ "x86_64-unknown-illumos",
+ "x86_64-unknown-linux-musl",
+ "x86_64-unknown-netbsd",
];
supported_platforms.contains(&&*config.build.triple)
}
config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
optimize = rust.optimize;
ignore_git = rust.ignore_git;
- set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling);
+ config.rust_new_symbol_mangling = rust.new_symbol_mangling;
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.codegen_tests, rust.codegen_tests);
set(&mut config.rust_rpath, rust.rpath);
config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false);
config.llvm_assertions = llvm_assertions.unwrap_or(false);
+ config.llvm_tests = llvm_tests.unwrap_or(false);
config.llvm_plugins = llvm_plugins.unwrap_or(false);
config.rust_optimize = optimize.unwrap_or(true);
"src/tools/rustfmt",
["rustfmt-nightly", "rustfmt-config_proc_macro"],
);
+tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]);
#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ErrorIndex {
struct Crate {
name: Interned<String>,
deps: HashSet<Interned<String>>,
- id: String,
path: PathBuf,
}
#[derive(Deserialize)]
struct Package {
- id: String,
name: String,
source: Option<String>,
manifest_path: String,
.filter(|dep| dep.source.is_none())
.map(|dep| INTERNER.intern_string(dep.name))
.collect();
- build.crates.insert(name, Crate { name, id: package.id, deps, path });
+ build.crates.insert(name, Crate { name, deps, path });
}
}
}
let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" };
let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" };
+ let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" };
cfg.out_dir(&out_dir)
.profile(profile)
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
.define("LLVM_INCLUDE_BENCHMARKS", "OFF")
- .define("LLVM_INCLUDE_TESTS", "OFF")
+ .define("LLVM_INCLUDE_TESTS", enable_tests)
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_ENABLE_BINDINGS", "OFF")
let version = output(cmd.arg("--version"));
let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
- if major >= 10 {
+ if major >= 12 {
return;
}
}
- panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version)
+ panic!("\n\nbad LLVM version: {}, need >=12.0\n\n", version)
}
fn configure_cmake(
# running with assertions again is not useful
ENV NO_DEBUG_ASSERTIONS=1
ENV NO_LLVM_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
# SLES 11 SP4 (glibc 2.11, kernel 3.0).
apt-get install --allow-unauthenticated -y --no-install-recommends \
automake \
bzip2 \
- ca-certificates \
- curl \
file \
g++ \
g++-multilib \
xz-utils \
zlib1g-dev
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
# static.rust-lang.org. This'll be used to link into libcurl below (and used
# later as well), so build a copy of OpenSSL with dynamic libraries into our
# generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
RUN ./build-openssl.sh
#
# Note that we also disable a bunch of optional features of curl that we don't
# really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
# binutils < 2.22 has a bug where the 32-bit executables it generates
# immediately segfault in Rust, so we need to install our own binutils.
git clone https://github.com/WebAssembly/wasi-libc
cd wasi-libc
-git reset --hard 58795582905e08fa7748846c1971b4ab911d1e16
+git reset --hard ad5133410f66b93a2381db5b542aad5e0964db96
make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
cd ..
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
# SLES 11 SP4 (glibc 2.11, kernel 3.0).
apt-get install --allow-unauthenticated -y --no-install-recommends \
automake \
bzip2 \
- ca-certificates \
- curl \
file \
g++ \
g++-multilib \
xz-utils \
zlib1g-dev
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
# static.rust-lang.org. This'll be used to link into libcurl below (and used
# later as well), so build a copy of OpenSSL with dynamic libraries into our
# generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
RUN ./build-openssl.sh
#
# Note that we also disable a bunch of optional features of curl that we don't
# really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
# binutils < 2.22 has a bug where the 32-bit executables it generates
# immediately segfault in Rust, so we need to install our own binutils.
source shared.sh
-LLVM=llvmorg-12.0.1
+LLVM=llvmorg-13.0.0
mkdir llvm-project
cd llvm-project
set -ex
source shared.sh
-VERSION=7.66.0
-
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
- | xz --decompress \
- | tar xf -
+tar xJf curl.tar.xz
mkdir curl-build
cd curl-build
-hide_output ../curl-$VERSION/configure \
+hide_output ../curl-*/configure \
--prefix=/rustroot \
--with-ssl=/rustroot \
--disable-sspi \
cd ..
rm -rf curl-build
-rm -rf curl-$VERSION
+rm -rf curl-*
set -ex
source shared.sh
-VERSION=1.0.2k
+tar xzf openssl.tar.gz
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz
-
-curl $URL | tar xzf -
-
-cd openssl-$VERSION
+cd openssl-*
hide_output ./config --prefix=/rustroot shared -fPIC
hide_output make -j$(nproc)
hide_output make install
cd ..
-rm -rf openssl-$VERSION
+rm -rf openssl-*
# Make the system cert collection available to the new install.
ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
--- /dev/null
+#!/usr/bin/env bash
+
+set -ex
+
+OPENSSL_VERSION=1.0.2k
+CURL_VERSION=7.66.0
+
+curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
+curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
+curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+++ /dev/null
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
-TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
-cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
-WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
-ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
-MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
-h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
-0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
-A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
-T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
-B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
-B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
-KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
-OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
-jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
-qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
-rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
-hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
-ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
-3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
-NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
-ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
-TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
-jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
-oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
-4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
-mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
-emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
------END CERTIFICATE-----
# otherwise normally be. We already test libstd with debug assertions in lots of
# other contexts as well
ENV NO_DEBUG_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
ENV WASM_TARGETS=wasm32-unknown-unknown
ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
+++ /dev/null
-FROM ubuntu:18.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
- g++ \
- gcc-multilib \
- make \
- ninja-build \
- file \
- curl \
- ca-certificates \
- python2.7 \
- git \
- cmake \
- sudo \
- gdb \
- llvm-10-tools \
- llvm-10-dev \
- libedit-dev \
- libssl-dev \
- pkg-config \
- zlib1g-dev \
- xz-utils \
- nodejs
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
- --build=x86_64-unknown-linux-gnu \
- --llvm-root=/usr/lib/llvm-10 \
- --enable-llvm-link-shared \
- --set rust.thin-lto-import-instr-limit=10
-
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
- # Run the `mir-opt` tests again but this time for a 32-bit target.
- # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
- # both 32-bit and 64-bit outputs updated by the PR author, before
- # the PR is approved and tested for merging.
- # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
- # despite having different output on 32-bit vs 64-bit targets.
- python2.7 ../x.py --stage 2 test src/test/mir-opt \
- --host='' --target=i686-unknown-linux-gnu && \
- # Run the UI test suite again, but in `--pass=check` mode
- #
- # This is intended to make sure that both `--pass=check` continues to
- # work.
- #
- python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
- --host='' --target=i686-unknown-linux-gnu && \
- # Run tidy at the very end, after all the other tests.
- python2.7 ../x.py --stage 2 test src/tools/tidy
--- /dev/null
+FROM ubuntu:20.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ gcc-multilib \
+ make \
+ ninja-build \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ llvm-12-tools \
+ llvm-12-dev \
+ libedit-dev \
+ libssl-dev \
+ pkg-config \
+ zlib1g-dev \
+ xz-utils \
+ nodejs
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --llvm-root=/usr/lib/llvm-12 \
+ --enable-llvm-link-shared \
+ --set rust.thin-lto-import-instr-limit=10
+
+ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+ # Run the `mir-opt` tests again but this time for a 32-bit target.
+ # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+ # both 32-bit and 64-bit outputs updated by the PR author, before
+ # the PR is approved and tested for merging.
+ # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+ # despite having different output on 32-bit vs 64-bit targets.
+ python2.7 ../x.py --stage 2 test src/test/mir-opt \
+ --host='' --target=i686-unknown-linux-gnu && \
+ # Run the UI test suite again, but in `--pass=check` mode
+ #
+ # This is intended to make sure that both `--pass=check` continues to
+ # work.
+ #
+ python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+ --host='' --target=i686-unknown-linux-gnu && \
+ # Run tidy at the very end, after all the other tests.
+ python2.7 ../x.py --stage 2 test src/tools/tidy
# https://github.com/puppeteer/puppeteer/issues/375
#
# We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.4.3 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.4.5 --unsafe-perm=true
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
# Look for all source files involves in the COPY command
copied_files=/tmp/.docker-copied-files.txt
rm -f "$copied_files"
- for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do
+ for i in $(sed -n -e '/^COPY --from=/! s/^COPY \(.*\) .*$/\1/p' \
+ "$docker_dir/$image/Dockerfile"); do
# List the file names
find "$script_dir/$i" -type f >> $copied_files
done
echo "Attempting to download $url"
rm -f /tmp/rustci_docker_cache
set +e
- retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url"
- loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
+ retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \
+ -o /tmp/rustci_docker_cache "$url"
+ echo "Loading images into docker"
+ # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM,
+ # KILL after 12 minutes
+ loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \
+ | sed 's/.* sha/sha/')
set -e
echo "Downloaded containers:\n$loaded_images"
fi
for lib in c cxxrt gcc_s m thr util; do
files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat kvm; do
files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
done
run: src/ci/scripts/install-sccache.sh
<<: *step
- - name: select Xcode
- run: src/ci/scripts/select-xcode.sh
- <<: *step
-
- name: install clang
run: src/ci/scripts/install-clang.sh
<<: *step
- name: mingw-check
<<: *job-linux-xl
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
<<: *job-linux-xl
- name: x86_64-gnu-tools
- name: x86_64-gnu-distcheck
<<: *job-linux-xl
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
env:
RUST_BACKTRACE: 1
<<: *job-linux-xl
# macOS Builders #
####################
+ # Only generate documentation for x86_64-apple-darwin, not other
+ # tier 2 targets produced by this builder.
- name: dist-x86_64-apple
env:
- SCRIPT: ./x.py dist
+ SCRIPT: ./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended
RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
<<: *job-macos-xl
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
<<: *job-macos-xl
- name: x86_64-apple
MACOSX_STD_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
<<: *job-macos-xl
# This target only needs to support 11.0 and up as nothing else supports the hardware
--set rust.jemalloc
--set llvm.ninja=false
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- SELECT_XCODE: /Applications/Xcode_12.2.app
USE_XCODE_CLANG: 1
MACOSX_DEPLOYMENT_TARGET: 11.0
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
# Corresponds to 16K page size
#
strategy:
matrix:
include:
- - *dist-x86_64-linux
+ - &dist-x86_64-linux
+ name: dist-x86_64-linux
+ <<: *job-linux-xl
master:
name: master
rm -rf /tmp/rustc-pgo
+# We collect LLVM profiling information and rustc profiling information in
+# separate phases. This increases build time -- though not by a huge amount --
+# but prevents any problems from arising due to different profiling runtimes
+# being simultaneously linked in.
+
python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
--stage 2 library/std \
- --rust-profile-generate=/tmp/rustc-pgo \
--llvm-profile-generate
# Profile libcore compilation in opt-level=0 and opt-level=3
RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
--crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
+# Merge the profile data we gathered for LLVM
+# Note that this uses the profdata from the clang we used to build LLVM,
+# which likely has a different version than our in-tree clang.
+/rustroot/bin/llvm-profdata \
+ merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
+
+# Rustbuild currently doesn't support rebuilding LLVM when PGO options
+# change (or any other llvm-related options); so just clear out the relevant
+# directories ourselves.
+rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
+
+# Okay, LLVM profiling is done, switch to rustc PGO.
+
+python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+ --stage 2 library/std \
+ --rust-profile-generate=/tmp/rustc-pgo
+
+# Profile libcore compilation in opt-level=0 and opt-level=3
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+ --crate-type=lib ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
+ --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
+
cp -r /tmp/rustc-perf ./
chown -R $(whoami): ./rustc-perf
cd rustc-perf
./build/$PGO_HOST/llvm/bin/llvm-profdata \
merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
-# Merge the profile data we gathered for LLVM
-# Note that this uses the profdata from the clang we used to build LLVM,
-# which likely has a different version than our in-tree clang.
-/rustroot/bin/llvm-profdata \
- merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
-
# Rustbuild currently doesn't support rebuilding LLVM when PGO options
# change (or any other llvm-related options); so just clear out the relevant
# directories ourselves.
rm -r ./build/$PGO_HOST/llvm ./build/$PGO_HOST/lld
-# This produces the actual final set of artifacts.
+# This produces the actual final set of artifacts, using both the LLVM and rustc
+# collected profiling data.
$@ \
--rust-profile-use=/tmp/rustc-pgo.profdata \
--llvm-profile-use=/tmp/llvm-pgo.profdata
PYTHON="python2"
fi
-if ! isCI || isCiBranch auto || isCiBranch beta; then
+if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
fi
+ # Same for overflow checks
+ if [ "$NO_OVERFLOW_CHECKS" = "" ]; then
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-overflow-checks"
+ fi
+
# In general we always want to run tests with LLVM assertions enabled, but not
# all platforms currently support that, so we have an option to disable.
if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
+++ /dev/null
-#!/bin/bash
-# This script selects the Xcode instance to use.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-
-if isMacOS; then
- if [[ -s "${SELECT_XCODE-}" ]]; then
- sudo xcode-select -s "${SELECT_XCODE}"
- fi
-fi
-Subproject commit eb1282ec444db94055fa9531b6f3f803e86bb382
+Subproject commit fd9299792852c9a368cb236748781852f75cdac6
-Subproject commit 270fccd339e5972d9c900e788f197e81a0bcd956
+Subproject commit 51739471276b1776dea27cf562b974ef07e24685
-Subproject commit 2d66852a27c5d0ec50ae021820d1de22caa2b1bd
+Subproject commit 358e6a61d5f4f0496d0a81e70cdcd25d05307342
-Subproject commit b5c68b02984f74e99d1f1b332029e05f607e2660
+Subproject commit a01d151a7250a540a9cb7ccce5956f020c677c21
-Subproject commit 9a60624fcad0140826c44389571dc622917cd632
+Subproject commit 27f1ff5e440ef78828b68ab882b98e1b10d9af32
-Subproject commit fba15a46ca8efa97e8a955794724ac7ce27805b8
+Subproject commit b06008731af0f7d07cd0614e820c8276dfed1c18
- [Platform Support](platform-support.md)
- [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
- [\*-kmc-solid_\*](platform-support/kmc-solid.md)
+ - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
- [Target Tier Policy](target-tier-policy.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
<tr>
<td>Forward-edge control flow protection
</td>
- <td>No
+ <td>Yes
</td>
- <td>
+ <td>Nightly
</td>
</tr>
<tr>
commercially available [grsecurity/PaX Reuse Attack Protector
(RAP)](https://grsecurity.net/rap_faq).
-The Rust compiler does not support forward-edge control flow protection on
-Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
-class="footnote">6</a></sup>. There is work currently ongoing to add support
-for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
-may not include support for LLVM CFI.
+The Rust compiler supports forward-edge control flow protection on nightly
+builds[40]-[41] <sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
+class="footnote">6</a></sup>.
```text
-$ readelf -s target/release/hello-rust | grep __cfi_init
+$ readelf -s -W target/debug/rust-cfi | grep "\.cfi"
+ 12: 0000000000005170 46 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_one.cfi
+ 15: 00000000000051a0 16 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_two.cfi
+ 17: 0000000000005270 396 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi4main.cfi
+...
```
-Fig. 15. Checking if LLVM CFI is enabled for a given binary.
+Fig. 15. Checking if LLVM CFI is enabled for a given binary[41].
-The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
-indicates that LLVM CFI (i.e., forward-edge control flow protection) is
-enabled for a given binary. Conversely, the absence of the `__cfi_init`
-symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
-enabled for a given binary (see Fig. 15).
+The presence of symbols suffixed with ".cfi" or the `__cfi_init` symbol (and
+references to `__cfi_check`) indicates that LLVM CFI (i.e., forward-edge control
+flow protection) is enabled for a given binary. Conversely, the absence of
+symbols suffixed with ".cfi" or the `__cfi_init` symbol (and references to
+`__cfi_check`) indicates that LLVM CFI is not enabled for a given binary (see
+Fig. 15).
-<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
+<small id="fn:6">6\. It also supports Control Flow Guard (CFG) on Windows (see
<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
class="reversefootnote" role="doc-backlink">↩</a></small>
39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
<https://github.com/rust-lang/rust/pull/55238>.
-40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
- <https://github.com/rust-lang/rust/issues/39699>.
+40. R. de C Valle. “Tracking Issue for LLVM Control Flow Integrity (CFI) Support
+ for Rust #89653.” GitHub. <https://github.com/rust-lang/rust/issues/89653>.
+
+41. “ControlFlowIntegrity.” The Rust Unstable Book.
+ <https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity>.
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
`x86_64-unknown-hermit` | ? | |
`x86_64-unknown-l4re-uclibc` | ? | |
+[`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | | Freestanding/bare-metal x86_64, softfloat
`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel
`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules
`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
--- /dev/null
+# `x86_64-unknown-none`
+
+**Tier: 3**
+
+Freestanding/bare-metal x86-64 binaries in ELF format: firmware, kernels, etc.
+
+## Target maintainers
+
+- Harald Hoyer `harald@profian.com`, https://github.com/haraldh
+- Mike Leany, https://github.com/mikeleany
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+By default, Rust code generated for this target does not use any vector or
+floating-point registers (e.g. SSE, AVX). This allows the generated code to run
+in environments, such as kernels, which may need to avoid the use of such
+registers or which may have special considerations about the use of such
+registers (e.g. saving and restoring them to avoid breaking userspace code
+using the same registers). You can change code generation to use additional CPU
+features via the `-C target-feature=` codegen options to rustc, or via the
+`#[target_feature]` mechanism within Rust code.
+
+By default, code generated with this target should run on any `x86_64`
+hardware; enabling additional target features may raise this baseline.
+
+Code generated with this target will use the `kernel` code model by default.
+You can change this using the `-C code-model=` option to rustc.
+
+On `x86_64-unknown-none`, `extern "C"` uses the [standard System V calling
+convention](https://gitlab.com/x86-psABIs/x86-64-ABI), without red zones.
+
+This target generated binaries in the ELF format. Any alternate formats or
+special considerations for binary layout will require linker options or linker
+scripts.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-unknown-none"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+As `x86_64-unknown-none` supports a variety of different environments and does
+not support `std`, this target does not support running the Rust testsuite.
+
+## Cross-compilation toolchains and C code
+
+If you want to compile C code along with Rust (such as for Rust crates with C
+dependencies), you will need an appropriate `x86_64` toolchain.
+
+Rust *may* be able to use an `x86_64-linux-gnu-` toolchain with appropriate
+standalone flags to build for this toolchain (depending on the assumptions of
+that toolchain, see below), or you may wish to use a separate
+`x86_64-unknown-none` (or `x86_64-elf-`) toolchain.
+
+On some `x86_64` hosts that use ELF binaries, you *may* be able to use the host
+C toolchain, if it does not introduce assumptions about the host environment
+that don't match the expectations of a standalone environment. Otherwise, you
+may need a separate toolchain for standalone/freestanding development, just as
+when cross-compiling from a non-`x86_64` platform.
These forms of the `#[doc]` attribute are used on individual items, to control how
they are documented.
-## `#[doc(no_inline)]`/`#[doc(inline)]`
+### `inline` and `no_inline`
+
+<span id="docno_inlinedocinline"></span>
These attributes are used on `use` statements, and control where the documentation shows
up. For example, consider this Rust code:
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
not eagerly inline it as a module unless you add `#[doc(inline)]`.
-## `#[doc(hidden)]`
+### `hidden`
+
+<span id="dochidden"></span>
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
the `strip-hidden` pass is removed.
+
+### `alias`
+
+This attribute adds an alias in the search index.
+
+Let's take an example:
+
+```rust,no_run
+#[doc(alias = "TheAlias")]
+pub struct SomeType;
+```
+
+So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
+Of course, if you enter `SomeType` it'll return `SomeType` as expected!
+
+#### FFI example
+
+This doc attribute is especially useful when writing bindings for a C library.
+For example, let's say we have a C function that looks like this:
+
+```c
+int lib_name_do_something(Obj *obj);
+```
+
+It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
+be written like this:
+
+```ignore (using non-existing ffi types)
+pub struct Obj {
+ inner: *mut ffi::Obj,
+}
+
+impl Obj {
+ pub fn do_something(&mut self) -> i32 {
+ unsafe { ffi::lib_name_do_something(self.inner) }
+ }
+}
+```
+
+The function has been turned into a method to make it more convenient to use.
+However, if you want to look for the Rust equivalent of `lib_name_do_something`,
+you have no way to do so.
+
+To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
+on the `do_something` method and then it's all good!
+Users can now look for `lib_name_do_something` in our crate directly and find
+`Obj::do_something`.
## Document primitives
+This is for Rust compiler internal use only.
+
Since primitive types are defined in the compiler, there's no place to attach documentation
-attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way to generate
-documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way
+to generate documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+
+## Document keywords
+
+This is for Rust compiler internal use only.
+
+Rust keywords are documented in the standard library (look for `match` for example).
+
+To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
+
+```rust
+#![feature(doc_keyword)]
+
+/// Some documentation about the keyword.
+#[doc(keyword = "keyword")]
+mod empty_mod {}
+```
## Unstable command-line arguments
* static
* typedef
2. If one of the previously listed items has a code example, then it'll be counted.
+
+### `--with-examples`: include examples of uses of items as documentation
+
+This option, combined with `--scrape-examples-target-crate` and
+`--scrape-examples-output-path`, is used to implement the functionality in [RFC
+#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
+functions / call-sites) are found in a crate and its reverse-dependencies, and
+then the uses are included as documentation for that item. This feature is
+intended to be used via `cargo doc --scrape-examples`, but the rustdoc-only
+workflow looks like:
+
+```bash
+$ rustdoc examples/ex.rs -Z unstable-options \
+ --extern foobar=target/deps/libfoobar.rmeta \
+ --scrape-examples-target-crate foobar \
+ --scrape-examples-output-path output.calls
+$ rustdoc src/lib.rs -Z unstable-options --with-examples output.calls
+```
+
+First, the library must be checked to generate an `rmeta`. Then a
+reverse-dependency like `examples/ex.rs` is given to rustdoc with the target
+crate being documented (`foobar`) and a path to output the calls
+(`output.calls`). Then, the generated calls file can be passed via
+`--with-examples` to the subsequent documentation of `foobar`.
--- /dev/null
+# `location-detail`
+
+The tracking issue for this feature is: [#70580](https://github.com/rust-lang/rust/issues/70580).
+
+------------------------
+
+Option `-Z location-detail=val` controls what location details are tracked when
+using `caller_location`. This allows users to control what location details
+are printed as part of panic messages, by allowing them to exclude any combination
+of filenames, line numbers, and column numbers. This option is intended to provide
+users with a way to mitigate the size impact of `#[track_caller]`.
+
+This option supports a comma separated list of location details to be included. Valid options
+within this list are:
+
+- `file` - the filename of the panic will be included in the panic output
+- `line` - the source line of the panic will be included in the panic output
+- `column` - the source column of the panic will be included in the panic output
+
+Any combination of these three options are supported. If this option is not specified,
+all three are included by default.
+
+An example of a panic output when using `-Z location-detail=line`:
+```text
+panicked at 'Process blink had a fault', <redacted>:323:0
+```
+
+The code size savings from this option are two-fold. First, the `&'static str` values
+for each path to a file containing a panic are removed from the binary. For projects
+with deep directory structures and many files with panics, this can add up. This category
+of savings can only be realized by excluding filenames from the panic output. Second,
+savings can be realized by allowing multiple panics to be fused into a single panicking
+branch. It is often the case that within a single file, multiple panics with the same
+panic message exist -- e.g. two calls to `Option::unwrap()` in a single line, or
+two calls to `Result::expect()` on adjacent lines. If column and line information
+are included in the `Location` struct passed to the panic handler, these branches cannot
+be fused, as the output is different depending on which panic occurs. However if line
+and column information is identical for all panics, these branches can be fused, which
+can lead to substantial code size savings, especially for small embedded binaries with
+many panics.
+
+The savings from this option are amplified when combined with the use of `-Zbuild-std`, as
+otherwise paths for panics within the standard library are still included in your binary.
--- /dev/null
+# `no-unique-section-names`
+
+------------------------
+
+This flag currently applies only to ELF-based targets using the LLVM codegen backend. It prevents the generation of unique ELF section names for each separate code and data item when `-Z function-sections` is also in use, which is the default for most targets. This option can reduce the size of object files, and depending on the linker, the final ELF binary as well.
+
+For example, a function `func` will by default generate a code section called `.text.func`. Normally this is fine because the linker will merge all those `.text.*` sections into a single one in the binary. However, starting with [LLVM 12](https://github.com/llvm/llvm-project/commit/ee5d1a04), the backend will also generate unique section names for exception handling, so you would see a section name of `.gcc_except_table.func` in the object file and potentially in the final ELF binary, which could add significant bloat to programs that contain many functions.
+
+This flag instructs LLVM to use the same `.text` and `.gcc_except_table` section name for each function, and it is analogous to Clang's `-fno-unique-section-names` option.
# `sanitizer`
-The tracking issue for this feature is: [#39699](https://github.com/rust-lang/rust/issues/39699).
+The tracking issues for this feature are:
+
+* [#39699](https://github.com/rust-lang/rust/issues/39699).
+* [#89653](https://github.com/rust-lang/rust/issues/89653).
------------------------
This feature allows for use of one of following sanitizers:
* [AddressSanitizer][clang-asan] a fast memory error detector.
+* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
+ forward-edge control flow protection.
* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
AddressSanitizer, but based on partial hardware assistance.
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
* [ThreadSanitizer][clang-tsan] a fast data race detector.
-To enable a sanitizer compile with `-Zsanitizer=address`,
+To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
`-Zsanitizer=thread`.
==39249==ABORTING
```
+# ControlFlowIntegrity
+
+The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
+provides forward-edge control flow protection for Rust-compiled code only by
+aggregating function pointers in groups identified by their number of arguments.
+
+Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
+binaries" (i.e., for when C or C++ and Rust -compiled code share the same
+virtual address space) will be provided in later work by defining and using
+compatible type identifiers (see Type metadata in the design document in the
+tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
+
+## Example
+
+```text
+#![feature(asm, naked_functions)]
+
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+ x + 1
+}
+
+#[naked]
+pub extern "C" fn add_two(x: i32) {
+ // x + 2 preceeded by a landing pad/nop block
+ unsafe {
+ asm!(
+ "
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ lea rax, [rdi+2]
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+ f(arg) + f(arg)
+}
+
+fn main() {
+ let answer = do_twice(add_one, 5);
+
+ println!("The answer is: {}", answer);
+
+ println!("With CFI enabled, you should not see the next answer");
+ let f: fn(i32) -> i32 = unsafe {
+ // Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
+ // invalid branch/call destinations (i.e., within the body of the function).
+ mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
+ };
+ let next_answer = do_twice(f, 5);
+
+ println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 1. Modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 3. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to an invalid destination, the execution is
+terminated (see Fig. 3).
+
+```rust
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+ x + 1
+}
+
+fn add_two(x: i32, _y: i32) -> i32 {
+ x + 2
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+ f(arg) + f(arg)
+}
+
+fn main() {
+ let answer = do_twice(add_one, 5);
+
+ println!("The answer is: {}", answer);
+
+ println!("With CFI enabled, you should not see the next answer");
+ let f: fn(i32) -> i32 =
+ unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
+ let next_answer = do_twice(f, 5);
+
+ println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 4. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different number of
+arguments than intended/passed in the call/branch site, the execution is also
+terminated (see Fig. 6).
+
+Forward-edge control flow protection not only by aggregating function pointers
+in groups identified by their number of arguments, but also their argument
+types, will also be provided in later work by defining and using compatible type
+identifiers (see Type metadata in the design document in the tracking
+issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: https://doc.rust-lang.org/book/title-page.html
+
# HWAddressSanitizer
HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
* [AddressSanitizer in Clang][clang-asan]
+* [ControlFlowIntegrity in Clang][clang-cfi]
* [HWAddressSanitizer in Clang][clang-hwasan]
* [LeakSanitizer in Clang][clang-lsan]
* [MemorySanitizer in Clang][clang-msan]
* [ThreadSanitizer in Clang][clang-tsan]
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
+[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
This will write the value `5` into the `u64` variable `x`.
You can see that the string literal we use to specify instructions is actually a template string.
It is governed by the same rules as Rust [format strings][format-syntax].
-The arguments that are inserted into the template however look a bit different then you may
+The arguments that are inserted into the template however look a bit different than you may
be familiar with. First we need to specify if the variable is an input or an output of the
inline assembly. In this case it is an output. We declared this by writing `out`.
We also need to specify in what kind of register the assembly expects the variable.
Second, we can see that inputs are declared by writing `in` instead of `out`.
Third, one of our operands has a type we haven't seen yet, `const`.
-This tells the compiler to expand this argument to value directly inside the assembly template.
+This tells the compiler to expand this argument to a value directly inside the assembly template.
This is only possible for constants and literals.
Fourth, we can see that we can specify an argument number, or name as in any format string.
}
println!(
- "L1 Cache: {}",
+ "L0 Cache: {}",
((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
);
```
- You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
- The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
+- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler.
+ - The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future.
> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
arrayvec = { version = "0.7", default-features = false }
pulldown-cmark = { version = "0.8", default-features = false }
minifier = "0.0.41"
-rayon = { version = "0.3.0", package = "rustc-rayon" }
+rayon = "1.3.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smallvec = "1.6.1"
let f = auto_trait::AutoTraitFinder::new(tcx);
debug!("get_auto_trait_impls({:?})", ty);
- let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+ let auto_traits: Vec<_> = self.cx.auto_traits.iter().copied().collect();
let mut auto_traits: Vec<Item> = auto_traits
.into_iter()
.filter_map(|trait_def_id| {
// to its smaller and larger regions. Note that 'larger' regions correspond
// to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
for constraint in regions.constraints.keys() {
- match constraint {
- &Constraint::VarSubVar(r1, r2) => {
+ match *constraint {
+ Constraint::VarSubVar(r1, r2) => {
{
let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
deps1.larger.insert(RegionTarget::RegionVid(r2));
let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
deps2.smaller.insert(RegionTarget::RegionVid(r1));
}
- &Constraint::RegSubVar(region, vid) => {
+ Constraint::RegSubVar(region, vid) => {
let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
deps.smaller.insert(RegionTarget::Region(region));
}
- &Constraint::VarSubReg(vid, region) => {
+ Constraint::VarSubReg(vid, region) => {
let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
deps.larger.insert(RegionTarget::Region(region));
}
- &Constraint::RegSubReg(r1, r2) => {
+ Constraint::RegSubReg(r1, r2) => {
// The constraint is already in the form that we want, so we're done with it
// Desired order is 'larger, smaller', so flip then
if region_name(r1) != region_name(r2) {
// as we want to combine them with any 'Output' qpaths
// later
- let is_fn = match &mut b {
- &mut GenericBound::TraitBound(ref mut p, _) => {
+ let is_fn = match b {
+ GenericBound::TraitBound(ref mut p, _) => {
// Insert regions into the for_generics hash map first, to ensure
// that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
for_generics.extend(p.generic_params.clone());
rhs,
});
continue; // If something other than a Fn ends up
- // with parenthesis, leave it alone
+ // with parentheses, leave it alone
}
}
}
fn region_name(region: Region<'_>) -> Option<Symbol> {
- match region {
- &ty::ReEarlyBound(r) => Some(r.name),
+ match *region {
+ ty::ReEarlyBound(r) => Some(r.name),
_ => None,
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match r {
- &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+ (match *r {
+ ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
-use crate::clean::{
- self, utils, Attributes, AttributesExt, GetDefId, ItemId, NestedAttributesExt, Type,
-};
+use crate::clean::{self, utils, Attributes, AttributesExt, ItemId, NestedAttributesExt, Type};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
}
}
-/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
+/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
crate fn build_impl(
cx: &mut DocContext<'_>,
parent_module: impl Into<Option<DefId>>,
return;
}
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
+
let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did);
// Only inline impl if the implementing type is
// reachable in rustdoc generated documentation
if !did.is_local() {
- if let Some(did) = for_.def_id() {
+ if let Some(did) = for_.def_id(&cx.cache) {
if !cx.cache.access_levels.is_public(did) {
return;
}
}
while let Some(ty) = stack.pop() {
- if let Some(did) = ty.def_id() {
+ if let Some(did) = ty.def_id(&cx.cache) {
if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
return;
}
let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
trace!("merged_attrs={:?}", merged_attrs);
- trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id());
+ trace!(
+ "build_impl: impl {:?} for {:?}",
+ trait_.as_ref().map(|t| t.def_id()),
+ for_.def_id(&cx.cache)
+ );
ret.push(clean::Item::from_def_id_and_attrs_and_parts(
did,
None,
impl Clean<Lifetime> for hir::Lifetime {
fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
let def = cx.tcx.named_region(self.hir_id);
- match def {
- Some(
- rl::Region::EarlyBound(_, node_id, _)
- | rl::Region::LateBound(_, _, node_id, _)
- | rl::Region::Free(_, node_id),
- ) => {
- if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
- return lt;
- }
+ if let Some(
+ rl::Region::EarlyBound(_, node_id, _)
+ | rl::Region::LateBound(_, _, node_id, _)
+ | rl::Region::Free(_, node_id),
+ ) = def
+ {
+ if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
+ return lt;
}
- _ => {}
}
Lifetime(self.name.ident().name)
}
let self_type = self.self_ty().clean(cx);
Type::QPath {
name: cx.tcx.associated_item(self.item_def_id).ident.name,
- self_def_id: self_type.def_id(),
+ self_def_id: self_type.def_id(&cx.cache),
self_type: box self_type,
trait_,
}
GenericParamDefKind::Type {
did: self.def_id,
bounds: vec![], // These are filled in from the where-clauses.
- default,
+ default: default.map(Box::new),
synthetic,
},
)
self.name,
GenericParamDefKind::Const {
did: self.def_id,
- ty: cx.tcx.type_of(self.def_id).clean(cx),
+ ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)),
default: match has_default {
- true => Some(cx.tcx.const_param_default(self.def_id).to_string()),
+ true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
false => None,
},
},
GenericParamDefKind::Type {
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
bounds: self.bounds.clean(cx),
- default: default.clean(cx),
+ default: default.clean(cx).map(Box::new),
synthetic,
},
),
self.name.ident().name,
GenericParamDefKind::Const {
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
- ty: ty.clean(cx),
+ ty: Box::new(ty.clean(cx)),
default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
- ty::Const::from_anon_const(cx.tcx, def_id).to_string()
+ Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
}),
},
),
.iter()
.enumerate()
.map(|(i, ty)| Argument {
- name: name_from_pat(&body.params[i].pat),
+ name: name_from_pat(body.params[i].pat),
type_: ty.clean(cx),
})
.collect(),
}
MethodItem(m, None)
}
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
(self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
});
}
TyMethodItem(t)
}
- hir::TraitItemKind::Type(ref bounds, ref default) => {
+ hir::TraitItemKind::Type(bounds, ref default) => {
AssocTypeItem(bounds.clean(cx), default.clean(cx))
}
};
let path = path.clean(cx);
resolve_type(cx, path)
}
- hir::QPath::Resolved(Some(ref qself), ref p) => {
+ hir::QPath::Resolved(Some(ref qself), p) => {
// Try to normalize `<X as Y>::T` to a type
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if let Some(normalized_value) = normalize(cx, ty) {
trait_,
}
}
- hir::QPath::TypeRelative(ref qself, ref segment) => {
+ hir::QPath::TypeRelative(ref qself, segment) => {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
let res = match ty.kind() {
ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
let length = print_const(cx, ct.eval(cx.tcx, param_env));
Array(box ty.clean(cx), length)
}
- TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
+ TyKind::Tup(tys) => Tuple(tys.clean(cx)),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
unreachable!()
}
}
- TyKind::Path(_) => clean_qpath(&self, cx),
- TyKind::TraitObject(ref bounds, ref lifetime, _) => {
+ TyKind::Path(_) => clean_qpath(self, cx),
+ TyKind::TraitObject(bounds, ref lifetime, _) => {
let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
DynTrait(bounds, lifetime)
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
ResolvedPath { path, did }
}
- ty::Dynamic(ref obj, ref reg) => {
+ ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
// might want to implement "native" support for marker-trait-only
// trait objects.
DynTrait(bounds, lifetime)
}
- ty::Tuple(ref t) => {
- Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
- }
+ ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx)),
ty::Projection(ref data) => data.clean(cx),
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Macro(ref macro_def) => MacroItem(Macro {
- source: display_macro_source(cx, name, ¯o_def, def_id, &item.vis),
+ source: display_macro_source(cx, name, macro_def, def_id, &item.vis),
}),
- ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+ ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
let items = item_ids
.iter()
.map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
}
let for_ = impl_.self_ty.clean(cx);
- let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+ let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
_ => None,
});
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let (item, renamed) = self;
- cx.with_param_env(item.def_id.to_def_id(), |cx| {
+ let def_id = item.def_id.to_def_id();
+ cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
- hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
+ hir::ForeignItemKind::Fn(decl, names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
let (generics, decl) = enter_impl_trait(cx, |cx| {
- (generics.clean(cx), (&**decl, &names[..]).clean(cx))
+ (generics.clean(cx), (&*decl, &names[..]).clean(cx))
});
ForeignFunctionItem(Function {
decl,
hir::TypeBindingKind::Equality { ref ty } => {
TypeBindingKind::Equality { ty: ty.clean(cx) }
}
- hir::TypeBindingKind::Constraint { ref bounds } => {
+ hir::TypeBindingKind::Constraint { bounds } => {
TypeBindingKind::Constraint { bounds: bounds.iter().map(|b| b.clean(cx)).collect() }
}
}
}
}
+/// The crate currently being documented.
#[derive(Clone, Debug)]
crate struct Crate {
- crate name: Symbol,
- crate src: FileName,
crate module: Item,
crate externs: Vec<ExternalCrate>,
crate primitives: ThinVec<(DefId, PrimitiveType)>,
crate collapsed: bool,
}
+// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Crate, 104);
+
+impl Crate {
+ crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
+ ExternalCrate::LOCAL.name(tcx)
+ }
+
+ crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
+ ExternalCrate::LOCAL.src(tcx)
+ }
+}
+
/// This struct is used to wrap additional information added by rustdoc on a `trait` item.
#[derive(Clone, Debug)]
crate struct TraitWithExtraInfo {
}
impl ExternalCrate {
+ const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
+
#[inline]
crate fn def_id(&self) -> DefId {
DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
.filter_map(|a| a.value_str())
.map(to_remote)
.next()
- .or(extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
+ .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
.unwrap_or(Unknown) // Well, at least we tried.
}
hir::ItemKind::Mod(_) => {
as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
- hir::ItemKind::Use(ref path, hir::UseKind::Single)
+ hir::ItemKind::Use(path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
as_keyword(path.res.expect_non_local())
hir::ItemKind::Mod(_) => {
as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
- hir::ItemKind::Use(ref path, hir::UseKind::Single)
+ hir::ItemKind::Use(path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
{
*span
} else {
- self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(|| Span::dummy())
+ self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
}
}
}
crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
- self.stability(tcx).as_ref().and_then(|ref s| {
+ self.stability(tcx).as_ref().and_then(|s| {
let mut classes = Vec::with_capacity(2);
if s.level.is_unstable() {
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
let sess = tcx.sess;
let doc_cfg_active = tcx.features().doc_cfg;
+ let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
let mut iter = it.into_iter();
Some(item)
}
- let mut cfg = if doc_cfg_active {
+ let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
let mut doc_cfg = self
.iter()
.filter(|attr| attr.has_name(sym::doc))
.flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
.filter(|attr| attr.has_name(sym::cfg))
.peekable();
- if doc_cfg.peek().is_some() {
+ if doc_cfg.peek().is_some() && doc_cfg_active {
doc_cfg
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
- } else {
+ } else if doc_auto_cfg_active {
self.iter()
.filter(|attr| attr.has_name(sym::cfg))
.filter_map(|attr| single(attr.meta_item_list()?))
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
.filter(|cfg| !hidden_cfg.contains(cfg))
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+ } else {
+ Cfg::True
}
} else {
Cfg::True
// #[doc(cfg(...))]
if let Some(cfg_mi) = item
.meta_item()
- .and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
+ .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
{
- match Cfg::parse(&cfg_mi) {
+ match Cfg::parse(cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => sess.span_err(e.span, e.msg),
}
T: IntoIterator<Item = &'a DocFragment>,
{
iter.into_iter().fold(String::new(), |mut acc, frag| {
- add_doc_fragment(&mut acc, &frag);
+ add_doc_fragment(&mut acc, frag);
acc
})
}
let ori = iter.next()?;
let mut out = String::new();
- add_doc_fragment(&mut out, &ori);
- while let Some(new_frag) = iter.next() {
+ 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);
+ add_doc_fragment(&mut out, new_frag);
}
if out.is_empty() { None } else { Some(out) }
}
for new_frag in self.doc_strings.iter() {
let out = ret.entry(new_frag.parent_module).or_default();
- add_doc_fragment(out, &new_frag);
+ add_doc_fragment(out, new_frag);
}
ret
}
Type {
did: DefId,
bounds: Vec<GenericBound>,
- default: Option<Type>,
+ default: Option<Box<Type>>,
synthetic: Option<hir::SyntheticTyParamKind>,
},
Const {
did: DefId,
- ty: Type,
- default: Option<String>,
+ ty: Box<Type>,
+ default: Option<Box<String>>,
},
}
// any embedded types, but `get_type` seems to be the wrong name for that.
crate fn get_type(&self) -> Option<Type> {
match self {
- GenericParamDefKind::Type { default, .. } => default.clone(),
- GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
+ GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
+ GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
GenericParamDefKind::Lifetime { .. } => None,
}
}
crate kind: GenericParamDefKind,
}
+// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(GenericParamDef, 56);
+
impl GenericParamDef {
crate fn is_synthetic_type_param(&self) -> bool {
match self.kind {
DefaultReturn,
}
-impl GetDefId for FnRetTy {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id(),
- DefaultReturn => None,
- }
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id_full(cache),
+impl FnRetTy {
+ crate fn as_return(&self) -> Option<&Type> {
+ match self {
+ Return(ret) => Some(ret),
DefaultReturn => None,
}
}
ImplTrait(Vec<GenericBound>),
}
-crate trait GetDefId {
- /// Use this method to get the [`DefId`] of a [`clean`] AST node.
- /// This will return [`None`] when called on a primitive [`clean::Type`].
- /// Use [`Self::def_id_full`] if you want to include primitives.
- ///
- /// [`clean`]: crate::clean
- /// [`clean::Type`]: crate::clean::Type
- // FIXME: get rid of this function and always use `def_id_full`
- fn def_id(&self) -> Option<DefId>;
-
- /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
- ///
- /// See [`Self::def_id`] for more.
- ///
- /// [clean]: crate::clean
- fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
- fn def_id(&self) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id())
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id_full(cache))
- }
-}
+// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Type, 72);
impl Type {
crate fn primitive_type(&self) -> Option<PrimitiveType> {
QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
Generic(_) | Infer | ImplTrait(_) => return None,
};
- cache.and_then(|c| Primitive(t).def_id_full(c))
+ cache.and_then(|c| Primitive(t).def_id(c))
}
-}
-impl GetDefId for Type {
- fn def_id(&self) -> Option<DefId> {
- self.inner_def_id(None)
+ /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+ ///
+ /// See [`Self::def_id_no_primitives`] for more.
+ ///
+ /// [clean]: crate::clean
+ crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
+ self.inner_def_id(Some(cache))
}
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.inner_def_id(Some(cache))
+ /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+ /// This will return [`None`] when called on a primitive [`clean::Type`].
+ /// Use [`Self::def_id`] if you want to include primitives.
+ ///
+ /// [`clean`]: crate::clean
+ /// [`clean::Type`]: crate::clean::Type
+ // FIXME: get rid of this function and always use `def_id`
+ crate fn def_id_no_primitives(&self) -> Option<DefId> {
+ self.inner_def_id(None)
}
}
crate item_type: Option<Type>,
}
-impl GetDefId for Typedef {
- fn def_id(&self) -> Option<DefId> {
- self.type_.def_id()
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.type_.def_id_full(cache)
- }
-}
-
#[derive(Clone, Debug)]
crate struct OpaqueTy {
crate bounds: Vec<GenericBound>,
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
let mut externs = Vec::new();
- for &cnum in cx.tcx.crates(()).iter() {
+ for &cnum in cx.tcx.crates(()) {
externs.push(ExternalCrate { crate_num: cnum });
// Analyze doc-reachability for extern items
LibEmbargoVisitor::new(cx).visit_lib(cnum);
}
- externs.sort_unstable_by_key(|e| e.crate_num);
// Clean the crate, translating the entire librustc_ast AST to one that is
// understood by rustdoc.
}
let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
- let src = local_crate.src(cx.tcx);
- let name = local_crate.name(cx.tcx);
let primitives = local_crate.primitives(cx.tcx);
let keywords = local_crate.keywords(cx.tcx);
{
}
Crate {
- name,
- src,
module,
externs,
primitives,
crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {
let segments = match *p {
- hir::QPath::Resolved(_, ref path) => &path.segments,
- hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+ hir::QPath::Resolved(_, path) => &path.segments,
+ hir::QPath::TypeRelative(_, segment) => return segment.ident.to_string(),
hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
};
PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
PatKind::Binding(_, _, ident, _) => return ident.name,
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
- PatKind::Or(ref pats) => {
+ PatKind::Or(pats) => {
pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
}
- PatKind::Tuple(ref elts, _) => format!(
+ PatKind::Tuple(elts, _) => format!(
"({})",
elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
),
- PatKind::Box(ref p) => return name_from_pat(&**p),
- PatKind::Ref(ref p, _) => return name_from_pat(&**p),
+ PatKind::Box(p) => return name_from_pat(&*p),
+ PatKind::Ref(p, _) => return name_from_pat(&*p),
PatKind::Lit(..) => {
warn!(
"tried to get argument name from PatKind::Lit, which is silly in function arguments"
return Symbol::intern("()");
}
PatKind::Range(..) => return kw::Underscore,
- PatKind::Slice(ref begin, ref mid, ref end) => {
+ PatKind::Slice(begin, ref mid, end) => {
let begin = begin.iter().map(|p| name_from_pat(p).to_string());
let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
let end = end.iter().map(|p| name_from_pat(p).to_string());
/// so that the channel is consistent.
///
/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
-crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.
use crate::html::static_files;
use crate::opts;
use crate::passes::{self, Condition, DefaultPassOption};
+use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
use crate::theme;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
crate json_unused_externs: bool,
/// Whether to skip capturing stdout and stderr of tests.
crate nocapture: bool,
+
+ /// Configuration for scraping examples from the current crate. If this option is Some(..) then
+ /// the compiler will scrape examples and not generate documentation.
+ crate scrape_examples_options: Option<ScrapeExamplesOptions>,
}
impl fmt::Debug for Options {
.field("run_check", &self.run_check)
.field("no_run", &self.no_run)
.field("nocapture", &self.nocapture)
+ .field("scrape_examples_options", &self.scrape_examples_options)
.finish()
}
}
crate emit: Vec<EmitType>,
/// If `true`, HTML source pages will generate links for items to their definition.
crate generate_link_to_definition: bool,
+ crate call_locations: AllCallLocations,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// been printed, returns `Err` with the exit code.
crate fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
// Check for unstable options.
- nightly_options::check_nightly_options(&matches, &opts());
+ nightly_options::check_nightly_options(matches, &opts());
if matches.opt_present("h") || matches.opt_present("help") {
crate::usage("rustdoc");
return Err(0);
} else if matches.opt_present("version") {
- rustc_driver::version("rustdoc", &matches);
+ rustc_driver::version("rustdoc", matches);
return Err(0);
}
return Err(0);
}
- let color = config::parse_color(&matches);
+ let color = config::parse_color(matches);
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
- config::parse_json(&matches);
- let error_format = config::parse_error_format(&matches, color, json_rendered);
+ config::parse_json(matches);
+ let error_format = config::parse_error_format(matches, color, json_rendered);
let codegen_options = CodegenOptions::build(matches, error_format);
let debugging_opts = DebuggingOptions::build(matches, error_format);
let diag = new_handler(error_format, None, &debugging_opts);
// check for deprecated options
- check_deprecated_options(&matches, &diag);
+ check_deprecated_options(matches, &diag);
let mut emit = Vec::new();
for list in matches.opt_strs("emit") {
.iter()
.map(|s| SearchPath::from_cli_opt(s, error_format))
.collect();
- let externs = parse_externs(&matches, &debugging_opts, error_format);
- let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+ let externs = parse_externs(matches, &debugging_opts, error_format);
+ let extern_html_root_urls = match parse_extern_html_roots(matches) {
Ok(ex) => ex,
Err(err) => {
diag.struct_err(err).emit();
}
}
- let edition = config::parse_crate_edition(&matches);
+ let edition = config::parse_crate_edition(matches);
let mut id_map = html::markdown::IdMap::new();
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"),
- nightly_options::match_is_nightly_build(&matches),
+ nightly_options::match_is_nightly_build(matches),
&diag,
&mut id_map,
edition,
return Err(1);
}
+ let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?;
+ let with_examples = matches.opt_strs("with-examples");
+ let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
Ok(Options {
),
emit,
generate_link_to_definition,
+ call_locations,
},
crate_name,
output_format,
json_unused_externs,
+ scrape_examples_options,
})
}
impl<'tcx> DocContext<'tcx> {
crate fn sess(&self) -> &'tcx Session {
- &self.tcx.sess
+ self.tcx.sess
}
crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
_ => continue,
};
for name in value.as_str().split_whitespace() {
- let span = attr.name_value_literal_span().unwrap_or(attr.span());
+ let span = attr.name_value_literal_span().unwrap_or_else(|| attr.span());
manual_passes.extend(parse_pass(name, Some(span)));
}
}
use std::string::ToString;
use std::sync::mpsc::Sender;
-macro_rules! try_err {
- ($e:expr, $file:expr) => {
- match $e {
- Ok(e) => e,
- Err(e) => return Err(E::new(e, $file)),
- }
- };
-}
-
crate trait PathError {
fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
where
});
});
} else {
- try_err!(fs::write(&path, contents), path);
+ fs::write(&path, contents).map_err(|e| E::new(e, path))?;
}
Ok(())
}
search_paths: options.libs.clone(),
crate_types,
lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
- lint_cap: Some(options.lint_cap.unwrap_or_else(|| lint::Forbid)),
+ lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
unstable_features: options.render_options.unstable_features,
.iter()
.map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
.fold(extern_names, |uextsa, uextsb| {
- uextsa.intersection(&uextsb).map(|v| *v).collect::<FxHashSet<&String>>()
+ uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>()
})
.iter()
.map(|v| (*v).clone())
// Add a \n to the end to properly terminate the last line,
// but only if there was output to be printed
- if out_lines.len() > 0 {
+ if !out_lines.is_empty() {
out_lines.push("");
}
let mut attrs = Attributes::from_ast(ast_attrs, None);
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
- if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
+ if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
return;
}
}
StructItem(mut i) => {
let num_fields = i.fields.len();
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.fields_stripped |=
- num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ if !i.fields_stripped {
+ i.fields_stripped =
+ num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ }
StructItem(i)
}
UnionItem(mut i) => {
let num_fields = i.fields.len();
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.fields_stripped |=
- num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ if !i.fields_stripped {
+ i.fields_stripped =
+ num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ }
UnionItem(i)
}
EnumItem(mut i) => {
let num_variants = i.variants.len();
i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.variants_stripped |=
- num_variants != i.variants.len() || i.variants.iter().any(|f| f.is_stripped());
+ if !i.variants_stripped {
+ i.variants_stripped = num_variants != i.variants.len()
+ || i.variants.iter().any(|f| f.is_stripped());
+ }
EnumItem(i)
}
TraitItem(mut i) => {
i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
ImplItem(i)
}
- VariantItem(i) => {
- let i2 = i.clone(); // this clone is small
- match i {
- Variant::Struct(mut j) => {
- let num_fields = j.fields.len();
- j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- j.fields_stripped |= num_fields != j.fields.len()
+ VariantItem(i) => match i {
+ Variant::Struct(mut j) => {
+ let num_fields = j.fields.len();
+ j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ if !j.fields_stripped {
+ j.fields_stripped = num_fields != j.fields.len()
|| j.fields.iter().any(|f| f.is_stripped());
- VariantItem(Variant::Struct(j))
- }
- Variant::Tuple(fields) => {
- let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Tuple(fields))
}
- _ => VariantItem(i2),
+ VariantItem(Variant::Struct(j))
}
- }
- x => x,
+ Variant::Tuple(fields) => {
+ let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantItem(Variant::Tuple(fields))
+ }
+ Variant::CLike => VariantItem(Variant::CLike),
+ },
+ ExternCrateItem { src: _ }
+ | ImportItem(_)
+ | FunctionItem(_)
+ | TypedefItem(_, _)
+ | OpaqueTyItem(_)
+ | StaticItem(_)
+ | ConstantItem(_)
+ | TraitAliasItem(_)
+ | TyMethodItem(_)
+ | MethodItem(_, _)
+ | StructFieldItem(_)
+ | ForeignFunctionItem(_)
+ | ForeignStaticItem(_)
+ | ForeignTypeItem
+ | MacroItem(_)
+ | ProcMacroItem(_)
+ | PrimitiveItem(_)
+ | AssocConstItem(_, _)
+ | AssocTypeItem(_, _)
+ | KeywordItem(_) => kind,
}
}
fn fold_crate(&mut self, mut c: Crate) -> Crate {
c.module = self.fold_item(c.module).unwrap();
- {
- let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
- for (k, mut v) in external_traits {
- v.trait_.items =
- v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
- c.external_traits.borrow_mut().insert(k, v);
- }
+ let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+ for (k, mut v) in external_traits {
+ v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
+ c.external_traits.borrow_mut().insert(k, v);
}
+
c
}
}
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
-use crate::clean::{self, GetDefId, ItemId, PrimitiveType};
+use crate::clean::{self, ItemId, PrimitiveType};
use crate::config::RenderOptions;
use crate::fold::DocFolder;
use crate::formats::item_type::ItemType;
|| i.trait_
.as_ref()
.map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
- || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
+ || i.for_
+ .def_id(self.cache)
+ .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
{
return None;
}
// inserted later on when serializing the search-index.
if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
let desc = item.doc_value().map_or_else(String::new, |x| {
- short_markdown_summary(&x.as_str(), &item.link_names(&self.cache))
+ short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
self.cache.search_index.push(IndexItem {
ty: item.type_(),
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
for bound in generics {
- if let Some(did) = bound.def_id() {
+ if let Some(did) = bound.def_id(self.cache) {
dids.insert(did);
}
}
let impl_item = Impl { impl_item: item };
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
for did in dids {
- self.cache.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+ self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
}
} else {
let trait_did = impl_item.trait_did().expect("no trait did");
ProcAttribute = 23,
ProcDerive = 24,
TraitAlias = 25,
+ Generic = 26,
}
impl Serialize for ItemType {
ItemType::ProcAttribute => "attr",
ItemType::ProcDerive => "derive",
ItemType::TraitAlias => "traitalias",
+ ItemType::Generic => "generic",
}
}
}
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path<'a, 'cx: 'a>(
+fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
did: DefId,
path: &clean::Path,
/// Helper to render type parameters
fn tybounds<'a, 'tcx: 'a>(
- bounds: &'a Vec<clean::PolyTrait>,
+ bounds: &'a [clean::PolyTrait],
lt: &'a Option<clean::Lifetime>,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
if bounds.len() > 1 || trait_lt.is_some() =>
{
write!(f, "{}{}{}(", amp, lt, m)?;
- fmt_type(&ty, f, use_absolute, cx)?;
+ fmt_type(ty, f, use_absolute, cx)?;
write!(f, ")")
}
clean::Generic(..) => {
&format!("{}{}{}", amp, lt, m),
cx,
)?;
- fmt_type(&ty, f, use_absolute, cx)
+ fmt_type(ty, f, use_absolute, cx)
}
_ => {
write!(f, "{}{}{}", amp, lt, m)?;
- fmt_type(&ty, f, use_absolute, cx)
+ fmt_type(ty, f, use_absolute, cx)
}
}
}
use std::collections::VecDeque;
use std::fmt::{Display, Write};
+use rustc_data_structures::fx::FxHashMap;
use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
crate root_path: &'c str,
}
+/// Decorations are represented as a map from CSS class to vector of character ranges.
+/// Each range will be wrapped in a span with that class.
+crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
+
/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
src: &str,
edition: Edition,
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
+ decoration_info: Option<DecorationInfo>,
) {
debug!("highlighting: ================\n{}\n==============", src);
if let Some((edition_info, class)) = tooltip {
}
write_header(out, class, extra_content);
- write_code(out, &src, edition, context_info);
+ write_code(out, src, edition, context_info, decoration_info);
write_footer(out, playground_button);
}
src: &str,
edition: Edition,
context_info: Option<ContextInfo<'_, '_, '_>>,
+ decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
- Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
- .highlight(&mut |highlight| {
- match highlight {
- Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
- Highlight::EnterSpan { class } => enter_span(out, class),
- Highlight::ExitSpan => exit_span(out),
- };
- });
+ Classifier::new(
+ &src,
+ edition,
+ context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+ decoration_info,
+ )
+ .highlight(&mut |highlight| {
+ match highlight {
+ Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+ Highlight::EnterSpan { class } => enter_span(out, class),
+ Highlight::ExitSpan => exit_span(out),
+ };
+ });
}
fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
PreludeTy,
PreludeVal,
QuestionMark,
+ Decoration(&'static str),
}
impl Class {
Class::PreludeTy => "prelude-ty",
Class::PreludeVal => "prelude-val",
Class::QuestionMark => "question-mark",
+ Class::Decoration(kind) => kind,
}
}
}
}
+/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls
+struct Decorations {
+ starts: Vec<(u32, &'static str)>,
+ ends: Vec<u32>,
+}
+
+impl Decorations {
+ fn new(info: DecorationInfo) -> Self {
+ // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end).
+ let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
+ .0
+ .into_iter()
+ .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+ .flatten()
+ .unzip();
+
+ // Sort the sequences in document order.
+ starts.sort_by_key(|(lo, _)| *lo);
+ ends.sort();
+
+ Decorations { starts, ends }
+ }
+}
+
/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
byte_pos: u32,
file_span: Span,
src: &'a str,
+ decorations: Option<Decorations>,
}
impl<'a> Classifier<'a> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file span which will be used later on by the `span_correspondance_map`.
- fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
+ fn new(
+ src: &str,
+ edition: Edition,
+ file_span: Span,
+ decoration_info: Option<DecorationInfo>,
+ ) -> Classifier<'_> {
let tokens = PeekIter::new(TokenIter { src });
+ let decorations = decoration_info.map(Decorations::new);
Classifier {
tokens,
in_attribute: false,
byte_pos: 0,
file_span,
src,
+ decorations,
}
}
/// token is used.
fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
loop {
+ if let Some(decs) = self.decorations.as_mut() {
+ let byte_pos = self.byte_pos;
+ let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count();
+ for (_, kind) in decs.starts.drain(0..n_starts) {
+ sink(Highlight::EnterSpan { class: Class::Decoration(kind) });
+ }
+
+ let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count();
+ for _ in decs.ends.drain(0..n_ends) {
+ sink(Highlight::ExitSpan);
+ }
+ }
+
if self
.tokens
.peek()
// Assume that '&' or '*' is the reference or dereference operator
// or a reference or pointer type. Unless, of course, it looks like
// a logical and or a multiplication operator: `&&` or `* `.
- TokenKind::Star => match self.peek() {
- Some(TokenKind::Whitespace) => Class::Op,
+ TokenKind::Star => match self.tokens.peek() {
+ Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Ident, "mut")) => {
+ self.next();
+ sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
+ return;
+ }
+ Some((TokenKind::Ident, "const")) => {
+ self.next();
+ sink(Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) });
+ return;
+ }
_ => Class::RefKeyWord,
},
- TokenKind::And => match lookahead {
- Some(TokenKind::And) => {
+ TokenKind::And => match self.tokens.peek() {
+ Some((TokenKind::And, _)) => {
self.next();
sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
return;
}
- Some(TokenKind::Eq) => {
+ Some((TokenKind::Eq, _)) => {
self.next();
sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
return;
}
- Some(TokenKind::Whitespace) => Class::Op,
+ Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Ident, "mut")) => {
+ self.next();
+ sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
+ return;
+ }
_ => Class::RefKeyWord,
},
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href {
LinkFromSrc::Local(span) => context
- .href_from_span(*span)
+ .href_from_span(*span, true)
.map(|s| format!("{}{}", context_info.root_path, s)),
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(context_info.root_path))
.map(|(url, _, _)| url)
}
LinkFromSrc::Primitive(prim) => format::href_with_root_path(
- PrimitiveType::primitive_locations(context.tcx())[&prim],
+ PrimitiveType::primitive_locations(context.tcx())[prim],
context,
Some(context_info.root_path),
)
--- /dev/null
+<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">"linux"</span>)]</span>
<span class="kw">fn</span> <span class="ident">main</span>() -> () {
<span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&&</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
- <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*</span><span class="kw">const</span> () <span class="op">=</span> <span class="number">0</span>;
+ <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&&</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
- <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
+ <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&mut</span> <span class="ident">bar</span>);
<span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
<span class="ident">::std::env::var</span>(<span class="string">"gateau"</span>).<span class="ident">is_ok</span>();
<span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
-use super::write_code;
+use super::{write_code, DecorationInfo};
use crate::html::format::Buffer;
use expect_test::expect_file;
+use rustc_data_structures::fx::FxHashMap;
use rustc_span::create_default_session_globals_then;
use rustc_span::edition::Edition;
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = Buffer::new();
- write_code(&mut out, src, Edition::Edition2018, None);
+ write_code(&mut out, src, Edition::Edition2018, None, None);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
println!(\"foo\");\r\n\
}\r\n";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
});
}
let y = Self::whatever;";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
});
}
create_default_session_globals_then(|| {
let src = include_str!("fixtures/union.rs");
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
});
}
+
+#[test]
+fn test_decorations() {
+ create_default_session_globals_then(|| {
+ let src = "let x = 1;
+let y = 2;";
+ let mut decorations = FxHashMap::default();
+ decorations.insert("example", vec![(0, 10)]);
+
+ let mut html = Buffer::new();
+ write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+ expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+ });
+}
/// 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)]
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
let style_files = style_files
.iter()
- .filter_map(|t| {
- if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
- })
- .filter_map(|t| if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None })
+ .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
+ .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
.map(|t| {
format!(
r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
} else if let Some(stripped) = trimmed.strip_prefix("# ") {
// # text
- Line::Hidden(&stripped)
+ Line::Hidden(stripped)
} else if trimmed == "#" {
// We cannot handle '#text' because it could be #[attr].
Line::Hidden("")
let parse_result = match kind {
CodeBlockKind::Fenced(ref lang) => {
let parse_result =
- LangString::parse_without_check(&lang, self.check_error_codes, false);
+ LangString::parse_without_check(lang, self.check_error_codes, false);
if !parse_result.rust {
return Some(Event::Html(
format!(
edition,
None,
None,
+ None,
);
Some(Event::Html(s.into_inner().into()))
}
loop {
match self.inner.next() {
Some((Event::FootnoteReference(ref reference), range)) => {
- let entry = self.get_entry(&reference);
+ let entry = self.get_entry(reference);
let reference = format!(
"<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
(*entry).1
// If there are characters between the preceding line ending and
// this code block, `str::lines` will return an additional line,
// which we subtract here.
- if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with("\n") {
+ if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') {
nb_lines -= 1;
}
let line = tests.get_line() + nb_lines + 1;
string
.split(|c| c == ',' || c == ' ' || c == '\t')
.map(str::trim)
- .map(|token| if token.chars().next() == Some('.') { &token[1..] } else { token })
+ .map(|token| token.strip_prefix('.').unwrap_or(token))
.filter(|token| !token.is_empty())
}
}
x if extra.is_some() => {
let s = x.to_lowercase();
- match if s == "compile-fail" || s == "compile_fail" || s == "compilefail" {
+ if let Some((flag, help)) = if s == "compile-fail"
+ || s == "compile_fail"
+ || s == "compilefail"
+ {
Some((
"compile_fail",
"the code block will either not be tested if not marked as a rust one \
} else {
None
} {
- Some((flag, help)) => {
- if let Some(ref extra) = extra {
- extra.error_invalid_codeblock_attr(
- &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
- help,
- );
- }
+ if let Some(extra) = extra {
+ extra.error_invalid_codeblock_attr(
+ &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
+ help,
+ );
}
- None => {}
}
seen_other_tags = true;
}
return String::new();
}
let mut replacer = |broken_link: BrokenLink<'_>| {
- if let Some(link) =
- links.iter().find(|link| &*link.original_text == broken_link.reference)
- {
- Some((link.href.as_str().into(), link.new_text.as_str().into()))
- } else {
- None
- }
+ links
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
}
let mut replacer = |broken_link: BrokenLink<'_>| {
- if let Some(link) =
- links.iter().find(|link| &*link.original_text == broken_link.reference)
- {
- Some((link.href.as_str().into(), link.new_text.as_str().into()))
- } else {
- None
- }
+ links
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
}
let mut replacer = |broken_link: BrokenLink<'_>| {
- if let Some(link) =
- link_names.iter().find(|link| &*link.original_text == broken_link.reference)
- {
- Some((link.href.as_str().into(), link.new_text.as_str().into()))
- } else {
- None
- }
+ link_names
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
CodeBlockKind::Indented => {
// The ending of the offset goes too far sometime so we reduce it by one in
// these cases.
- if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
+ if offset.end > offset.start && md.get(offset.end..=offset.end) == Some("\n") {
(
LangString::default(),
offset.start,
+use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use crate::clean;
-use crate::clean::types::{
- FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
-};
+use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::html::markdown::short_markdown_summary;
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
let desc = item
.doc_value()
- .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(&cache)));
+ .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
cache.search_index.push(IndexItem {
ty: item.type_(),
name: item.name.unwrap().to_string(),
desc,
parent: Some(did),
parent_idx: None,
- search_type: get_index_search_type(&item, tcx),
+ search_type: get_index_search_type(item, tcx),
aliases: item.attrs.get_doc_aliases(),
});
}
let crate_doc = krate
.module
.doc_value()
- .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(&cache)));
+ .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache)));
let Cache { ref mut search_index, ref paths, .. } = *cache;
// Set up alias indexes.
for (i, item) in search_index.iter().enumerate() {
for alias in &item.aliases[..] {
- aliases.entry(alias.to_lowercase()).or_insert(Vec::new()).push(i);
+ aliases.entry(alias.to_lowercase()).or_insert_with(Vec::new).push(i);
}
}
let mut lastpathid = 0usize;
for item in search_index {
- item.parent_idx = item.parent.and_then(|defid| {
- if defid_to_pathid.contains_key(&defid) {
- defid_to_pathid.get(&defid).copied()
- } else {
+ item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+ Entry::Occupied(entry) => Some(*entry.get()),
+ Entry::Vacant(entry) => {
let pathid = lastpathid;
- defid_to_pathid.insert(defid, pathid);
+ entry.insert(pathid);
lastpathid += 1;
if let Some(&(ref fqp, short)) = paths.get(&defid) {
// Collect the index into a string
format!(
r#""{}":{}"#,
- krate.name,
+ krate.name(tcx),
serde_json::to_string(&CrateData {
doc: crate_doc,
items: crate_items,
item: &clean::Item,
tcx: TyCtxt<'tcx>,
) -> Option<IndexItemFunctionType> {
- let (all_types, ret_types) = match *item.kind {
+ let (mut inputs, mut output) = match *item.kind {
clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx),
clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx),
clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx),
_ => return None,
};
- let inputs = all_types
- .iter()
- .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
- .filter(|a| a.ty.name.is_some())
- .collect();
- let output = ret_types
- .iter()
- .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
- .filter(|a| a.ty.name.is_some())
- .collect::<Vec<_>>();
+ inputs.retain(|a| a.ty.name.is_some());
+ output.retain(|a| a.ty.name.is_some());
let output = if output.is_empty() { None } else { Some(output) };
Some(IndexItemFunctionType { inputs, output })
}
-fn get_index_type(clean_type: &clean::Type) -> RenderType {
+fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
RenderType {
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
- generics: get_generics(clean_type),
+ generics: if generics.is_empty() { None } else { Some(generics) },
}
}
}
}
-/// Return a list of generic parameters for use in the search index.
-///
-/// This function replaces bounds with types, so that `T where T: Debug` just becomes `Debug`.
-/// It does return duplicates, and that's intentional, since search queries like `Result<usize, usize>`
-/// are supposed to match only results where both parameters are `usize`.
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
- clean_type.generics().and_then(|types| {
- let r = types
- .iter()
- .filter_map(|t| {
- get_index_type_name(t, false).map(|name| name.as_str().to_ascii_lowercase())
- })
- .collect::<Vec<_>>();
- if r.is_empty() { None } else { Some(r) }
- })
-}
-
/// The point of this function is to replace bounds with types.
///
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
generics: &Generics,
arg: &Type,
tcx: TyCtxt<'tcx>,
- recurse: i32,
- res: &mut FxHashSet<(Type, ItemType)>,
-) -> usize {
- fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
- if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
- res.insert((ty, kind));
- 1
+ recurse: usize,
+ res: &mut Vec<TypeWithKind>,
+) {
+ fn insert_ty(
+ res: &mut Vec<TypeWithKind>,
+ tcx: TyCtxt<'_>,
+ ty: Type,
+ mut generics: Vec<TypeWithKind>,
+ ) {
+ let is_full_generic = ty.is_full_generic();
+
+ if is_full_generic && generics.len() == 1 {
+ // In this case, no need to go through an intermediate state if the generics
+ // contains only one element.
+ //
+ // For example:
+ //
+ // fn foo<T: Display>(r: Option<T>) {}
+ //
+ // In this case, it would contain:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "",
+ // generics: [
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // }]
+ // ```
+ //
+ // After removing the intermediate (unnecessary) full generic, it'll become:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // ```
+ //
+ // To be noted that it can work if there is ONLY ONE generic, otherwise we still
+ // need to keep it as is!
+ res.push(generics.pop().unwrap());
+ return;
+ }
+ let mut index_ty = get_index_type(&ty, generics);
+ if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
+ return;
+ }
+ if is_full_generic {
+ // We remove the name of the full generic because we have no use for it.
+ index_ty.name = Some(String::new());
+ res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
+ } else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
+ res.push(TypeWithKind::from((index_ty, kind)));
} else if ty.is_primitive() {
// This is a primitive, let's store it as such.
- res.insert((ty, ItemType::Primitive));
- 1
- } else {
- 0
+ res.push(TypeWithKind::from((index_ty, ItemType::Primitive)));
}
}
if recurse >= 10 {
// FIXME: remove this whole recurse thing when the recursion bug is fixed
- return 0;
+ return;
}
- let mut nb_added = 0;
- if let &Type::Generic(arg_s) = arg {
+ if let Type::Generic(arg_s) = *arg {
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
- WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
+ WherePredicate::BoundPredicate { ty, .. } => {
+ ty.def_id_no_primitives() == arg.def_id_no_primitives()
+ }
_ => false,
}) {
+ let mut ty_generics = Vec::new();
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let GenericBound::TraitBound(poly_trait, _) = bound {
continue;
}
if let Some(ty) = x.get_type() {
- let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
- nb_added += adds;
- if adds == 0 && !ty.is_full_generic() {
- nb_added += insert(res, tcx, ty);
- }
+ get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
}
}
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+ let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::ResolvedPath { did: path.def_id(), path };
- let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
- nb_added += adds;
- if adds == 0 && !ty.is_full_generic() {
- nb_added += insert(res, tcx, ty);
- }
+ get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
} else {
- nb_added += insert(res, tcx, arg.clone());
- if let Some(gens) = arg.generics() {
- for gen in gens.iter() {
- if gen.is_full_generic() {
- nb_added += get_real_types(generics, gen, tcx, recurse + 1, res);
- } else {
- nb_added += insert(res, tcx, (*gen).clone());
- }
+ let mut ty_generics = Vec::new();
+ if let Some(arg_generics) = arg.generics() {
+ for gen in arg_generics.iter() {
+ get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
- nb_added
}
/// Return the full list of types when bounds have been resolved.
generics: &Generics,
decl: &FnDecl,
tcx: TyCtxt<'tcx>,
-) -> (Vec<(Type, ItemType)>, Vec<(Type, ItemType)>) {
- let mut all_types = FxHashSet::default();
+) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
+ let mut all_types = Vec::new();
for arg in decl.inputs.values.iter() {
if arg.type_.is_self_type() {
continue;
}
- let mut args = FxHashSet::default();
+ // FIXME: performance wise, it'd be much better to move `args` declaration outside of the
+ // loop and replace this line with `args.clear()`.
+ let mut args = Vec::new();
get_real_types(generics, &arg.type_, tcx, 0, &mut args);
if !args.is_empty() {
+ // FIXME: once back to performance improvements, replace this line with:
+ // `all_types.extend(args.drain(..));`.
all_types.extend(args);
} else {
- if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
- all_types.insert((arg.type_.clone(), kind));
+ if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+ {
+ all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind)));
}
}
}
- let ret_types = match decl.output {
+ let mut ret_types = Vec::new();
+ match decl.output {
FnRetTy::Return(ref return_type) => {
- let mut ret = FxHashSet::default();
- get_real_types(generics, &return_type, tcx, 0, &mut ret);
- if ret.is_empty() {
- if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
- ret.insert((return_type.clone(), kind));
+ get_real_types(generics, return_type, tcx, 0, &mut ret_types);
+ if ret_types.is_empty() {
+ if let Some(kind) =
+ return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+ {
+ ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
}
}
- ret.into_iter().collect()
}
- _ => Vec::new(),
+ _ => {}
};
- (all_types.into_iter().collect(), ret_types)
+ (all_types, ret_types)
}
use std::sync::mpsc::{channel, Receiver};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
BASIC_KEYWORDS,
};
-use crate::clean;
-use crate::clean::ExternalCrate;
+use crate::clean::{self, ExternalCrate};
use crate::config::RenderOptions;
use crate::docfs::{DocFS, PathError};
use crate::error::Error;
use crate::html::format::Buffer;
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
use crate::html::{layout, sources};
+use crate::scrape_examples::AllCallLocations;
+use crate::try_err;
/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
/// real location of an item. This is used to allow external links to
/// publicly reused items to redirect to the right location.
pub(super) render_redirect_pages: bool,
+ /// Tracks section IDs for `Deref` targets so they match in both the main
+ /// body and the sidebar.
+ pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: RefCell<IdMap>,
/// Shared mutable state.
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 104);
+rustc_data_structures::static_assert_size!(Context<'_>, 144);
/// Shared mutable state used in [`Context`] and elsewhere.
crate struct SharedContext<'tcx> {
crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
/// The [`Cache`] used during rendering.
crate cache: Cache,
+
+ crate call_locations: AllCallLocations,
}
impl SharedContext<'_> {
}
pub(super) fn sess(&self) -> &'tcx Session {
- &self.shared.tcx.sess
+ self.shared.tcx.sess
}
pub(super) fn derive_id(&self, id: String) -> String {
};
title.push_str(" - Rust");
let tyname = it.type_();
- let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
+ let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(doc));
let desc = if let Some(desc) = desc {
desc
} else if it.is_crate() {
/// may happen, for example, with externally inlined items where the source
/// of their crate documentation isn't known.
pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
- self.href_from_span(item.span(self.tcx()))
+ self.href_from_span(item.span(self.tcx()), true)
}
- crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+ crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
if span.is_dummy() {
return None;
}
(&*symbol, &path)
};
- let loline = span.lo(self.sess()).line;
- let hiline = span.hi(self.sess()).line;
- let lines =
- if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
+ let anchor = if with_lines {
+ let loline = span.lo(self.sess()).line;
+ let hiline = span.hi(self.sess()).line;
+ format!(
+ "#{}",
+ if loline == hiline {
+ loline.to_string()
+ } else {
+ format!("{}-{}", loline, hiline)
+ }
+ )
+ } else {
+ "".to_string()
+ };
Some(format!(
- "{root}src/{krate}/{path}#{lines}",
+ "{root}src/{krate}/{path}{anchor}",
root = Escape(&root),
krate = krate,
path = path,
- lines = lines
+ anchor = anchor
))
}
}
generate_redirect_map,
show_type_layout,
generate_link_to_definition,
+ call_locations,
..
} = options;
- let src_root = match krate.src {
+ let src_root = match krate.src(tcx) {
FileName::Real(ref p) => match p.local_path_if_available().parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
let mut playground = None;
if let Some(url) = playground_url {
playground =
- Some(markdown::Playground { crate_name: Some(krate.name.to_string()), url });
+ Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
}
let mut layout = layout::Layout {
logo: String::new(),
favicon: String::new(),
external_html,
default_settings,
- krate: krate.name.to_string(),
+ 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;
}
(sym::html_playground_url, Some(s)) => {
playground = Some(markdown::Playground {
- crate_name: Some(krate.name.to_string()),
+ crate_name: Some(krate.name(tcx).to_string()),
url: s.to_string(),
});
}
}
}
- let (mut krate, local_sources, matches) = collect_spans_and_sources(
+ let (local_sources, matches) = collect_spans_and_sources(
tcx,
- krate,
+ &krate,
&src_root,
include_sources,
generate_link_to_definition,
templates,
span_correspondance_map: matches,
cache,
+ call_locations,
};
// Add the default themes to the `Vec` of stylepaths
dst,
render_redirect_pages: false,
id_map: RefCell::new(id_map),
+ deref_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::new(scx),
include_sources,
};
if emit_crate {
- krate = sources::render(&mut cx, krate)?;
+ sources::render(&mut cx, &krate)?;
}
// Build our search index
current: self.current.clone(),
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
+ deref_id_map: RefCell::new(FxHashMap::default()),
id_map: RefCell::new(IdMap::new()),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
use std::collections::VecDeque;
use std::default::Default;
use std::fmt;
+use std::fs;
+use std::iter::Peekable;
use std::path::PathBuf;
use std::str;
use std::string::ToString;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{
+ symbol::{kw, sym, Symbol},
+ BytePos, FileName, RealFileName,
+};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use crate::clean::{self, GetDefId, ItemId, RenderedLink, SelfTy};
+use crate::clean::{self, ItemId, RenderedLink, SelfTy};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
href, print_abi_with_space, print_constness_with_space, print_default_space,
print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
};
+use crate::html::highlight;
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use crate::html::sources;
+use crate::scrape_examples::{CallData, CallLocation};
+use crate::try_none;
/// A pair of name and its optional document.
crate type NameDoc = (String, Option<String>);
#[derive(Debug)]
crate struct RenderType {
name: Option<String>,
- generics: Option<Vec<String>>,
+ generics: Option<Vec<TypeWithKind>>,
}
/// Full type of functions/methods in the search index.
// If we couldn't figure out a type, just write `null`.
let mut iter = self.inputs.iter();
if match self.output {
- Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
- None => iter.any(|ref i| i.ty.name.is_none()),
+ Some(ref output) => iter.chain(output.iter()).any(|i| i.ty.name.is_none()),
+ None => iter.any(|i| i.ty.name.is_none()),
} {
serializer.serialize_none()
} else {
render_markdown(w, cx, &s, item.links(cx), heading_offset);
}
}
+
+ let kind = match &*item.kind {
+ clean::ItemKind::StrippedItem(box kind) | kind => kind,
+ };
+
+ if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
+ render_call_locations(w, cx, item);
+ }
}
/// Add extra information about an item such as:
AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from an impl-item to the corresponding
// trait-item and need to map the anchored type accordingly.
- let ty = if provided_methods.contains(&name) {
+ let ty = if provided_methods.contains(name) {
ItemType::Method
} else {
ItemType::TyMethod
name = name,
generics = g.print(cx),
decl = d.full_print(header_len, indent, header.asyncness, cx),
- notable_traits = notable_traits_decl(&d, cx),
+ notable_traits = notable_traits_decl(d, cx),
where_clause = print_where_clause(g, cx, indent, end_newline),
)
}
.iter()
.filter_map(|attr| {
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
- Some(pprust::attribute_to_string(&attr).replace("\n", "").replace(" ", " "))
+ Some(pprust::attribute_to_string(attr).replace("\n", "").replace(" ", " "))
} else {
None
}
impl<'a> AssocItemLink<'a> {
fn anchor(&self, id: &'a str) -> Self {
match *self {
- AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
+ AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
ref other => *other,
}
}
containing_item: &clean::Item,
it: DefId,
what: AssocItemRender<'_>,
+) {
+ let mut derefs = FxHashSet::default();
+ derefs.insert(it);
+ render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
+}
+
+fn render_assoc_items_inner(
+ w: &mut Buffer,
+ cx: &Context<'_>,
+ containing_item: &clean::Item,
+ it: DefId,
+ what: AssocItemRender<'_>,
+ derefs: &mut FxHashSet<DefId>,
) {
info!("Documenting associated items of {:?}", containing_item.name);
let cache = cx.cache();
};
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
if !non_trait.is_empty() {
+ let mut tmp_buf = Buffer::empty_from(w);
let render_mode = match what {
AssocItemRender::All => {
- w.write_str(
+ tmp_buf.write_str(
"<h2 id=\"implementations\" class=\"small-section-header\">\
Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
</h2>",
RenderMode::Normal
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
+ let id =
+ cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
+ if let Some(def_id) = type_.def_id(cx.cache()) {
+ cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
+ }
write!(
- w,
- "<h2 id=\"deref-methods\" class=\"small-section-header\">\
+ tmp_buf,
+ "<h2 id=\"{id}\" class=\"small-section-header\">\
<span>Methods from {trait_}<Target = {type_}></span>\
- <a href=\"#deref-methods\" class=\"anchor\"></a>\
+ <a href=\"#{id}\" class=\"anchor\"></a>\
</h2>",
+ id = id,
trait_ = trait_.print(cx),
type_ = type_.print(cx),
);
RenderMode::ForDeref { mut_: deref_mut_ }
}
};
+ let mut impls_buf = Buffer::empty_from(w);
for i in &non_trait {
render_impl(
- w,
+ &mut impls_buf,
cx,
i,
containing_item,
},
);
}
+ if !impls_buf.is_empty() {
+ w.push_buffer(tmp_buf);
+ w.push_buffer(impls_buf);
+ }
}
- if let AssocItemRender::DerefFor { .. } = what {
- return;
- }
+
if !traits.is_empty() {
let deref_impl =
traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
if let Some(impl_) = deref_impl {
let has_deref_mut =
traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
- render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
+ render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
+ }
+
+ // If we were already one level into rendering deref methods, we don't want to render
+ // anything after recursing into any further deref methods above.
+ if let AssocItemRender::DerefFor { .. } = what {
+ return;
}
+
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
traits.iter().partition(|t| t.inner_impl().synthetic);
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
- let mut impls = Buffer::empty_from(&w);
+ let mut impls = Buffer::empty_from(w);
render_impls(cx, &mut impls, &concrete, containing_item);
let impls = impls.into_inner();
if !impls.is_empty() {
impl_: &Impl,
container_item: &clean::Item,
deref_mut: bool,
+ derefs: &mut FxHashSet<DefId>,
) {
let cache = cx.cache();
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
let what =
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
- if let Some(did) = target.def_id_full(cache) {
- if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cache) {
+ if let Some(did) = target.def_id(cache) {
+ if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
// `impl Deref<Target = S> for S`
- if did == type_did {
+ if did == type_did || !derefs.insert(did) {
// Avoid infinite cycles
return;
}
}
- render_assoc_items(w, cx, container_item, did, what);
+ render_assoc_items_inner(w, cx, container_item, did, what, derefs);
} else {
if let Some(prim) = target.primitive_type() {
if let Some(&did) = cache.primitive_locations.get(&prim) {
- render_assoc_items(w, cx, container_item, did, what);
+ render_assoc_items_inner(w, cx, container_item, did, what, derefs);
}
}
}
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
- if let Some(did) = decl.output.def_id_full(cx.cache()) {
+ if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
&& match render_mode {
RenderMode::Normal => true,
RenderMode::ForDeref { mut_: deref_mut_ } => {
- should_render_item(&item, deref_mut_, cx.tcx())
+ should_render_item(item, deref_mut_, cx.tcx())
}
};
&mut impl_items,
cx,
&t.trait_,
- &i.inner_impl(),
+ i.inner_impl(),
&i.impl_item,
parent,
render_mode,
error_codes: cx.shared.codes,
edition: cx.shared.edition(),
playground: &cx.shared.playground,
- heading_offset: HeadingOffset::H2
+ heading_offset: HeadingOffset::H4
}
.into_string()
);
if let Some(impl_) =
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
{
- sidebar_deref_methods(cx, out, impl_, v);
+ let mut derefs = FxHashSet::default();
+ derefs.insert(did);
+ sidebar_deref_methods(cx, out, impl_, v, &mut derefs);
}
let format_impls = |impls: Vec<&Impl>| {
}
}
-fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
+fn sidebar_deref_methods(
+ cx: &Context<'_>,
+ out: &mut Buffer,
+ impl_: &Impl,
+ v: &[Impl],
+ derefs: &mut FxHashSet<DefId>,
+) {
let c = cx.cache();
debug!("found Deref: {:?}", impl_);
})
{
debug!("found target, real_target: {:?} {:?}", target, real_target);
- if let Some(did) = target.def_id_full(c) {
- if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
+ if let Some(did) = target.def_id(c) {
+ if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
// `impl Deref<Target = S> for S`
- if did == type_did {
+ if did == type_did || !derefs.insert(did) {
// Avoid infinite cycles
return;
}
}
let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
let inner_impl = target
- .def_id_full(c)
+ .def_id(c)
.or_else(|| {
target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
})
})
.collect::<Vec<_>>();
if !ret.is_empty() {
+ let map;
+ let id = if let Some(target_def_id) = real_target.def_id(c) {
+ map = cx.deref_id_map.borrow();
+ map.get(&target_def_id).expect("Deref section without derived id")
+ } else {
+ "deref-methods"
+ };
write!(
out,
- "<h3 class=\"sidebar-title\"><a href=\"#deref-methods\">Methods from {}<Target={}></a></h3>",
+ "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}<Target={}></a></h3>",
+ id,
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
Escape(&format!("{:#}", real_target.print(cx))),
);
out.push_str("</div>");
}
}
+
+ // Recurse into any further impls that might exist for `target`
+ if let Some(target_did) = target.def_id_no_primitives() {
+ if let Some(target_impls) = c.impls.get(&target_did) {
+ if let Some(target_deref_impl) = target_impls.iter().find(|i| {
+ i.inner_impl()
+ .trait_
+ .as_ref()
+ .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
+ .unwrap_or(false)
+ }) {
+ sidebar_deref_methods(cx, out, target_deref_impl, target_impls, derefs);
+ }
+ }
+ }
}
}
fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
match *item.kind {
clean::ItemKind::ImplItem(ref i) => {
- if let Some(ref trait_) = i.trait_ {
+ i.trait_.as_ref().map(|trait_| {
// Alternative format produces no URLs,
// so this parameter does nothing.
- Some((
+ (
format!("{:#}", i.for_.print(cx)),
get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
- ))
- } else {
- None
- }
+ )
+ })
}
_ => None,
}
let mut res = implementors
.iter()
.filter(|i| {
- i.inner_impl()
- .for_
- .def_id_full(cache)
- .map_or(false, |d| !cache.paths.contains_key(&d))
+ i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
})
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
.collect::<Vec<_>>();
let mut variants = e
.variants
.iter()
- .filter_map(|v| match v.name {
- Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
- _ => None,
+ .filter_map(|v| {
+ v.name
+ .as_ref()
+ .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
})
.collect::<Vec<_>>();
if !variants.is_empty() {
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
ItemType::ProcDerive => ("derives", "Derive Macros"),
ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
+ ItemType::Generic => unreachable!(),
}
}
}
out
}
+
+const MAX_FULL_EXAMPLES: usize = 5;
+const NUM_VISIBLE_LINES: usize = 10;
+
+/// Generates the HTML for example call locations generated via the --scrape-examples flag.
+fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
+ let tcx = cx.tcx();
+ let def_id = item.def_id.expect_def_id();
+ let key = tcx.def_path_hash(def_id);
+ let call_locations = match cx.shared.call_locations.get(&key) {
+ Some(call_locations) => call_locations,
+ _ => {
+ return;
+ }
+ };
+
+ // Generate a unique ID so users can link to this section for a given method
+ let id = cx.id_map.borrow_mut().derive("scraped-examples");
+ write!(
+ w,
+ "<div class=\"docblock scraped-example-list\">\
+ <span></span>\
+ <h5 id=\"{id}\" class=\"section-header\">\
+ <a href=\"#{id}\">Examples found in repository</a>\
+ </h5>",
+ id = id
+ );
+
+ // Create a URL to a particular location in a reverse-dependency's source file
+ let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
+ let (line_lo, line_hi) = loc.call_expr.line_span;
+ let (anchor, title) = if line_lo == line_hi {
+ ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
+ } else {
+ (
+ format!("{}-{}", line_lo + 1, line_hi + 1),
+ format!("lines {}-{}", line_lo + 1, line_hi + 1),
+ )
+ };
+ let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+ (url, title)
+ };
+
+ // Generate the HTML for a single example, being the title and code block
+ let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
+ let contents = match fs::read_to_string(&path) {
+ Ok(contents) => contents,
+ Err(err) => {
+ let span = item.span(tcx).inner();
+ tcx.sess
+ .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
+ return false;
+ }
+ };
+
+ // To reduce file sizes, we only want to embed the source code needed to understand the example, not
+ // the entire file. So we find the smallest byte range that covers all items enclosing examples.
+ assert!(!call_data.locations.is_empty());
+ let min_loc =
+ call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
+ let byte_min = min_loc.enclosing_item.byte_span.0;
+ let line_min = min_loc.enclosing_item.line_span.0;
+ let max_loc =
+ call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
+ let byte_max = max_loc.enclosing_item.byte_span.1;
+ let line_max = max_loc.enclosing_item.line_span.1;
+
+ // The output code is limited to that byte range.
+ let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
+
+ // The call locations need to be updated to reflect that the size of the program has changed.
+ // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
+ let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
+ .locations
+ .iter()
+ .map(|loc| {
+ let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+ let (line_lo, line_hi) = loc.call_expr.line_span;
+ let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
+ let line_range = (line_lo - line_min, line_hi - line_min);
+ let (line_url, line_title) = link_to_loc(call_data, loc);
+
+ (byte_range, (line_range, line_url, line_title))
+ })
+ .unzip();
+
+ let (_, init_url, init_title) = &line_ranges[0];
+ let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
+ let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
+
+ write!(
+ w,
+ "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
+ <div class=\"scraped-example-title\">\
+ {name} (<a href=\"{url}\">{title}</a>)\
+ </div>\
+ <div class=\"code-wrapper\">",
+ expanded_cls = if needs_expansion { "" } else { "expanded" },
+ name = call_data.display_name,
+ url = init_url,
+ title = init_title,
+ // The locations are encoded as a data attribute, so they can be read
+ // later by the JS for interactions.
+ locations = Escape(&locations_encoded)
+ );
+
+ if line_ranges.len() > 1 {
+ write!(w, r#"<span class="prev">≺</span> <span class="next">≻</span>"#);
+ }
+
+ if needs_expansion {
+ write!(w, r#"<span class="expand">↕</span>"#);
+ }
+
+ // Look for the example file in the source map if it exists, otherwise return a dummy span
+ let file_span = (|| {
+ let source_map = tcx.sess.source_map();
+ let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+ let abs_crate_src = crate_src.canonicalize().ok()?;
+ let crate_root = abs_crate_src.parent()?.parent()?;
+ let rel_path = path.strip_prefix(crate_root).ok()?;
+ let files = source_map.files();
+ let file = files.iter().find(|file| match &file.name {
+ FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
+ _ => false,
+ })?;
+ Some(rustc_span::Span::with_root_ctxt(
+ file.start_pos + BytePos(byte_min),
+ file.start_pos + BytePos(byte_max),
+ ))
+ })()
+ .unwrap_or(rustc_span::DUMMY_SP);
+
+ // The root path is the inverse of Context::current
+ let root_path = vec!["../"; cx.current.len() - 1].join("");
+
+ let mut decoration_info = FxHashMap::default();
+ decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+ decoration_info.insert("highlight", byte_ranges);
+
+ sources::print_src(
+ w,
+ contents_subset,
+ call_data.edition,
+ file_span,
+ cx,
+ &root_path,
+ Some(highlight::DecorationInfo(decoration_info)),
+ sources::SourceContext::Embedded { offset: line_min },
+ );
+ write!(w, "</div></div>");
+
+ true
+ };
+
+ // The call locations are output in sequence, so that sequence needs to be determined.
+ // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
+ // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
+ // understand at a glance.
+ let ordered_locations = {
+ let sort_criterion = |(_, call_data): &(_, &CallData)| {
+ // Use the first location because that's what the user will see initially
+ let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
+ hi - lo
+ };
+
+ let mut locs = call_locations.into_iter().collect::<Vec<_>>();
+ locs.sort_by_key(sort_criterion);
+ locs
+ };
+
+ let mut it = ordered_locations.into_iter().peekable();
+
+ // An example may fail to write if its source can't be read for some reason, so this method
+ // continues iterating until a write suceeds
+ let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+ while let Some(example) = it.next() {
+ if write_example(&mut *w, example) {
+ break;
+ }
+ }
+ };
+
+ // Write just one example that's visible by default in the method's description.
+ write_and_skip_failure(w, &mut it);
+
+ // Then add the remaining examples in a hidden section.
+ if it.peek().is_some() {
+ write!(
+ w,
+ "<details class=\"rustdoc-toggle more-examples-toggle\">\
+ <summary class=\"hideme\">\
+ <span>More examples</span>\
+ </summary>\
+ <div class=\"more-scraped-examples\">\
+ <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
+ <div class=\"more-scraped-examples-inner\">"
+ );
+
+ // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
+ // make the page arbitrarily huge!
+ for _ in 0..MAX_FULL_EXAMPLES {
+ write_and_skip_failure(w, &mut it);
+ }
+
+ // For the remaining examples, generate a <ul> containing links to the source files.
+ if it.peek().is_some() {
+ write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
+ it.for_each(|(_, call_data)| {
+ let (url, _) = link_to_loc(&call_data, &call_data.locations[0]);
+ write!(
+ w,
+ r#"<li><a href="{url}">{name}</a></li>"#,
+ url = url,
+ name = call_data.display_name
+ );
+ });
+ write!(w, "</ul></div>");
+ }
+
+ write!(w, "</div></div></details>");
+ }
+
+ write!(w, "</div>");
+}
render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
ImplRenderingParameters,
};
-use crate::clean::{self, GetDefId};
+use crate::clean;
use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape;
use serde::Serialize;
-const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &'static str = "</div>";
-const ITEM_TABLE_ROW_OPEN: &'static str = "<div class=\"item-row\">";
-const ITEM_TABLE_ROW_CLOSE: &'static str = "</div>";
+const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
+const ITEM_TABLE_CLOSE: &str = "</div>";
+const ITEM_TABLE_ROW_OPEN: &str = "<div class=\"item-row\">";
+const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
// A component in a `use` path, like `string` in std::string::ToString
#[derive(Serialize)]
+ name.as_str().len()
+ generics_len;
- wrap_item(w, "fn", |w| {
- render_attributes_in_pre(w, it, "");
- w.reserve(header_len);
- write!(
- w,
- "{vis}{constness}{asyncness}{unsafety}{abi}fn \
- {name}{generics}{decl}{notable_traits}{where_clause}",
- vis = vis,
- constness = constness,
- asyncness = asyncness,
- unsafety = unsafety,
- abi = abi,
- name = name,
- generics = f.generics.print(cx),
- where_clause = print_where_clause(&f.generics, cx, 0, true),
- decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
- notable_traits = notable_traits_decl(&f.decl, cx),
- );
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "fn", |w| {
+ render_attributes_in_pre(w, it, "");
+ w.reserve(header_len);
+ write!(
+ w,
+ "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+ {name}{generics}{decl}{notable_traits}{where_clause}",
+ vis = vis,
+ constness = constness,
+ asyncness = asyncness,
+ unsafety = unsafety,
+ abi = abi,
+ name = name,
+ generics = f.generics.print(cx),
+ where_clause = print_where_clause(&f.generics, cx, 0, true),
+ decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
+ notable_traits = notable_traits_decl(&f.decl, cx),
+ );
+ });
});
document(w, cx, it, None, HeadingOffset::H2)
}
}
let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
- i.inner_impl().for_.def_id_full(cache).map_or(true, |d| cache.paths.contains_key(&d))
+ i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
});
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
render_impl(
w,
cx,
- &implementor,
+ implementor,
it,
assoc_link,
RenderMode::Normal,
}
fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
- wrap_item(w, "trait-alias", |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "trait {}{}{} = {};",
- it.name.as_ref().unwrap(),
- t.generics.print(cx),
- print_where_clause(&t.generics, cx, 0, true),
- bounds(&t.bounds, true, cx)
- );
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "trait-alias", |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "trait {}{}{} = {};",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx),
+ print_where_clause(&t.generics, cx, 0, true),
+ bounds(&t.bounds, true, cx)
+ );
+ });
});
document(w, cx, it, None, HeadingOffset::H2);
}
fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
- wrap_item(w, "opaque", |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "type {}{}{where_clause} = impl {bounds};",
- it.name.as_ref().unwrap(),
- t.generics.print(cx),
- where_clause = print_where_clause(&t.generics, cx, 0, true),
- bounds = bounds(&t.bounds, false, cx),
- );
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "opaque", |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "type {}{}{where_clause} = impl {bounds};",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx),
+ where_clause = print_where_clause(&t.generics, cx, 0, true),
+ bounds = bounds(&t.bounds, false, cx),
+ );
+ });
});
document(w, cx, it, None, HeadingOffset::H2);
t: &clean::Typedef,
is_associated: bool,
) {
- wrap_item(w, "typedef", |w| {
- render_attributes_in_pre(w, it, "");
- if !is_associated {
- write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
- }
- write!(
- w,
- "type {}{}{where_clause} = {type_};",
- it.name.as_ref().unwrap(),
- t.generics.print(cx),
- where_clause = print_where_clause(&t.generics, cx, 0, true),
- type_ = t.type_.print(cx),
- );
- });
+ fn write_content(
+ w: &mut Buffer,
+ cx: &Context<'_>,
+ it: &clean::Item,
+ t: &clean::Typedef,
+ is_associated: bool,
+ ) {
+ wrap_item(w, "typedef", |w| {
+ render_attributes_in_pre(w, it, "");
+ if !is_associated {
+ write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
+ }
+ write!(
+ w,
+ "type {}{}{where_clause} = {type_};",
+ it.name.as_ref().unwrap(),
+ t.generics.print(cx),
+ where_clause = print_where_clause(&t.generics, cx, 0, true),
+ type_ = t.type_.print(cx),
+ );
+ });
+ }
+
+ // If this is an associated typedef, we don't want to wrap it into a docblock.
+ if is_associated {
+ write_content(w, cx, it, t, is_associated);
+ } else {
+ wrap_into_docblock(w, |w| {
+ write_content(w, cx, it, t, is_associated);
+ });
+ }
document(w, cx, it, None, HeadingOffset::H2);
if let Some(stability_class) = field.stability_class(cx.tcx()) {
write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
}
- document(w, cx, field, Some(it), HeadingOffset::H2);
+ document(w, cx, field, Some(it), HeadingOffset::H3);
}
}
let def_id = it.def_id.expect_def_id();
w.write_str("</code>");
render_stability_since(w, variant, it, cx.tcx());
w.write_str("</div>");
- document(w, cx, variant, Some(it), HeadingOffset::H2);
+ document(w, cx, variant, Some(it), HeadingOffset::H3);
document_non_exhaustive(w, variant);
use crate::clean::Variant;
f = field.name.as_ref().unwrap(),
t = ty.print(cx)
);
- document(w, cx, field, Some(variant), HeadingOffset::H2);
+ document(w, cx, field, Some(variant), HeadingOffset::H4);
}
_ => unreachable!(),
}
it.span(cx.tcx()).inner().edition(),
None,
None,
+ None,
);
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
- let name = it.name.as_ref().expect("proc-macros always have names");
- match m.kind {
- MacroKind::Bang => {
- wrap_item(w, "macro", |w| {
- write!(w, "{}!() {{ /* proc-macro */ }}", name);
- });
- }
- MacroKind::Attr => {
- wrap_item(w, "attr", |w| {
- write!(w, "#[{}]", name);
- });
- }
- MacroKind::Derive => {
- wrap_item(w, "derive", |w| {
- write!(w, "#[derive({})]", name);
- if !m.helpers.is_empty() {
- w.push_str("\n{\n");
- w.push_str(" // Attributes available to this derive:\n");
- for attr in &m.helpers {
- writeln!(w, " #[{}]", attr);
+ wrap_into_docblock(w, |w| {
+ let name = it.name.as_ref().expect("proc-macros always have names");
+ match m.kind {
+ MacroKind::Bang => {
+ wrap_item(w, "macro", |w| {
+ write!(w, "{}!() {{ /* proc-macro */ }}", name);
+ });
+ }
+ MacroKind::Attr => {
+ wrap_item(w, "attr", |w| {
+ write!(w, "#[{}]", name);
+ });
+ }
+ MacroKind::Derive => {
+ wrap_item(w, "derive", |w| {
+ write!(w, "#[derive({})]", name);
+ if !m.helpers.is_empty() {
+ w.push_str("\n{\n");
+ w.push_str(" // Attributes available to this derive:\n");
+ for attr in &m.helpers {
+ writeln!(w, " #[{}]", attr);
+ }
+ w.push_str("}\n");
}
- w.push_str("}\n");
- }
- });
+ });
+ }
}
- }
+ });
document(w, cx, it, None, HeadingOffset::H2)
}
}
fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
- wrap_item(w, "const", |w| {
- render_attributes_in_code(w, it);
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "const", |w| {
+ render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}const {name}: {typ}",
- vis = it.visibility.print_with_space(it.def_id, cx),
- name = it.name.as_ref().unwrap(),
- typ = c.type_.print(cx),
- );
+ write!(
+ w,
+ "{vis}const {name}: {typ}",
+ vis = it.visibility.print_with_space(it.def_id, cx),
+ name = it.name.as_ref().unwrap(),
+ typ = c.type_.print(cx),
+ );
- let value = c.value(cx.tcx());
- let is_literal = c.is_literal(cx.tcx());
- let expr = c.expr(cx.tcx());
- if value.is_some() || is_literal {
- write!(w, " = {expr};", expr = Escape(&expr));
- } else {
- w.write_str(";");
- }
+ let value = c.value(cx.tcx());
+ let is_literal = c.is_literal(cx.tcx());
+ let expr = c.expr(cx.tcx());
+ if value.is_some() || is_literal {
+ write!(w, " = {expr};", expr = Escape(&expr));
+ } else {
+ w.write_str(";");
+ }
- if !is_literal {
- if let Some(value) = &value {
- let value_lowercase = value.to_lowercase();
- let expr_lowercase = expr.to_lowercase();
+ if !is_literal {
+ if let Some(value) = &value {
+ let value_lowercase = value.to_lowercase();
+ let expr_lowercase = expr.to_lowercase();
- if value_lowercase != expr_lowercase
- && value_lowercase.trim_end_matches("i32") != expr_lowercase
- {
- write!(w, " // {value}", value = Escape(value));
+ if value_lowercase != expr_lowercase
+ && value_lowercase.trim_end_matches("i32") != expr_lowercase
+ {
+ write!(w, " // {value}", value = Escape(value));
+ }
}
}
- }
+ });
});
document(w, cx, it, None, HeadingOffset::H2)
name = field_name,
ty = ty.print(cx)
);
- document(w, cx, field, Some(it), HeadingOffset::H2);
+ document(w, cx, field, Some(it), HeadingOffset::H3);
}
}
}
}
fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
- wrap_item(w, "static", |w| {
- render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}static {mutability}{name}: {typ}",
- vis = it.visibility.print_with_space(it.def_id, cx),
- mutability = s.mutability.print_with_space(),
- name = it.name.as_ref().unwrap(),
- typ = s.type_.print(cx)
- );
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "static", |w| {
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ "{vis}static {mutability}{name}: {typ}",
+ vis = it.visibility.print_with_space(it.def_id, cx),
+ mutability = s.mutability.print_with_space(),
+ name = it.name.as_ref().unwrap(),
+ typ = s.type_.print(cx)
+ );
+ });
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
- wrap_item(w, "foreigntype", |w| {
- w.write_str("extern {\n");
- render_attributes_in_code(w, it);
- write!(
- w,
- " {}type {};\n}}",
- it.visibility.print_with_space(it.def_id, cx),
- it.name.as_ref().unwrap(),
- );
+ wrap_into_docblock(w, |w| {
+ wrap_item(w, "foreigntype", |w| {
+ w.write_str("extern {\n");
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ " {}type {};\n}}",
+ it.visibility.print_with_space(it.def_id, cx),
+ it.name.as_ref().unwrap(),
+ );
+ });
});
document(w, cx, it, None, HeadingOffset::H2);
where
F: FnOnce(&mut Buffer),
{
- w.write_str("<div class=\"docblock type-decl\">");
+ w.write_str("<div class=\"docblock item-decl\">");
f(w);
w.write_str("</div>")
}
);
if let Some(g) = g {
write!(w, "{}", g.print(cx));
- write!(w, "{}", print_where_clause(&g, cx, 0, true));
+ write!(w, "{}", print_where_clause(g, cx, 0, true));
}
write!(w, " {{\n{}", tab);
/// only keep the `lo` and `hi`.
crate fn collect_spans_and_sources(
tcx: TyCtxt<'_>,
- krate: clean::Crate,
+ krate: &clean::Crate,
src_root: &Path,
include_sources: bool,
generate_link_to_definition: bool,
-) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
if include_sources {
if generate_link_to_definition {
tcx.hir().walk_toplevel_module(&mut visitor);
}
- let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate);
- (krate, sources, visitor.matches)
+ let sources = sources::collect_local_sources(tcx, src_root, &krate);
+ (sources, visitor.matches)
} else {
- (krate, Default::default(), Default::default())
+ (Default::default(), Default::default())
}
}
}
for bound in p.bounds {
if let Some(trait_ref) = bound.trait_ref() {
- self.handle_path(&trait_ref.path, None);
+ self.handle_path(trait_ref.path, None);
}
}
}
if !span.overlaps(m.inner) {
// Now that we confirmed it's a file import, we want to get the span for the module
// name only and not all the "mod foo;".
- if let Some(node) = self.tcx.hir().find(id) {
- match node {
- Node::Item(item) => {
- self.matches
- .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
- }
- _ => {}
- }
+ if let Some(Node::Item(item)) = self.tcx.hir().find(id) {
+ self.matches.insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
}
}
intravisit::walk_mod(self, m, id);
}
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
- match expr.kind {
- ExprKind::MethodCall(segment, method_span, _, _) => {
- if let Some(hir_id) = segment.hir_id {
- let hir = self.tcx.hir();
- let body_id = hir.enclosing_body_owner(hir_id);
- let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
- self.tcx.typeck_body(
- hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
- )
- });
- if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
- self.matches.insert(
- method_span,
- match hir.span_if_local(def_id) {
- Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
- None => LinkFromSrc::External(def_id),
- },
- );
- }
+ if let ExprKind::MethodCall(segment, method_span, _, _) = expr.kind {
+ if let Some(hir_id) = segment.hir_id {
+ let hir = self.tcx.hir();
+ let body_id = hir.enclosing_body_owner(hir_id);
+ let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+ self.tcx.typeck_body(
+ hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+ )
+ });
+ if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+ self.matches.insert(
+ method_span,
+ match hir.span_if_local(def_id) {
+ Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+ None => LinkFromSrc::External(def_id),
+ },
+ );
}
}
- _ => {}
}
intravisit::walk_expr(self, expr);
}
use crate::docfs::PathError;
use crate::error::Error;
use crate::html::{layout, static_files};
+use crate::{try_err, try_none};
static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
map! {
"SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
"SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
"SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
- "noto-sans-kr-regular.woff2" => static_files::noto_sans_kr::REGULAR2,
- "noto-sans-kr-regular.woff" => static_files::noto_sans_kr::REGULAR,
- "noto-sans-kr-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
+ "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
+ "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+ "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
"COPYRIGHT.txt" => static_files::COPYRIGHT,
) -> Result<(), Error> {
if minify {
let contents = contents.as_ref();
- let contents = if resource.extension() == Some(&OsStr::new("css")) {
+ let contents = if resource.extension() == Some(OsStr::new("css")) {
minifier::css::minify(contents).map_err(|e| {
Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
})?
)?;
}
+ if cx.shared.layout.scrape_examples_extension {
+ cx.write_minify(
+ SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
+ static_files::SCRAPE_EXAMPLES_JS,
+ options.enable_minification,
+ &options.emit,
+ )?;
+ }
+
if let Some(ref css) = cx.shared.layout.css_file_extension {
let buffer = try_err!(fs::read_to_string(css), css);
// This varies based on the invocation, so it can't go through the write_minify wrapper.
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
- try_err!(collect(&dst, &krate.name.as_str(), "sourcesIndex"), &dst);
+ try_err!(collect(&dst, &krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
all_sources.push(format!(
"sourcesIndex[\"{}\"] = {};",
- &krate.name,
+ &krate.name(cx.tcx()),
hierarchy.to_json_string()
));
all_sources.sort();
// Update the search index and crate list.
let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
- let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst);
+ let (mut all_indexes, mut krates) =
+ try_err!(collect_json(&dst, &krate.name(cx.tcx()).as_str()), &dst);
all_indexes.push(search_index);
- krates.push(krate.name.to_string());
+ krates.push(krate.name(cx.tcx()).to_string());
krates.sort();
// Sort the indexes by crate so the file will be generated identically even
let implementors = format!(
r#"implementors["{}"] = {};"#,
- krate.name,
+ krate.name(cx.tcx()),
serde_json::to_string(&implementors).unwrap()
);
mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
let (mut all_implementors, _) =
- try_err!(collect(&mydst, &krate.name.as_str(), "implementors"), &mydst);
+ try_err!(collect(&mydst, &krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
all_implementors.push(implementors);
// Sort the implementors by crate so the file will be generated
// identically even with rustdoc running in parallel.
use crate::clean;
use crate::docfs::PathError;
use crate::error::Error;
-use crate::fold::DocFolder;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
use crate::html::render::{Context, BASIC_KEYWORDS};
+use crate::visit::DocVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use std::fs;
use std::path::{Component, Path, PathBuf};
-crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> {
+crate fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
info!("emitting source files");
- let dst = cx.dst.join("src").join(&*krate.name.as_str());
+
+ let dst = cx.dst.join("src").join(&*krate.name(cx.tcx()).as_str());
cx.shared.ensure_dir(&dst)?;
- let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
- Ok(folder.fold_crate(krate))
+
+ let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
+ collector.visit_crate(krate);
+ Ok(())
}
crate fn collect_local_sources<'tcx>(
tcx: TyCtxt<'tcx>,
src_root: &Path,
- krate: clean::Crate,
-) -> (clean::Crate, FxHashMap<PathBuf, String>) {
+ krate: &clean::Crate,
+) -> FxHashMap<PathBuf, String> {
let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
-
- let krate = lsc.fold_crate(krate);
- (krate, lsc.local_sources)
+ lsc.visit_crate(krate);
+ lsc.local_sources
}
struct LocalSourcesCollector<'a, 'tcx> {
}
fn is_real_and_local(span: clean::Span, sess: &Session) -> bool {
- span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE
+ span.cnum(sess) == LOCAL_CRATE && span.filename(sess).is_real()
}
impl LocalSourcesCollector<'_, '_> {
return;
}
let filename = span.filename(sess);
- let p = match filename {
- FileName::Real(ref file) => match file.local_path() {
- Some(p) => p.to_path_buf(),
- _ => return,
- },
- _ => return,
+ let p = if let FileName::Real(file) = filename {
+ match file.into_local_path() {
+ Some(p) => p,
+ None => return,
+ }
+ } else {
+ return;
};
if self.local_sources.contains_key(&*p) {
// We've already emitted this source
}
let mut href = String::new();
- clean_path(&self.src_root, &p, false, |component| {
+ clean_path(self.src_root, &p, false, |component| {
href.push_str(&component.to_string_lossy());
href.push('/');
});
}
}
-impl DocFolder for LocalSourcesCollector<'_, '_> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
- self.add_local_source(&item);
+impl DocVisitor for LocalSourcesCollector<'_, '_> {
+ fn visit_item(&mut self, item: &clean::Item) {
+ self.add_local_source(item);
- // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
- // we could return None here without having to walk the rest of the crate.
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
emitted_local_sources: FxHashSet<PathBuf>,
}
-impl DocFolder for SourceCollector<'_, '_> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl DocVisitor for SourceCollector<'_, '_> {
+ fn visit_item(&mut self, item: &clean::Item) {
+ if !self.cx.include_sources {
+ return;
+ }
+
let tcx = self.cx.tcx();
let span = item.span(tcx);
let sess = tcx.sess;
// If we're not rendering sources, there's nothing to do.
// If we're including source files, and we haven't seen this file yet,
// then we need to render it out to the filesystem.
- if self.cx.include_sources && is_real_and_local(span, sess) {
+ if is_real_and_local(span, sess) {
let filename = span.filename(sess);
let span = span.inner();
let pos = sess.source_map().lookup_source_file(span.lo());
}
};
}
- // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
- // we could return None here without having to walk the rest of the crate.
- Some(self.fold_item_recur(item))
+
+ self.visit_item_recur(item)
}
}
};
// Remove the utf-8 BOM if any
- let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
+ let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents);
// Create the intermediate directories
let mut cur = self.dst.clone();
&page,
"",
|buf: &mut _| {
- print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+ print_src(
+ buf,
+ contents,
+ self.cx.shared.edition(),
+ file_span,
+ self.cx,
+ &root_path,
+ None,
+ SourceContext::Standalone,
+ )
},
&self.cx.shared.style_files,
);
}
}
+crate enum SourceContext {
+ Standalone,
+ Embedded { offset: usize },
+}
+
/// Wrapper struct to render the source code of a file. This will do things like
/// adding line numbers to the left-hand side.
-fn print_src(
+crate fn print_src(
buf: &mut Buffer,
s: &str,
edition: Edition,
file_span: rustc_span::Span,
context: &Context<'_>,
root_path: &str,
+ decoration_info: Option<highlight::DecorationInfo>,
+ source_context: SourceContext,
) {
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
}
line_numbers.write_str("<pre class=\"line-numbers\">");
for i in 1..=lines {
- writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
+ match source_context {
+ SourceContext::Standalone => {
+ writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols)
+ }
+ SourceContext::Embedded { offset } => {
+ writeln!(line_numbers, "<span>{0:1$}</span>", i + offset, cols)
+ }
+ }
}
line_numbers.write_str("</pre>");
highlight::render_with_highlighting(
edition,
Some(line_numbers),
Some(highlight::ContextInfo { context, file_span, root_path }),
+ decoration_info,
);
}
/* It requires JS to work so no need to display it in this case. */
display: none;
}
+
+.sub {
+ /* The search bar and related controls don't work without JS */
+ display: none;
+}
+
+#theme-picker {
+ display: none;
+}
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
@font-face {
- font-family: 'Noto Sans KR';
- src: url("noto-sans-kr-regular.woff2") format("woff2"),
- url("noto-sans-kr-regular.woff") format("woff");
+ font-family: 'NanumBarunGothic';
+ src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
+ url("NanumBarunGothic.ttf.woff") format("woff");
font-display: swap;
- unicode-range: U+AC00-D7AF, U+3130-318F, U+1100-11FF, U+A960-A97F, U+D7B0-D7FF;
+ unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
}
* {
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
+ font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 500;
+}
+h1, h2, h3, h4 {
margin: 20px 0 15px 0;
padding-bottom: 6px;
}
+.docblock h3, .docblock h4, h5, h6 {
+ margin: 15px 0 5px 0;
+}
h1.fqn {
display: flex;
border-bottom: 1px dashed;
h1.fqn > .in-band > a:hover {
text-decoration: underline;
}
-h2, h3, h4 {
+/* 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)
+ Underlines elsewhere in the documentation break up visual flow and tend to invert
+ section hierarchies. */
+h2,
+.top-doc h3,
+.top-doc h4,
+.sidebar .others h3 {
border-bottom: 1px solid;
}
-h3.code-header, h4.code-header {
+h3.code-header {
+ font-size: 1.1em;
+}
+h4.code-header {
font-size: 1em;
+}
+h3.code-header, h4.code-header {
font-weight: 600;
- border: none;
+ border-bottom-style: none;
padding: 0;
margin: 0;
}
margin-bottom: 10px;
position: relative;
}
-.impl, .method.trait-impl,
-.type.trait-impl,
-.associatedconstant.trait-impl,
-.associatedtype.trait-impl {
- padding-left: 15px;
-}
div.impl-items > div {
padding-left: 0;
.content ul.crate a.crate, a.srclink,
/* This selector is for the items listed in the "all items" page. */
#main > ul.docblock > li > a {
- font-family: "Fira Sans", Arial, sans-serif;
+ font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
}
.content ul.crate a.crate {
pre {
padding: 14px;
}
-.type-decl pre {
+.docblock.item-decl {
+ margin-left: 0;
+}
+.item-decl pre {
overflow-x: auto;
}
overflow-x: auto;
}
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+ width: auto;
+ overflow-x: visible;
+}
+
.rustdoc .example-wrap > pre {
margin: 0;
}
white-space: pre-wrap;
}
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
- border-bottom: 1px solid;
-}
-
.top-doc .docblock h2 { font-size: 1.3em; }
.top-doc .docblock h3 { font-size: 1.15em; }
.top-doc .docblock h4,
-.top-doc .docblock h5,
+.top-doc .docblock h5 {
+ font-size: 1.1em;
+}
.top-doc .docblock h6 {
font-size: 1em;
}
position: relative;
}
-.docblock > * {
+.docblock > :not(.information) {
max-width: 100%;
overflow-x: auto;
}
flex-grow: 1;
margin: 0px;
padding: 0px;
+ overflow-wrap: anywhere;
}
.in-band > code, .in-band > .code-header {
left: -19px;
}
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
-.impl-items > .associatedtype, .content .impl-items details > summary > .type,
-.impl-items details > summary > .associatedconstant,
-.impl-items details > summary > .associatedtype {
- margin-left: 20px;
-}
-
.content .impl-items .docblock, .content .impl-items .item-info {
margin-bottom: .6em;
}
.anchor {
display: none;
position: absolute;
- left: 0;
+ left: -0.5em;
background: none !important;
}
.anchor.field {
details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- left: -23px;
+ left: -24px;
top: 3px;
}
.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- left: -2px;
+ left: -24px;
}
/* When a "hideme" summary is open and the "Expand description" or "Show
overflow-wrap: anywhere;
}
}
+
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-title {
+ font-family: 'Fira Sans';
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+ overflow: hidden;
+ max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+ overflow-y: hidden;
+ max-height: 240px;
+ padding-bottom: 0;
+}
+
+.scraped-example .code-wrapper .prev {
+ position: absolute;
+ top: 0.25em;
+ right: 2.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+ position: absolute;
+ top: 0.25em;
+ right: 1.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+ position: absolute;
+ top: 0.25em;
+ right: 0.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper {
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ top: 0;
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ bottom: 0;
+ background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+ overflow: hidden;
+ max-height: 240px;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+ margin: 0;
+ padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+ padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+ flex: 1;
+ overflow-x: auto;
+ overflow-y: hidden;
+ margin-bottom: 0;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+ overflow-x: inherit;
+ width: inherit;
+ overflow-y: hidden;
+}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: #fcffd6;
+}
+
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: #f6fdb0;
+}
+
+.more-examples-toggle {
+ margin-top: 10px;
+}
+
+.more-examples-toggle summary {
+ color: #999;
+ font-family: 'Fira Sans';
+}
+
+.more-scraped-examples {
+ margin-left: 25px;
+ display: flex;
+ flex-direction: row;
+ width: calc(100% - 25px);
+}
+
+.more-scraped-examples-inner {
+ /* 20px is width of toggle-line + toggle-line-inner */
+ width: calc(100% - 20px);
+}
+
+.toggle-line {
+ align-self: stretch;
+ margin-right: 10px;
+ margin-top: 5px;
+ padding: 0 4px;
+ cursor: pointer;
+}
+
+.toggle-line:hover .toggle-line-inner {
+ background: #aaa;
+}
+
+.toggle-line-inner {
+ min-width: 2px;
+ background: #ddd;
+ height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+ margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+ margin-bottom: 0;
+}
+
+.example-links a {
+ margin-top: 20px;
+ font-family: 'Fira Sans';
+}
+
+.example-links ul {
+ margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
background: #333;
}
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
#help a {
color: #39AFD7;
box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
}
-.search-input:disabled {
- background-color: #3e3e3e;
-}
-
.module-item .stab,
.import-item .stab {
color: #000;
input:checked + .slider {
background-color: #ffb454 !important;
}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+ background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: ##898989;
+}
background: #333;
}
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
#help a {
color: #D2991D;
border-color: #008dfd;
}
-.search-input:disabled {
- background-color: #c5c4c4;
-}
-
#crate-search + .search-input:focus {
box-shadow: 0 0 8px 4px #078dd8;
}
.setting-line > .title {
border-bottom-color: #ddd;
}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+ background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: ##898989;
+}
background: #eee;
}
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
#help a {
color: #3873AD;
border-color: #66afe9;
}
-.search-input:disabled {
- background-color: #e6e6e6;
-}
-
#crate-search + .search-input:focus {
box-shadow: 0 0 8px #078dd8;
}
--- /dev/null
+Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
+
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
+NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
+Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
+NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
+Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+++ /dev/null
-Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
search_input.placeholder = searchState.input.origPlaceholder;
});
- search_input.removeAttribute('disabled');
+ if (search_input.value != '') {
+ loadSearch();
+ }
// `crates{version}.js` should always be loaded before this script, so we can use it
// safely.
// delayed sidebar rendering.
window.initSidebarItems = function(items) {
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
+ var others;
var current = window.sidebarCurrent;
function addSidebarCrates(crates) {
li.appendChild(link);
ul.appendChild(li);
}
- sidebar.appendChild(div);
+ others.appendChild(div);
}
function block(shortty, longty) {
ul.appendChild(li);
}
div.appendChild(ul);
- sidebar.appendChild(div);
+ others.appendChild(div);
}
if (sidebar) {
+ others = document.createElement("div");
+ others.className = "others";
+ sidebar.appendChild(others);
+
var isModule = hasClass(document.body, "mod");
if (!isModule) {
block("primitive", "Primitive Types");
--- /dev/null
+/* global addClass, hasClass, removeClass, onEach */
+
+(function () {
+ // Scroll code block to put the given code location in the middle of the viewer
+ function scrollToLoc(elt, loc) {
+ var wrapper = elt.querySelector(".code-wrapper");
+ var halfHeight = wrapper.offsetHeight / 2;
+ var lines = elt.querySelector('.line-numbers');
+ var offsetMid = (lines.children[loc[0]].offsetTop
+ + lines.children[loc[1]].offsetTop) / 2;
+ var scrollOffset = offsetMid - halfHeight;
+ lines.scrollTo(0, scrollOffset);
+ elt.querySelector(".rust").scrollTo(0, scrollOffset);
+ }
+
+ function updateScrapedExample(example) {
+ var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+ var locIndex = 0;
+ var highlights = example.querySelectorAll('.highlight');
+ var link = example.querySelector('.scraped-example-title a');
+
+ if (locs.length > 1) {
+ // Toggle through list of examples in a given file
+ var onChangeLoc = function(changeIndex) {
+ removeClass(highlights[locIndex], 'focus');
+ changeIndex();
+ scrollToLoc(example, locs[locIndex][0]);
+ addClass(highlights[locIndex], 'focus');
+
+ var url = locs[locIndex][1];
+ var title = locs[locIndex][2];
+
+ link.href = url;
+ link.innerHTML = title;
+ };
+
+ example.querySelector('.prev')
+ .addEventListener('click', function() {
+ onChangeLoc(function() {
+ locIndex = (locIndex - 1 + locs.length) % locs.length;
+ });
+ });
+
+ example.querySelector('.next')
+ .addEventListener('click', function() {
+ onChangeLoc(function() {
+ locIndex = (locIndex + 1) % locs.length;
+ });
+ });
+ }
+
+ var expandButton = example.querySelector('.expand');
+ if (expandButton) {
+ expandButton.addEventListener('click', function () {
+ if (hasClass(example, "expanded")) {
+ removeClass(example, "expanded");
+ scrollToLoc(example, locs[0][0]);
+ } else {
+ addClass(example, "expanded");
+ }
+ });
+ }
+
+ // Start with the first example in view
+ scrollToLoc(example, locs[0][0]);
+ }
+
+ var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+ onEach(firstExamples, updateScrapedExample);
+ onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+ // Allow users to click the left border of the <details> section to close it,
+ // since the section can be large and finding the [+] button is annoying.
+ toggle.querySelector('.toggle-line').addEventListener('click', function() {
+ toggle.open = false;
+ });
+
+ var moreExamples = toggle.querySelectorAll('.scraped-example');
+ toggle.querySelector('summary').addEventListener('click', function() {
+ // Wrapping in setTimeout ensures the update happens after the elements are actually
+ // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+ // depends on offsetHeight, a property that requires an element to be visible to
+ // compute correctly.
+ setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+ }, {once: true});
+ });
+})();
var elems = Object.create(null);
var elength = obj[GENERICS_DATA].length;
for (var x = 0; x < elength; ++x) {
- if (!elems[obj[GENERICS_DATA][x]]) {
- elems[obj[GENERICS_DATA][x]] = 0;
+ if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+ elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
- elems[obj[GENERICS_DATA][x]] += 1;
+ elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
var total = 0;
var done = 0;
// Check for type name and type generics (if any).
function checkType(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
+ var tmp_lev = MAX_LEV_DISTANCE + 1;
var len, x, firstGeneric;
if (obj[NAME] === val.name) {
if (literalSearch) {
var elems = Object.create(null);
len = obj[GENERICS_DATA].length;
for (x = 0; x < len; ++x) {
- if (!elems[obj[GENERICS_DATA][x]]) {
- elems[obj[GENERICS_DATA][x]] = 0;
+ if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+ elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
- elems[obj[GENERICS_DATA][x]] += 1;
+ elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
var allFound = true;
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
- var tmp_lev = checkGenerics(obj, val);
+ tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
if ((!val.generics || val.generics.length === 0) &&
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
return obj[GENERICS_DATA].some(
- function(name) {
- return name === val.name;
+ function(gen) {
+ return gen[NAME] === val.name;
});
}
return false;
// a levenshtein distance value that isn't *this* good so it goes
// into the search results but not too high.
lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
- } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
+ }
+ if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
// We can check if the type we're looking for is inside the generics!
var olength = obj[GENERICS_DATA].length;
for (x = 0; x < olength; ++x) {
- lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
- lev_distance);
+ tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+ }
+ if (tmp_lev !== 0) {
+ // If we didn't find a good enough result, we go check inside the generics of
+ // the generics.
+ for (x = 0; x < olength && tmp_lev !== 0; ++x) {
+ tmp_lev = Math.min(
+ checkType(obj[GENERICS_DATA][x], val, literalSearch),
+ tmp_lev
+ );
+ }
}
}
// Now whatever happens, the returned distance is "less good" so we should mark it
// as such, and so we add 1 to the distance to make it "less good".
- return lev_distance + 1;
+ return Math.min(lev_distance, tmp_lev) + 1;
}
function findArg(obj, val, literalSearch, typeFilter) {
/// Storage, used to store documentation settings.
crate static STORAGE_JS: &str = include_str!("static/js/storage.js");
+/// The file contents of `scraped-examples.js`, which contains functionality related to the
+/// --scrape-examples flag that inserts automatically-found examples of usages of items.
+crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
+
/// The file contents of `brush.svg`, the icon used for the theme-switch button.
crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
}
-crate mod noto_sans_kr {
- /// The file `noto-sans-kr.woff`, the Regular variant of the Noto Sans KR font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff");
-
- /// The file `noto-sans-kr.woff2`, the Regular variant of the Noto Sans KR font.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff2");
-
- /// The file `noto-sans-kr-LICENSE.txt`, the license text of the Noto Sans KR font.
- crate static LICENSE: &[u8] = include_bytes!("static/fonts/noto-sans-kr-LICENSE.txt");
+/// Files related to the Nanum Barun Gothic font.
+///
+/// These files are used to avoid some legacy CJK serif fonts in Windows.
+///
+/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
+/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
+/// rendering that distorts OpenType fonts too much.
+///
+/// The font files were generated with these commands:
+///
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
+/// ```
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
+/// ```
+crate mod nanum_barun_gothic {
+ /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
+
+ /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
+ crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+
+ /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
+ crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
}
/// Files related to the sidebar in rustdoc sources.
<input {# -#}
class="search-input" {# -#}
name="search" {# -#}
- disabled {# -#}
autocomplete="off" {# -#}
spellcheck="false" {# -#}
placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
{%- for script in page.static_extra_scripts -%}
<script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
{% endfor %}
+ {%- if layout.scrape_examples_extension -%}
+ <script src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+ {%- endif -%}
{%- for script in page.extra_scripts -%}
<script src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#}
{% endfor %}
},
Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
- default: default.map(|x| x.into_tcx(tcx)),
+ default: default.map(|x| (*x).into_tcx(tcx)),
},
Const { did: _, ty, default } => {
- GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default }
+ GenericParamDefKind::Const { ty: (*ty).into_tcx(tcx), default: default.map(|x| *x) }
}
}
}
.map(|t| {
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
})
- .chain(lt.into_iter().map(|lt| clean::GenericBound::Outlives(lt)))
+ .chain(lt.map(clean::GenericBound::Outlives))
.map(|bound| bound.into_tcx(tcx))
.collect(),
}
TraitAlias => ItemKind::TraitAlias,
ProcAttribute => ItemKind::ProcAttribute,
ProcDerive => ItemKind::ProcDerive,
+ Generic => unreachable!(),
}
}
}
extern crate rustc_lexer;
extern crate rustc_lint;
extern crate rustc_lint_defs;
+extern crate rustc_macros;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_parse;
extern crate rustc_passes;
extern crate rustc_resolve;
+extern crate rustc_serialize;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
}}
}
-#[macro_use]
-mod externalfiles;
-
mod clean;
mod config;
mod core;
mod docfs;
+mod doctest;
mod doctree;
-#[macro_use]
mod error;
-mod doctest;
+mod externalfiles;
mod fold;
mod formats;
// used by the error-index generator, so it needs to be public
crate mod lint;
mod markdown;
mod passes;
+mod scrape_examples;
mod theme;
+mod visit;
mod visit_ast;
mod visit_lib;
"Make the identifiers in the HTML source code pages navigable",
)
}),
+ unstable("scrape-examples-output-path", |o| {
+ o.optopt(
+ "",
+ "scrape-examples-output-path",
+ "",
+ "collect function call information and output at the given path",
+ )
+ }),
+ unstable("scrape-examples-target-crate", |o| {
+ o.optmulti(
+ "",
+ "scrape-examples-target-crate",
+ "",
+ "collect function call information for functions from the target crate",
+ )
+ }),
+ unstable("with-examples", |o| {
+ o.optmulti(
+ "",
+ "with-examples",
+ "",
+ "path to function call information (for displaying examples in the documentation)",
+ )
+ }),
]
}
// FIXME: fix this clone (especially render_options)
let manual_passes = options.manual_passes.clone();
let render_options = options.render_options.clone();
+ let scrape_examples_options = options.scrape_examples_options.clone();
let config = core::create_config(options);
interface::create_compiler_and_run(config, |compiler| {
// 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(queries, &sess);
+ let resolver = core::create_resolver(queries, sess);
if sess.has_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
});
info!("finished with rustc");
+ if let Some(options) = scrape_examples_options {
+ return scrape_examples::run(krate, render_opts, cache, tcx, options);
+ }
+
cache.crate_version = crate_version;
if show_coverage {
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::main_body_opts;
+use crate::visit::DocVisitor;
use core::ops::Range;
use pulldown_cmark::{Event, Parser, Tag};
use regex::Regex;
) {
trace!("looking for raw urls in {}", text);
// For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
- for match_ in URL_REGEX.find_iter(&text) {
+ for match_ in URL_REGEX.find_iter(text) {
let url = match_.as_str();
let url_range = match_.range();
f(
}
crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- BareUrlsLinter { cx }.fold_crate(krate)
+ BareUrlsLinter { cx }.visit_crate(&krate);
+ krate
}
-impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return Some(self.fold_item_recur(item));
+ return;
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use crate::clean;
use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
use crate::html::markdown::{find_testable_code, ErrorCodes};
use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
use rustc_hir as hir;
use rustc_lint::builtin::MISSING_DOCS;
use rustc_middle::lint::LintLevelSource;
fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate {
let mut calc = CoverageCalculator { items: Default::default(), ctx };
- let krate = calc.fold_crate(krate);
+ calc.visit_crate(&krate);
calc.print_results();
}
}
-impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
- fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
+impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
+ fn visit_item(&mut self, i: &clean::Item) {
+ if !i.def_id.is_local() {
+ // non-local items are skipped because they can be out of the users control,
+ // especially in the case of trait impls, which rustdoc eagerly inlines
+ return;
+ }
+
match *i.kind {
- _ if !i.def_id.is_local() => {
- // non-local items are skipped because they can be out of the users control,
- // especially in the case of trait impls, which rustdoc eagerly inlines
- return Some(i);
- }
clean::StrippedItem(..) => {
// don't count items in stripped modules
- return Some(i);
+ return;
}
// docs on `use` and `extern crate` statements are not displayed, so they're not
// worth counting
}
}
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
use crate::clean;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{self, RustCodeBlock};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
name: "check-code-block-syntax",
};
crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
- SyntaxChecker { cx }.fold_crate(krate)
+ SyntaxChecker { cx }.visit_crate(&krate);
+ krate
}
struct SyntaxChecker<'a, 'tcx> {
let source = dox[code_block.code].to_owned();
let sess = ParseSess::with_span_handler(handler, sm);
- let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+ let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition());
let expn_data = ExpnData::default(
ExpnKind::AstPass(AstPass::TestHarness),
DUMMY_SP,
// The span and whether it is precise or not.
let (sp, precise_span) = match super::source_span_for_markdown_range(
self.cx.tcx,
- &dox,
+ dox,
&code_block.range,
&item.attrs,
) {
// FIXME(#67563): Provide more context for these errors by displaying the spans inline.
for message in buffer.messages.iter() {
- diag.note(&message);
+ diag.note(message);
}
diag.emit();
}
}
-impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> {
+ fn visit_item(&mut self, item: &clean::Item) {
if let Some(dox) = &item.attrs.collapsed_doc_value() {
let sp = item.attr_span(self.cx.tcx);
let extra = crate::html::markdown::ExtraInfo::new_did(
item.def_id.expect_def_id(),
sp,
);
- for code_block in markdown::rust_code_blocks(&dox, &extra) {
- self.check_rust_syntax(&item, &dox, code_block);
+ for code_block in markdown::rust_code_blocks(dox, &extra) {
+ self.check_rust_syntax(&item, dox, code_block);
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use crate::clean;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
+use crate::visit::DocVisitor;
use crate::visit_ast::inherits_doc_hidden;
use rustc_hir as hir;
use rustc_middle::lint::LintLevelSource;
crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
let mut coll = DocTestVisibilityLinter { cx };
-
- coll.fold_crate(krate)
+ coll.visit_crate(&krate);
+ krate
}
-impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
look_for_tests(self.cx, &dox, &item);
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
let mut tests = Tests { found_tests: 0 };
- find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
+ find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
- if should_have_doc_example(cx, &item) {
+ if should_have_doc_example(cx, item) {
debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
let sp = item.attr_span(cx.tcx);
cx.tcx.struct_span_lint_hir(
use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{markdown_links, MarkdownLink};
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
mod early;
crate use early::load_intra_link_crates;
};
fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- LinkCollector {
+ let mut collector = LinkCollector {
cx,
mod_ids: Vec::new(),
kind_side_channel: Cell::new(None),
visited_links: FxHashMap::default(),
- }
- .fold_crate(krate)
+ };
+ collector.visit_crate(&krate);
+ krate
}
/// Top-level errors emitted by this pass.
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
- module_id: module_id,
+ module_id,
partial_res: None,
unresolved: path_str.into(),
};
fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
let result = self.cx.enter_resolver(|resolver| {
resolver
- .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+ .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
.and_then(|(_, res)| res.try_into())
});
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
ty::Uint(uty) => Res::Primitive(uty.into()),
ty::Float(fty) => Res::Primitive(fty.into()),
ty::Str => Res::Primitive(Str),
- ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
+ ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
ty::Tuple(_) => Res::Primitive(Tuple),
ty::Array(..) => Res::Primitive(Array),
ty::Slice(_) => Res::Primitive(Slice),
)
}
-impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
use rustc_middle::ty::DefIdTree;
let parent_node =
}
}
- Some(if item.is_mod() {
+ if item.is_mod() {
if !inner_docs {
self.mod_ids.push(item.def_id.expect_def_id());
}
- let ret = self.fold_item_recur(item);
+ self.visit_item_recur(item);
self.mod_ids.pop();
- ret
} else {
- self.fold_item_recur(item)
- })
+ self.visit_item_recur(item)
+ }
}
}
}
// Parse and strip the disambiguator from the link, if present.
- let (disambiguator, path_str, link_text) = match Disambiguator::from_str(&link) {
+ let (disambiguator, path_str, link_text) = match Disambiguator::from_str(link) {
Ok(Some((d, path, link_text))) => (Some(d), path.trim(), link_text.trim()),
Ok(None) => (None, link.trim(), link.trim()),
Err((err_msg, relative_range)) => {
// Only report error if we would not have ignored this link. See issue #83859.
if !should_ignore_link_with_disambiguators(link) {
- let no_backticks_range = range_between_backticks(&ori_link);
+ let no_backticks_range = range_between_backticks(ori_link);
let disambiguator_range = (no_backticks_range.start + relative_range.start)
..(no_backticks_range.start + relative_range.end);
return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
// Strip generics from the path.
let path_str = if path_str.contains(['<', '>'].as_slice()) {
- match strip_generics_from_path(&path_str) {
+ match strip_generics_from_path(path_str) {
Ok(path) => path,
Err(err_kind) => {
debug!("link has malformed generics: {}", path_str);
if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
&& !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
{
- privacy_error(self.cx, &diag_info, &path_str);
+ privacy_error(self.cx, &diag_info, path_str);
}
}
let span =
super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
- if dox.bytes().nth(link_range.start) == Some(b'`')
- && dox.bytes().nth(link_range.end - 1) == Some(b'`')
+ if dox.as_bytes().get(link_range.start) == Some(&b'`')
+ && dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
{
sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
} else {
};
name = start;
for ns in [TypeNS, ValueNS, MacroNS] {
- if let Some(res) =
- collector.check_full_res(ns, &start, module_id, &None)
+ if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
{
debug!("found partial_res={:?}", res);
*partial_res = Some(res);
let attrs = crate::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()) {
+ for link in markdown_links(doc.as_str()) {
debug!(?link.link);
let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
x.path_str
span,
&path_str,
TypeNS,
- parent_module.unwrap_or(self.current_mod.to_def_id()),
+ parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
);
});
}
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
+use crate::visit::DocVisitor;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::DefIdTree;
use rustc_span::symbol::sym;
description: "retrieves trait impls for items in the crate",
};
-crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || {
+crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+ let synth_impls = cx.sess().time("collect_synthetic_impls", || {
let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
- (synth.fold_crate(krate), synth.impls)
+ synth.visit_crate(&krate);
+ synth.impls
});
let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
let crate_items = {
let mut coll = ItemCollector::new();
- krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate));
+ cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate));
coll.items
};
for &cnum in cx.tcx.crates(()).iter() {
for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
- cx.tcx.sess.prof.generic_activity("build_extern_trait_impl").run(|| {
- inline::build_impl(cx, None, did, None, &mut new_items);
- });
+ inline::build_impl(cx, None, did, None, &mut new_items);
}
}
}
let mut cleaner = BadImplStripper { prims, items: crate_items };
+ let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
+
+ // Follow all `Deref` targets of included items and recursively add them as valid
+ fn add_deref_target(
+ map: &FxHashMap<DefId, &Type>,
+ cleaner: &mut BadImplStripper,
+ type_did: DefId,
+ ) {
+ if let Some(target) = map.get(&type_did) {
+ debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
+ if let Some(target_prim) = target.primitive_type() {
+ cleaner.prims.insert(target_prim);
+ } else if let Some(target_did) = target.def_id_no_primitives() {
+ // `impl Deref<Target = S> for S`
+ if target_did == type_did {
+ // Avoid infinite cycles
+ return;
+ }
+ cleaner.items.insert(target_did.into());
+ add_deref_target(map, cleaner, target_did);
+ }
+ }
+ }
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
- if cleaner.keep_impl(for_)
- && trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+ if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+ && cleaner.keep_impl(for_, true)
{
let target = items
.iter()
if let Some(prim) = target.primitive_type() {
cleaner.prims.insert(prim);
- } else if let Some(did) = target.def_id() {
+ } else if let Some(did) = target.def_id(&cx.cache) {
cleaner.items.insert(did.into());
}
+ if let Some(for_did) = for_.def_id_no_primitives() {
+ if type_did_to_deref_target.insert(for_did, target).is_none() {
+ // Since only the `DefId` portion of the `Type` instances is known to be same for both the
+ // `Deref` target type and the impl for type positions, this map of types is keyed by
+ // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
+ if cleaner.keep_impl_with_def_id(for_did.into()) {
+ add_deref_target(&type_did_to_deref_target, &mut cleaner, for_did);
+ }
+ }
+ }
}
}
}
new_items.retain(|it| {
if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
- cleaner.keep_impl(for_)
- || trait_
- .as_ref()
- .map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
+ cleaner.keep_impl(
+ for_,
+ trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
+ ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
|| blanket_impl.is_some()
} else {
true
}
}
- let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
- items
+ if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
+ items.extend(synth_impls);
+ items.extend(new_items);
} else {
panic!("collect-trait-impls can't run");
};
- items.extend(synth_impls);
- items.extend(new_items);
krate
}
impls: Vec<Item>,
}
-impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
+ fn visit_item(&mut self, i: &Item) {
if i.is_struct() || i.is_enum() || i.is_union() {
// FIXME(eddyb) is this `doc(hidden)` check needed?
if !self
}
}
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
}
}
-impl DocFolder for ItemCollector {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl DocVisitor for ItemCollector {
+ fn visit_item(&mut self, i: &Item) {
self.items.insert(i.def_id);
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
}
impl BadImplStripper {
- fn keep_impl(&self, ty: &Type) -> bool {
+ fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
if let Generic(_) = ty {
// keep impls made on generics
true
} else if let Some(prim) = ty.primitive_type() {
self.prims.contains(&prim)
- } else if let Some(did) = ty.def_id() {
- self.keep_impl_with_def_id(did.into())
+ } else if let Some(did) = ty.def_id_no_primitives() {
+ is_deref || self.keep_impl_with_def_id(did.into())
} else {
false
}
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::main_body_opts;
-use core::ops::Range;
+use crate::visit::DocVisitor;
+
use pulldown_cmark::{Event, Parser, Tag};
+
use std::iter::Peekable;
+use std::ops::Range;
use std::str::CharIndices;
crate const CHECK_INVALID_HTML_TAGS: Pass = Pass {
}
crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- if !cx.tcx.sess.is_nightly_build() {
- krate
- } else {
+ if cx.tcx.sess.is_nightly_build() {
let mut coll = InvalidHtmlTagsLinter { cx };
-
- coll.fold_crate(krate)
+ coll.visit_crate(&krate);
}
+ krate
}
const ALLOWED_UNCLOSED: &[&str] = &[
}
}
-impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let tcx = self.cx.tcx;
let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return Some(self.fold_item_recur(item));
+ return;
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use rustc_middle::middle::privacy::AccessLevels;
use std::mem;
-use crate::clean::{self, GetDefId, Item, ItemIdSet};
+use crate::clean::{self, Item, ItemIdSet};
use crate::fold::{strip_item, DocFolder};
crate struct Stripper<'a> {
if imp.trait_.is_none() && imp.items.is_empty() {
return None;
}
- if let Some(did) = imp.for_.def_id() {
+ if let Some(did) = imp.for_.def_id_no_primitives() {
if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
{
debug!("ImplStripper: impl item for stripped type; removing");
}
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
for typaram in generics {
- if let Some(did) = typaram.def_id() {
+ if let Some(did) = typaram.def_id_no_primitives() {
if did.is_local() && !self.retained.contains(&did.into()) {
debug!(
"ImplStripper: stripped item in trait's generics; removing impl"
--- /dev/null
+//! This module analyzes crates to find call sites that can serve as examples in the documentation.
+
+use crate::clean;
+use crate::config;
+use crate::formats;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{
+ self as hir,
+ intravisit::{self, Visitor},
+};
+use rustc_interface::interface;
+use rustc_macros::{Decodable, Encodable};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_serialize::{
+ opaque::{Decoder, FileEncoder},
+ Decodable, Encodable,
+};
+use rustc_session::getopts;
+use rustc_span::{
+ def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
+ edition::Edition,
+ BytePos, FileName, SourceFile,
+};
+
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+crate struct ScrapeExamplesOptions {
+ output_path: PathBuf,
+ target_crates: Vec<String>,
+}
+
+impl ScrapeExamplesOptions {
+ crate fn new(
+ matches: &getopts::Matches,
+ diag: &rustc_errors::Handler,
+ ) -> Result<Option<Self>, i32> {
+ let output_path = matches.opt_str("scrape-examples-output-path");
+ let target_crates = matches.opt_strs("scrape-examples-target-crate");
+ match (output_path, !target_crates.is_empty()) {
+ (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
+ output_path: PathBuf::from(output_path),
+ target_crates,
+ })),
+ (Some(_), false) | (None, true) => {
+ diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+ Err(1)
+ }
+ (None, false) => Ok(None),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct SyntaxRange {
+ crate byte_span: (u32, u32),
+ crate line_span: (usize, usize),
+}
+
+impl SyntaxRange {
+ fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+ let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
+ let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+
+ SyntaxRange {
+ byte_span: (get_pos(span.lo()), get_pos(span.hi())),
+ line_span: (get_line(span.lo()), get_line(span.hi())),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallLocation {
+ crate call_expr: SyntaxRange,
+ crate enclosing_item: SyntaxRange,
+}
+
+impl CallLocation {
+ fn new(
+ expr_span: rustc_span::Span,
+ enclosing_item_span: rustc_span::Span,
+ source_file: &SourceFile,
+ ) -> Self {
+ CallLocation {
+ call_expr: SyntaxRange::new(expr_span, source_file),
+ enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallData {
+ crate locations: Vec<CallLocation>,
+ crate url: String,
+ crate display_name: String,
+ crate edition: Edition,
+}
+
+crate type FnCallLocations = FxHashMap<PathBuf, CallData>;
+crate type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+
+/// Visitor for traversing a crate and finding instances of function calls.
+struct FindCalls<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ map: Map<'tcx>,
+ cx: Context<'tcx>,
+ target_crates: Vec<CrateNum>,
+ calls: &'a mut AllCallLocations,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
+where
+ 'tcx: 'a,
+{
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::OnlyBodies(self.map)
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+ intravisit::walk_expr(self, ex);
+
+ let tcx = self.tcx;
+
+ // If we visit an item that contains an expression outside a function body,
+ // then we need to exit before calling typeck (which will panic). See
+ // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
+ let hir = tcx.hir();
+ let owner = hir.local_def_id_to_hir_id(ex.hir_id.owner);
+ if hir.maybe_body_owned_by(owner).is_none() {
+ return;
+ }
+
+ // Get type of function if expression is a function call
+ let (ty, span) = match ex.kind {
+ hir::ExprKind::Call(f, _) => {
+ let types = tcx.typeck(ex.hir_id.owner);
+
+ match types.node_type_opt(f.hir_id) {
+ Some(ty) => (ty, ex.span),
+ None => {
+ return;
+ }
+ }
+ }
+ hir::ExprKind::MethodCall(_, _, _, span) => {
+ let types = tcx.typeck(ex.hir_id.owner);
+ let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+ (tcx.type_of(def_id), span)
+ }
+ _ => {
+ return;
+ }
+ };
+
+ // If this span comes from a macro expansion, then the source code may not actually show
+ // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
+ if span.from_expansion() {
+ trace!("Rejecting expr from macro: {:?}", span);
+ return;
+ }
+
+ // If the enclosing item has a span coming from a proc macro, then we also don't want to include
+ // the example.
+ let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id));
+ if enclosing_item_span.from_expansion() {
+ trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
+ return;
+ }
+
+ assert!(
+ enclosing_item_span.contains(span),
+ "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.",
+ span,
+ enclosing_item_span
+ );
+
+ // Save call site if the function resolves to a concrete definition
+ if let ty::FnDef(def_id, _) = ty.kind() {
+ if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+ trace!("Rejecting expr from crate not being documented: {:?}", span);
+ return;
+ }
+
+ let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+ let file_path = match file.name.clone() {
+ FileName::Real(real_filename) => real_filename.into_local_path(),
+ _ => None,
+ };
+
+ if let Some(file_path) = file_path {
+ let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+ let cx = &self.cx;
+ let mk_call_data = || {
+ let clean_span = crate::clean::types::Span::new(span);
+ let url = cx.href_from_span(clean_span, false).unwrap();
+ let display_name = file_path.display().to_string();
+ let edition = span.edition();
+ CallData { locations: Vec::new(), url, display_name, edition }
+ };
+
+ let fn_key = tcx.def_path_hash(*def_id);
+ let fn_entries = self.calls.entry(fn_key).or_default();
+
+ trace!("Including expr: {:?}", span);
+ let location = CallLocation::new(span, enclosing_item_span, &file);
+ fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
+ }
+ }
+ }
+}
+
+crate fn run(
+ krate: clean::Crate,
+ renderopts: config::RenderOptions,
+ cache: formats::cache::Cache,
+ tcx: TyCtxt<'_>,
+ options: ScrapeExamplesOptions,
+) -> interface::Result<()> {
+ let inner = move || -> Result<(), String> {
+ // Generates source files for examples
+ let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
+
+ // Collect CrateIds corresponding to provided target crates
+ // If two different versions of the crate in the dependency tree, then examples will be collcted from both.
+ let all_crates = tcx
+ .crates(())
+ .iter()
+ .chain([&LOCAL_CRATE])
+ .map(|crate_num| (crate_num, tcx.crate_name(*crate_num)))
+ .collect::<Vec<_>>();
+ let target_crates = options
+ .target_crates
+ .into_iter()
+ .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
+ .flatten()
+ .map(|(crate_num, _)| **crate_num)
+ .collect::<Vec<_>>();
+
+ debug!("All crates in TyCtxt: {:?}", all_crates);
+ debug!("Scrape examples target_crates: {:?}", target_crates);
+
+ // Run call-finder on all items
+ let mut calls = FxHashMap::default();
+ let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
+ tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+
+ // Sort call locations within a given file in document order
+ for fn_calls in calls.values_mut() {
+ for file_calls in fn_calls.values_mut() {
+ file_calls.locations.sort_by_key(|loc| loc.call_expr.byte_span.0);
+ }
+ }
+
+ // Save output to provided path
+ let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
+ calls.encode(&mut encoder).map_err(|e| e.to_string())?;
+ encoder.flush().map_err(|e| e.to_string())?;
+
+ Ok(())
+ };
+
+ if let Err(e) = inner() {
+ tcx.sess.fatal(&e);
+ }
+
+ Ok(())
+}
+
+// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+crate fn load_call_locations(
+ with_examples: Vec<String>,
+ diag: &rustc_errors::Handler,
+) -> Result<AllCallLocations, i32> {
+ let inner = || {
+ let mut all_calls: AllCallLocations = FxHashMap::default();
+ for path in with_examples {
+ let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+ let mut decoder = Decoder::new(&bytes, 0);
+ let calls = AllCallLocations::decode(&mut decoder)?;
+
+ for (function, fn_calls) in calls.into_iter() {
+ all_calls.entry(function).or_default().extend(fn_calls.into_iter());
+ }
+ }
+
+ Ok(all_calls)
+ };
+
+ inner().map_err(|e: String| {
+ diag.err(&format!("failed to load examples: {}", e));
+ 1
+ })
+}
--- /dev/null
+use crate::clean::*;
+
+crate trait DocVisitor: Sized {
+ fn visit_item(&mut self, item: &Item) {
+ self.visit_item_recur(item)
+ }
+
+ /// don't override!
+ fn visit_inner_recur(&mut self, kind: &ItemKind) {
+ match kind {
+ StrippedItem(..) => unreachable!(),
+ ModuleItem(i) => {
+ self.visit_mod(i);
+ return;
+ }
+ StructItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+ UnionItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+ EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
+ TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+ ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+ VariantItem(i) => match i {
+ Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+ Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+ Variant::CLike => {}
+ },
+ ExternCrateItem { src: _ }
+ | ImportItem(_)
+ | FunctionItem(_)
+ | TypedefItem(_, _)
+ | OpaqueTyItem(_)
+ | StaticItem(_)
+ | ConstantItem(_)
+ | TraitAliasItem(_)
+ | TyMethodItem(_)
+ | MethodItem(_, _)
+ | StructFieldItem(_)
+ | ForeignFunctionItem(_)
+ | ForeignStaticItem(_)
+ | ForeignTypeItem
+ | MacroItem(_)
+ | ProcMacroItem(_)
+ | PrimitiveItem(_)
+ | AssocConstItem(_, _)
+ | AssocTypeItem(_, _)
+ | KeywordItem(_) => {}
+ }
+ }
+
+ /// don't override!
+ fn visit_item_recur(&mut self, item: &Item) {
+ match &*item.kind {
+ StrippedItem(i) => self.visit_inner_recur(i),
+ _ => self.visit_inner_recur(&item.kind),
+ }
+ }
+
+ fn visit_mod(&mut self, m: &Module) {
+ m.items.iter().for_each(|i| self.visit_item(i))
+ }
+
+ fn visit_crate(&mut self, c: &Crate) {
+ self.visit_item(&c.module);
+
+ // FIXME: make this a simple by-ref for loop once external_traits is cleaned up
+ let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+ for (k, v) in external_traits {
+ v.trait_.items.iter().for_each(|i| self.visit_item(i));
+ c.external_traits.borrow_mut().insert(k, v);
+ }
+ }
+}
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
-use rustc_span;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
// the rexport defines the path that a user will actually see. Accordingly,
// we add the rexport as an item here, and then skip over the original
// definition in `visit_item()` below.
+ //
+ // We also skip `#[macro_export] macro_rules!` that have already been inserted,
+ // it can happen if within the same module a `#[macro_export] macro_rules!`
+ // 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(&[]) {
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) {
- let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- let item = self.cx.tcx.hir().expect_item(hir_id);
- top_level_module.items.push((item, None));
+ if inserted.insert(def_id) {
+ let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ let item = self.cx.tcx.hir().expect_item(hir_id);
+ top_level_module.items.push((item, None));
+ }
}
}
}
.unwrap_or(&[])
.iter()
.filter_map(|attr| {
- Some(
- Cfg::parse(attr.meta_item()?)
- .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
- .ok()?,
- )
+ Cfg::parse(attr.meta_item()?)
+ .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
+ .ok()
})
.collect::<Vec<_>>()
})
_ if self.inlining && !is_pub => {}
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
- hir::ItemKind::Use(ref path, kind) => {
+ hir::ItemKind::Use(path, kind) => {
let is_glob = kind == hir::UseKind::Glob;
// Struct and variant constructors and proc macro stubs always show up alongside
"__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
"dist_server": "https://static.rust-lang.org",
"compiler": {
- "date": "2021-09-08",
+ "date": "2021-10-22",
"version": "beta"
},
"rustfmt": {
- "date": "2021-09-08",
+ "date": "2021-10-23",
"version": "nightly"
},
"checksums_sha256": {
- "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.gz": "5bc2e21b10c153fd070c1a9b9af8ff68ada71f10953d8261bd8aa5f599878db3",
- "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.xz": "95082b292ccf8e0fdd637f591dd3180297c48ec13ccbcb3e1a2c115feb17463f",
- "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "7de49c4e1db688089dd566647c23233fb4ff21dbb4025a4be37d18b11cc82e2f",
- "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "35394e3c08a3dd392958187b091b3bdc576a6bf0d2d139556df21cd3ff1d21cc",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "a71153dde967a7816636dce62ba4334baadad4b926b25dc54c068c5cb293df9a",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "d4e33616af35dd7564a73e702eb6eab7eae5da7a980f518bd3d34f4cf0d05440",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "f76545e48977d2ebad75d3cf745d81ca709d59ca02a6c66ee3d049d8ca145463",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "79cf346367022c3a1ba58fd134f8189fa7781e702871d56f60dc1fff9d318570",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7884e6a177a2469f21dee177564e03490fc541e877f0a1858e17162a9037298c",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "6fb307038c827d4e915224bc17709929628bdc5eda625644eaa4df992de75718",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "a367fc19f65b07cfec4732d3bd13aa662581d9aca886d56c93bad171948c9593",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "161eabe9fc1a0031f9fb044da4cc4c2cf376c6a018695f9fa1f5d7ce96c742d1",
- "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "35587eeb680443f759c6cc9526186d51e35b08683f9c8a112d692324b62afae4",
- "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "8fea8765c22e9751379585d381ad14aa0faab811cfaf40dbb55a60c82146b91e",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.gz": "9e7e075e79cfca74b1185067962e3b37118ed32c8258d6746f05891f742226cb",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.xz": "50f34954765c542076e7a6d9dbaf3a8e8dbfbabfa95bbc76e95eb1fb52e1227a",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.gz": "eb93a58581ff485b44013d3623d0f4afb0fc2e3a3c7ff1898b74faad6f7bf48d",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.xz": "1913dd2d4b0c56a6e5ec3686fa03eafc716006cc1fcdcfd81cf1b7984b9532b1",
- "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.gz": "04b3f5ca4f4a24a2555c186600f683730a59f807d3525248c1d8f2f674cd00a6",
- "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.xz": "c730e3f619d69d221277f3b44a188746980eb7a0c79dab9a252cea6bc4a1e54b",
- "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.gz": "94fc426e50671c39d7a272b9636ce43bc3242f1b6a302555914127ab73ce6c65",
- "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.xz": "c44957519099e19edfeceed53b99674d9b98731b20ca7494621fb0dcc6488ed5",
- "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "377a998bba44a16bb401bf56c4be2e38f1c40e37f71335f93ba8e54d20d7a3c3",
- "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2406c2ac61d9b494b3a6327d991a6846a18c867fc581892874a2e3e83f4d49fe",
- "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "52c7d8009a6ca8701912c9e02c1278dacd2b6c2bdb218416d1e3db2c750b7536",
- "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "764820946adfd6594c7c9c4f97cb06d1c639ae2621ded3059d234a0cef97b1dd",
- "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "d351cbcd87d10d54bde4311d6fc902a655e8c74ffb16b2a85cfb8e5ad30faeda",
- "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ec7235af6ae25ce30c61d06f94bd398018878b741d8d94edad8e3dbaaad0cc2e",
- "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "11d983f439f46a1b49d72b0e8ec1dd5f78c72c23f305476ce3b56ec20167ccc9",
- "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "327fcdfcc7679178e734293e23e752d44bf1a4c44a88e5b2d89bfa7f95b7876c",
- "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "52f827f09376c0f21419cbff1e56d30337d140c1c097d5a38d4541f65545d3d2",
- "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "e9f956aaa4f8428b813d27c43a8602671a27f567d206f769da7b14e5029f5a1f",
- "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "b59d4814b99031a9e418fd423833500a3436b65b0696974d1d6a2f7598ecce2d",
- "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "5751e2453329e1fe2378cf9e7ade93c75df7a31d4dbeb0f14fde9c3cfbc5d5b1",
- "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a3d97d9efad02108166878a9a30d3485a9f6db0768bbef5c98e86540c6f4901c",
- "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "e8c3bf169cdcf9192363c9ace37457a94720d36ff1b607e178796dac933f652f",
- "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "51fc38135a45870bd01bbcee4b69f5e7055424b1cfa36d4c0272613baf3185c2",
- "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "bc392d660368c856ab1bc96b603699d492f03b226a0d60812a1bb19ca6c05ff3",
- "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.gz": "ea1804dfe7b806368f278adcb887e4aa023ff7f533bee84541415cb0862ed836",
- "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.xz": "69fa3524d2bb2bbbf0c0a4e18ecbec3eeae791f9b60547d6adf0fa20123c4a41",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "611c3653a03ca05effb06b5857b77cb24fd87ae5f1d294df980c96a57b8a9a74",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "cca04b2298bea6b447daa806af2313da4797072d27ecc3202bd0633b5a1d5fb4",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "763d4ec911a374d348468a38d07caa8d559330c6179f5cd40b5a54ccdb355580",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "37d24786e764c3af201cba07ef88a27fac97d150d7711cfdbb625e957b9f0139",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.gz": "f39494da3f92c39be50579f26d7f09d8e5f985e3566f8742aacc1446ab9f92c1",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b65f8024b47d4784ab59e4722e522e54442852bbe16906760f2708e2b0d0fe65",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.gz": "072bb564f73a97bdc6d58970735191d8da0831926dcd155a946f0fde1f382a02",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.xz": "fc6a9c6d4cceeac868b37e200ed193981b8d70e8408d8e4b4765e149a9075c3a",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "8074fc6912e4bdbae269a334f21d0ead7bb0f28344ad67d71f65487baf21cc35",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "32a8471b2fb91b62aeda637bdb1368c67d1b17daaeea2592517666393857af16",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "19dbfab31784d0615d0e84c526e98d9f47332492744bd1ab4fc7434c0762c5ad",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "510734acf369b92a3f1eb30921a96f393ae207af7dffe6a83df66c350bd1a510",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.gz": "85e2fb4ab2ca3eff3ce98ab1c74c996a6b9cd2c20ff3f47c8624e261ac254195",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2b1cff0bfa9bcece19e61f4be680ebaa05663e918fc9f3a20516efd91244e1c6",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.gz": "54386650675047126f2b418485a5b2ca8bf3b568231fe54914512ae09809276e",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.xz": "c7613b2089562353502560a6521139dfd7fd58a96c772877cf2ea7bfd62920d4",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "a80e59fa3885f73973d9c3eb50628718eda015b1e62f328152ee95971acb10c2",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b0b65575680186ae6c032fabad5dd4352d17ec2d29ecc22771ab9f86a54b90e8",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.gz": "22fdfea8abb345a32ca47ce658c601c36d7838cf22383a34470db643a14e89b3",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.xz": "3a145167eb7bd82e59df7bd009f69f4951efb1487cf002c584625c24be35f4c0",
- "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.gz": "97d1614ad18e71a09326d65ec4bb631c9974f4d3c63c9438b180646579227f7d",
- "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.xz": "aabd6f6c8548b6576986f6fa2632ced035f0ad504da05d3dfd92ab0202104ff9",
- "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.gz": "5e67121330fd7e095f86c5dc71bd5180ec1669ad819ccf0bb4b38b46f35bcf94",
- "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.xz": "b3d72ba51cca485d742117c70915a5e57404d3f8c80356c8df388eba913e136d",
- "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f3eaf16070eb770d464a844e72257cca4ccce4ee2c380f276e82d259d8781326",
- "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "846480e3eaf8d21fb4d99659a68e71259da613e54cfd098470c139e38ea5a447",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "198be5989e4d2d479582ef2002ec3041105555cbb86488ba563fce35ae1c5c18",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "706148bf9e562cf61d6f882a330e0fd150eb0593136a370cf559c54b6723f4c1",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "8e2718c2509c3db0696599dbd93f7a9c846228374ec0e24bf9f7b876a7714d71",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "e44e11ca1ac94d2335c19891fc8b85394b3935a86fa51c8a2c558faf8606c7bc",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "9439bb56b5c11e9fab00e02e7f931c4582a6dbb3aeb7b20e5ad0fe5420dd27d0",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e3187685291d52c500aba70de657478e08b5a69ecbf381f2ae41cb78cfd82d3",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.gz": "69c5da7ba93aeb93f8f7a6b581f1895b427c377c8f624274cf2691cacf845acc",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.xz": "8d66841c5e9e20d35b3791bbd10fb97e73b7abf602fee52a939a7096e0040eb0",
- "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.gz": "4901f22f057d78331d298c23b66a39b2caa39580b19adc007fa8a4780483b27c",
- "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.xz": "ba5d5016a625f433dc2fdacb3a1c462a08cdf9cdfcd202a966f16386e58362cb",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "0ea2986826d17ea1baeecda1c73af27e41830d22aa10722ac18e1427a3c11295",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "11e8397c3b6cc2f0ce7c8d725e8bc8dd0a7b7c800174ca3f4da6ee4c32e338e9",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "019fb984e383342a3ec4069f7f62bbc33c9b9609202b571ae32fe6b0ddd2dd60",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e86d5310c9181ccfd432bc93e6715d109f26608bea97fee0d9f0d2efaaa7126a",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "1a7c7bf25c54c9a394a671d7f23e5cb08d6501b25bbb687159a208dfa16b0d33",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e8deaf7cf0031d73e93ac1f61713836a0413f644639f8f602d234bd583c660c2",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0d72ae75cc1b59146dd799cb85a8c60ea9c4169f53f17b8eeb74da644bad0e21",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1dd8c951a7e13e68686e9a9a3eb0ecdae83fb178454a0ace9c649b5b47fc9a50",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.gz": "8b4b4163b746618c2dde450a7151ccdbfaf9732311fb959d11336bd78bfa8d25",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.xz": "fa6ef79c9a3ac07c0cebe908eebab2a32f578f0838c0f939bf8f4136aed7a499",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.gz": "487c64e8251564373437f94b5e94d81bec50b61e77c39c691ce912cf95236d0d",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.xz": "2bae0e0b2383ee6182ce8df4dd26993aaa56aa4dd89e6cac1982a48414ca5d5c",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "bb5ca2b48383b27d181d90e4802cd387cacab9c00fca853c0deeb317270851b0",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "f7bf769be48434faddf3dbed8264b1ab5dbbb3657f5b71640ad9330b3340ca29",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c88db813417a1263408cc3bffeaf03b45db7b2c0a89c8441b3f4e7514473a0c3",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3c5a3ea4ce9a6826dd3fc1eaae8615701bf3b5c53d56fe6948432229f027ac1c",
- "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.gz": "3d45d64267149d222337421be4cd5207812125f9b2df253f507f0cc2cba37219",
- "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.xz": "ee71e74b369b42a9c2258bf5d9c8c7119ee65b8951d4655c477a4593ec2cf3fa",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "949bce55fc6047a37f8ea26e21cc69557ad66a45c688442f2be06a8cab503358",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "28ec52f486459b436c0097db2b400a202ad1280591f2612cadf4daec1ef4e4a8",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0f7782f0b6874c858de7171d255f12fe309e9255ad55a6406577feae3702fbc0",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cf3bc863ecd6da3fb45c3d2f5b6741d57ff778b1bb2e4f0d05480c9aab480bbf",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "35e3647a940d2e2e37ed3a5b7c1a789f94b7f1a256f0bd339630bb7b0342c2e0",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "ed1ec913fd3e821501e52be1d3cdac3fbe5a6c00acd17204b1891aa5fa3e6f93",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "2fc9f5791717cc876d155f4cbb672dabf9fa308ac67636e50a75a5b5ea11369f",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "91ac6c321d172cfb62e6772c2c7340110fb9801a8d44814b69b477f611f09c58",
- "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.gz": "69661706ec6749f851d6a967f69fc8e4de8e5a58da2a771129b22202918f6ce8",
- "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.xz": "45275aea14a3f4547e0e2f11ce2cf364ac2c749cf0df467a54e27b39b65a5fe2",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.gz": "63ea71e69e36d916baca6eb42b4b4b6f2f69870063526533a2699f66fc0cb317",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.xz": "2d6f4ca658991a7b426d50330371922888706944eb3c1603288d4be2fa4f5457",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.gz": "3d27ea42bd3a419ccf7f28b9ff040e077f3e963948924f996aaf718abeeb1709",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.xz": "8f6bc34715629354b4d9f71d7a8693171b667604d237b433f7444df1228d2a36",
- "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f83bdc7e73590beab7ec915bb7a3a7531e485d7f73cf9c65150102748207d874",
- "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "1068750fb0b4a7ec35b5674a6c7fb0368b043bee6df0fbe360f521c7c2f08b94",
- "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.gz": "506bd86d803953bb086e057c6b2ee1fd9ffa0e08a0d7162189119cd21668cc0f",
- "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.xz": "b608aff18260165b51acbc06d551c5eb003928f2c7551f83a1ac1782442826ac",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "c90eca1f2326cfa916e225199e2526719fc9b6f18e2b789366a9668a52eba339",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ab382cc6c67bceaf76555a2c71c5f26e46802fe7c2713e173744b14371b742a5",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.gz": "dd52e44df6cd8bbac61d484e574d363125662fef270695e962900995a05818b3",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e9c4bba480b748625898dc047b950a142ccda9e9fe1e329365741f09f640e843",
- "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.gz": "bb2e1dea2aae2f726420d8a5cd112f1bed6e06e95053f10c6497b1be878b180e",
- "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.xz": "df15194a40cce8c574b219164b75590ad9c55c03ab811682ebe89db004c651f4",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c7b38618dda1cd13d52c59bb9a4632458aa7b20d90b01478fb506801c3fb41eb",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.xz": "83390b595e3273f0b02e05878064429a1815f18bceb7e0d77a63c5caecaebfeb",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e7c6c8e5ae9d02e9f3c33b174862d1d6e0caf357c7c3cd510e63cc3472db816b",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.xz": "feb49ed3fdf25d7703134afefc3c04b0ed23d87adc02945bccac4b30c425fa16",
- "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.gz": "f633cb1bd2636eceaa87d98a214aa73907502aa92d4cb1a1869870c9bc6ad23a",
- "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.xz": "cd61b7dfe7ead85a79469008717bc52cb76572fc9688f82a50f07b0c7e0fafb2",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "b22f1285e8d179a372060916bc2a6d609499231f805b5cec2ef8d1e5d0c70d71",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "24fd3c052bdec08615e54438fbccd9e43c9956d25b1bfce6f3640eb164aa6f5d",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.gz": "df63f460486eeb9a11ed53c35814495e931492aed5abe44a841cd7a43a9e3719",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.xz": "3ba2d402c01b099b89518acded3734a552f64a330a7d21732ce641cf25cd5c8d",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4cc5b2cfa6747155a0e0c6a7a835abd464bc9610fd071197af1ac50ab8f2fa1c",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "28f70f287f4cceba042b9574b16ce0403d73785bc6261c9a6739d770d5f354f9",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.gz": "04a8dc4e8144330f326dba5182928cf91c50c4b3513df0b67d55d601d3524a7e",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.xz": "06a91efa4f8ab42c3a0f9c2ae9279da87bb2a239f1032d1faa3583febace37cc",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "887728123ccd4bb75f4d42bffc1d2b7f46d8bdc4554a77b12578507cb44e7fd5",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "987598a67a36f428fa8fb21e0239aa345e952a1e6c64fefcc2fe2feda56bb864",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "2110b1b7456366668e093d27013d7002e302c6ecccff63c147c0346cd9a452b7",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "d6f16eca6526aeeef3ec7d0a9948ff5da3b7eff6e4bb9203a9546037df1f8d55",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "36a510c2a8fbc751416183b88680685c232646289504d2e2422e5208cd11670b",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "2f2a7a533d30cdb437bf31d18fb547680d646ec1765ca6c5fe16e449dbf3b613",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "09472066c8403c059e9d34ac2f7a4387e61726c45dd5ff2bc03b85543d8376c0",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "83c4a0f9ed4fa2884d1d193b79693c3af4e9c8603b9a1f3bd6eb827ba09a5466",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "739998734f48c9591b7aed3452d8425e2c916d202341ff63931fa473e3eb9a25",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "83be5e72fc8597f51c6b2cc216d90c8dba6be509b44fa25f3d7d285e1c54c7c0",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0a02455697ac62af66b359d5b73436ce7b18274abd18ffa13b7f0f9c1df72f82",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "1cc6fe6ecfe4c10c2957806e56c1a0aa256ef5bb3ad4ca47f24aae42cf0fc0e3",
- "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "f90d70acfa78388fe8e54a62f4fd9e773bd1455b036f6af13a5feec072de11e8",
- "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "d2c491b6fb62bc5279447e7f5d96fbb679a225ec13d6c96c8f80cad859b0f5f8",
- "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "17e9bca285df96b3bcd48297c89c096aab6b545d783e261103f7b364c214c09d",
- "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "d4a8679af46449daa4db0acc23bda23aa5c8f35fb2ca9d0e065b35e30d6fc649",
- "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "845cab4436d36b6eb2a914ab7c48bd49626a04053eee918fbbb78aba1d1e0a4a",
- "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "b399647f0d9e8458570e8a9ab11b30d7258fa396ab019037b5bb391dbe65ead7",
- "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6c84662ba3c210b9d7c3332473cdc95dcf3e238d9c9010581accfafa37cdf4f8",
- "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "594aba2abb126a615c93bb5c7927eb5a2ccdbe4c54c22bfdfa9cacf99e268889",
- "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "439f5d5f1d2ee9db18c6e3b0bb831b037234852067a91f1a15bca38ca38b7a0b",
- "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "227fa2ff323d20a2a8c29e0167fac78c7b88b8db3368b009b75d4a1cd49b7b29",
- "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "5055560e4dc3df90bf127bb5133c8d2d0ba662c1b1b20d63453cd60ee3e04947",
- "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "df1267905fe5a23c2ddc47fc0ade249bd663e6d3e8982193cb2a2a638e747e5c",
- "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "2a702d0d0a0e2cf17a42eac549bd751eadc4398182f42590e3322cc7420b4cd1",
- "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "98e5d336ee07556ff0fe01f89f9059cb977fa36d5f87ee8633aebb5fa6c8762b",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "de64e6d171a2c11e16142b1e964c0f0e0d6e4bab2e9e9d5d8121ee77fbdb60de",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1dbb24b1ed6510f098f63933a596f1f58907c22320eb79394dce341af7d7b59a",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "66af911664286500164db018c0aad12a85da035fc1e2d6cffbe7603ff0145624",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e8abd1f9f7344842af5f6a85d75404c1589fd17efbe5a8008ab52f082b7b3772",
- "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "a9f06d8862f9bb805f438b1c01464dd7a9cd07ecd04b1246727ac290891da54f",
- "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "6143b4b36bbdd1c56b978e9a2afc012163610fac7b8fb9bd9f24abb4e970b21d",
- "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "5cb4c0616056f36c7cfe446fa97e146fd5c525be1de8bbdb5017ad0d07a9561d",
- "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "9d2397f9d70956ddd50b37f8a7dba71d3cea9df5fa128e35d92cb162d7f938d4",
- "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b7e0fe340919a37cf8daeb1a747392c53fce4dafc84331f998479c3c12572973",
- "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "464b2601346e014b2f5a9cc64dd32897be915742a5c75eeacf82691277c4f8de",
- "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.gz": "40c61118e3e85343f6ea3059e41e3d2e3108f540331d8114948447307eea9b5f",
- "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.xz": "3dfb77e1315a8367b4a5665ae9419843a8cb953ce4726b35307e7c7199514616",
- "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.gz": "66632c7fad29f275ccfed907e395db12e621b17909e5e026d192f0b552fd4be1",
- "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.xz": "a308cdebc35d65d8208fe2b2dc7b45dfb1a64405478d86b82bfb28115174a129",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.gz": "c342b21b5f61dcddea74b89f60f1d0d0622c5aedc79550d316b8744b522bda6f",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.xz": "a3b00a6b9b3fb8942700f91d32077520185a7c21d25620193cbe2e730a021f64",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "18f15f7e2ffe97f7be99e246144e6b9ad7445b1b66382112e71e08137a36b840",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "16eb54bf02813d45c6ff328ec7db8f16daf0e57dedfad7247249af2ec5133d4b",
- "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.gz": "14bdada81be2379b2ead0212cc34add3ace87bd222532ada2a00b603180db946",
- "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f6cfa6bdcee91a6cab748fced0d2be7642b83cbe7d5fdcdf638fc3e86277d17e",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "e11e35a643c0a9983fb1f1e8f60ac073a4ee48c4a9f3e757f4fb55ea8364046d",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "2ee5fc11fb01f84e2346a17745c935f75d400a2448ec49d9e3535c98c3d67a73",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "61b26681fdb6957c3acd9aa32b011605786bed196cd71334d966ad9289efbb2f",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "bfd3391ebdc20690ede1a8a606f59df9009a473962deb04d3a89b266d0a89949",
- "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ae8d90bdd3d2faa2623ec30935e3e93bf3af6ad036eaae72bc8a3d086f7cd054",
- "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "66ce451e2a0830808aa996b4643fa6ca6d89a072467d9df659ad4e202b73d561",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1afbb6a4ee9ec38b7ad1c67c3df3371d188b831ffdb58ae96227e5c9a017f5d9",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "8c1e0000926fb4ff370763396e69aef70ed7871c33f01bc2d429abf31ee8d211",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "169852e1ae03792a8f492954258d08bc1483615e7121d587476ac4fc065c79a1",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "1da32effe4416f0cd5448a9061d57dd2f4b541f737a7036d20d78fd44f715ddb",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "39d22c8ff2620d4e6569eb75c86d4135a288bba00dcc479f4371a1e7e52fee4b",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "c34b1abdb8e3f3f913564a472b18dc52b239d7e327a4bd89d9bd0290d0b31635",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.gz": "ae284aa5819407e8daf022fbbf1f5d279366077faf25a6653d9c518ab3fe710e",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.xz": "be7a5b763db13ab1582a5f98fe7fb9ab1facdd645a7fe4544e0cbec9d1c58e76",
- "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.gz": "ac9f39cb7924f48fc29d666dfda3c6001b6880d6efd956acfa734389ef7b5dbe",
- "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.xz": "04d20256cea7b2394f72f6c0895a9d249fbd641fcaf616a628ad703e79c950a2",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.gz": "c304a11e2361b42f80fb9c6f239cbfbd2b7ffdcf00fe49ac94e3a6d4a9d2d2b3",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.xz": "35d51256fc42481b8265a02d756bb9bd84a23240156ed1fdf84ee3adaa77b8c2",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.gz": "6eec11897fe08b43fece4a1cf0ecec1ca247b3d01656b4a2a159815fbe13c626",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.xz": "faddd6de72f17f669e38dc2e9ef5cdd4b729cdbccaae6a7711c54b173d86bfd2",
- "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "6741696a588c4e723d279e388d446271b773c6029a823c5e2135a08a018c6083",
- "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "a62d276ad6a4832cadd3ef4c587cc77f588774b93b2807dc1ab9e0acff037838",
- "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.gz": "38a61746734681a97e84419709bd3ebc722207db656737e7be75479e0d991f9f",
- "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.xz": "b85bbcd1353315e5c4eef82707912566f6a1f94f706350ae0474a29ff33b603e",
- "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.gz": "de32ea66a8228857a34f39d8d47e6cb32a4db9efd73100e97afe12bf58f6d520",
- "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.xz": "e2f89e63a379ba8182acf1b4fba33f790e0cdf4675bc46239840ecde613b1835",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.gz": "6136d0607905fe49617a8171896bfada258eb84cb00e8042fd67bef29732a714",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.xz": "00a98839ab7d2302feeaa0fdbedc169bfb2bd7229c27aa274954efc73b52c4f3",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "2f711c4a26ed3b876e64e256bf1b4040552e80a06bec352a9d3479ed8ed6aca9",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "e479e495292512d67414d3056c322ea368559a0d95d827f944bae7382bea4e4a",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "ce43642d886784242a3914b799b1a77b60df642af2a41f75eac186b7f1b6104e",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "a83d236d59f04f3a51a6a34ccf7b79b4b2f269dc50e147d61e1e9c4a57925835",
- "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.gz": "a8e7f979fc8ad5bdaa4ea2965c305a3296dfe88ffa235cdb7aea8234e4a46138",
- "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.xz": "72ed0fb32e53b283c6a0e1752d231915b98504164965f7e2b5f06d8550e4c338",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "1f5535f9d44afdacf059681587239bf4d21985f1dfbd3ace94c864c2d7616a42",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "5faf349a9cc231c144c52de40f2a487a935c6f6146614547e64cabb26f037a23",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.gz": "0ae64780c9a944a32bc51b5efef9f0818025a423819ef60fdc799945d52bfd73",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.xz": "b3308afe75af668878959db95b039c6e1c4416badf67ee650b07f5cf07f14ab2",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "f8078421bde37f74dd0ffe0ea44704778baca779e502cb760371340a6bfa15a5",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "cc26d8fd139b35e13cf75c2942727bba7899a874d95f865c127b0c3af15707cd",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "6e0ef50cb8c4ce19d7de517ad51581c4d80043fa489278c0ba984a5d408269db",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "5c9380fb472de93ebfe59b21f2a74b5f19a632ef6eccf77a89cf0b26ce2054a7",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "264c78d59e71d4fa232f6f10713ee61d94c270e493eabad7318877afa46b7327",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "af3e5b1883e8fa7d49e64ce8754d656d2992eba33b8ec5f92245f2a82793abf4",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "0797448414c3421577705e725814dbf833a44b0930875fe418aa1eed9ebf6121",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "bd3ec2d0fde1e11a75bfc3b684c2d564bd5068519d1c5a382ae09379337236c9",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.gz": "449ea2e6ed2e1b4d656f8da8390f2e22cbbe40713e5f91cbc85971f36488402d",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.xz": "5424c5b4aa5588de73734dcd43cd1ff9bf0e0ba244749a1519afc94c8f2057e2",
- "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.gz": "b14f7853a9353b71d7babeeb136fbb595b5c23144ac1bd72e70b74227a1685ca",
- "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.xz": "af2ab319357b3b4a2810a52c824f8f308d2c3f41ea1ed30ba9ef9ff6a4769dde",
- "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c09a6bdbe6dccbdcd366a695d54be4e0a472fa1ca5bf30bf7eaf389534e2f70c",
- "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "9fad7bc10840340081cd29166aa788843a9950e293d6ced71a26e36bf0eafe9e",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d20cdcc681b0506e73ccd0b484a7b7394a08615d2d195318d0f2c5af3063581b",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "07d0b4393149f854dca2d622a6ac8d6cb9fc62d2d24977bcf50cdc1824fe6a32",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "dbe81393d5253521adceda8027b103edef45a031120e92f2e9e89564e85863c2",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "40edabc1e00f228815c88798543f55081e3dfe352f88753f5592479de9236b4b",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "114dce61c5bf25be9f3cb33cd0c7500b1a60f5cbebef27547458312b8ddb8f4d",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "abc9130f7116badf9949f5a3ecd6820787e40bb590ebbd5c867b05cedfbdce5f",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "cbebd112f0dd96258ed19b25762af60c9bac30669ae229d6b8456049779c890f",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "cff6cbf35aba285cfb5f5d2f8a9dee5edefc7c22843ae0198e693993d556fcae",
- "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c20cf9a2e72f712f02ed867e9c4babe02d7ff22d62eb96cb127054010b6731b6",
- "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "aa1b6cd4f9153fba338eb5c8a90ace06d742c97e659c3ffbca75125e5477b828",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.gz": "3308d1e3ee0ae40f8db301601c73bf6eace168b570e9ab952760e28bd970a240",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.xz": "0a019f66979c2542bf9fb268bad143cd55deac6f1502a4393464bb26a1e21c76",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.gz": "31016537cedf38ef83e29a6125445946834a06ec2fda51ef799566baeb47211d",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.xz": "a997b98b7a28358bd4ed394ddd3af62e5b19d7a33a61f55bf973b06fb9b95fe5",
- "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ddfba3dfb711db2ebb4cd7149172a738200b8e38a98f7ec5e5bbc81515be5453",
- "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.xz": "5b0435f652dc749216735fc06599a3c6916a867ab82dc126d0cde872855dac83",
- "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6408766f8c58c13ba51347375dc5ed0fb7c247c8aee9b8a89e3369c70541c397",
- "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.xz": "18a41553893aa8ff4c80fef252e8ba80c383d2809a57123fe89e89172a5839c5",
- "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "28078984a80c4cb0e65391ae213390059a9eebff028209861d23c82b4db0a11c",
- "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "277cfaafab145858ee5102a657c597abbdfa33ed2d6f1c8806f218bad91b2d8f",
- "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8c8c92719f3d299047089031cb29ce209e2954466415449d37d474e88a732d8e",
- "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "d055a61cd0ec951edbc703180c190ef4dbed3391d1b2472668340642e205fecb",
- "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "95433c7dc0437f61a024276c10a0654128bd0e873597932297140f82e34ad201",
- "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "a3660c9909e3821537a275e37121950d6adbc87b85959e80fd7b72c6e3b7b944",
- "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "07384f5fba55ad572753fc85ad6b2d231d94b31f009defb694c8632b38eeeb62",
- "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "f0985ea483fbad75a9cff021db6c230c5c322eff942da667a0dd6cb3e37bb2c6",
- "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "81a7ddf94bf62f45dde9199df8b28ac9971d23b1817906e119ca4ea32000b08d",
- "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "7ce055fd68b1c5e3c48c9f03289cd4eb3af619cc30a7103056b20fe842a92db8",
- "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6b853d5c2fd2dc61d89c26bf5b365f48a9c535dd30aa672f28f254af8fbcc9e3",
- "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "32c659ea9578759020f291099f16b1d12eebae30e07d35568e69cd0721576c24",
- "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a73a918ec89b759f19b605df527471acbbcfd2e3debcd0601d7a3956f645bcf0",
- "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "eabdfdac435195844bdfaaa5f8bf6b57cf045742c6180c3ff0822bd85fac40f5",
- "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a626ed9d5ce779e7fd8ab17d4dc83130a57200669730851bc68eb01d88bade7d",
- "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "67f195e60d88b3e0f1a702f7ba0cefded2dca6ffc03ede1f9b6e4fd38592eb6d",
- "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.gz": "01e5b6d7153866ada9d3c1caee5c95da58296acd7007aa93338171cc349af304",
- "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.xz": "a0b87b79f87e97a746ad311f2bf36ee9d5784f504f844427415e4a983ea4a0ac",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "54ff5dfa917a5ebbaf77185d4efff9700d248dd66746dcb3942e29917495dd3b",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "2d9dddd6b9a3ef6c5bb0758dbee171f08882292ba17e1f98445a9cf196f9c02c",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "359690df63e15260f028d6838f4f5007f828c4a977cc657513b8ab6900f1d126",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "6d8d2b9d5964fe690d4f6fd7ee643bce5f049d19e33c7f3b580502ba83ce5ea5",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.gz": "5e47aa933805000f806984b09222808636eddcb58ea0b95913eae6c4f0ce913c",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4e01128800f479a96597ce7eee9d2e76a5128ae1c13a4e0e2eb52e36d43cf559",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.gz": "51cdd463ec6402dac5a4b0ab3b0e303ad97ba49c2a63e1cfa2d8036d060fd67a",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.xz": "498cca6f9826a9180759a0446627e2e6dba50b6bf1051044e6e09dc714d7b3e7",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "59314c4c868e57a76f7cb4dd80cd9a7e6230b87080784db44349420c950efddc",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "8b3e2cdba3ff86144029f7c7446825dff79937ed8a30df15a33a779e9f694227",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "56dc8f8914bbe5beaa1e369fdc22d99ef98c9d864e24f5b7d64cf6188c400b1c",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "66cf18df72034540d756b29d69a4148123029ff512fc831a786fe15a9641382b",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2315fd067e858501b4df44f2a4d042cef3f70b7314ee6cfe24749849b8d386ae",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.xz": "62b429e67f24365963b0744e9b4807ae2cb7aa280a5e425882e4894a2d3225fb",
- "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "691922fb32f3da37532bb9be974ad1717af521ec2b71bca4bbb5e57f3c4cc3fa",
- "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "2c9667209094b7a603d50d3dc684c505b2ab855c64dcd8b23fe09248a6e13cee",
- "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "daee571bf222bb7addf0d495991acf3f5001b69bb97d31bb43f0466b4e43c600",
- "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "f6d31e21f798427c5483256d54b25b6dca1d61ff8c601384c62648959ebbce25",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "98b2eaf259a1bfdc70e40a52e891920dec7fc6132ad8d2420f91655c793ea340",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "a97c1c2646f9628fcc92818d21f4925568681976727686701116d0e6a71693a7",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "a4df0726fba466a5180471d3e63735c2b5ee9794e9f42026b1e8ae404dd43ab6",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "92846ab58a75bddc0270c9f42234a6585edc9a382e2018baa776aa74bb13e444",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "a8dbc2a00d359c95f05b0b3cf08a12b6df9f888157ba57fa9ba4a134cf271075",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "44b17a06b015f9701291cec7e60b0932c5ebc29244f4a6e35736e9f5ccf47c41",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "ee54b0a25f061c29ea22977c7d36d6fa6bf85abee3b108135b53bcb37028af0b",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "0a721d2526a78f7e70f9a6c49d156b1c18cd627c066bc8f09b084910864ec252",
- "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "584ba68113add6e113cffb5c93a8000cfea16d621ba337dc68cd4d106f5e2759",
- "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e450429fcd37f15b6e200f62d9cb4790b39b7227e0246b667c82fa3b9ecf1b75",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e0aa68b96699402e7cc09329055826f63ac9899cf22828d56cf393476a70405a",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "6f10f279f81c35c718446e837f5f22fb61841c45f5172abb2d0d4a035065edcd",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "aeb05fcb66830d395bf9a819a05a44f179cad3f35016f76fa60a4959f9e3c69e",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "351ee1490533ac9fa00a21c6db6087cb498b0034cb21358d29a8b944bf0f77e3",
- "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "418b0481fd2b074e9a0f195b9e07f888652642aced34136044bad997f7500802",
- "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "90d04308cbfc845462687206bf13182d907afebd02bdf88cca9a27eb8f1e7e28",
- "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "0d2f54c9927ac9de3c00f8f703d52d8310d1b36baa84dbcddf1159759b4bff06",
- "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f2b33077267e6ae064b12c7d0082115ea7f011f168f0d0e3ad9dc7ac9d39705",
- "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "bdc9fa2cdb295e453460f1bf7b12efaa673955c27b01f22df626de989c3e1a28",
- "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "bacd376fe18068010ada3e52c531de5a07dcc8232f988feb9e90be59986efb3b",
- "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "fdc93a8295c563be29793d36b6b1e25f579d187b7e234ced6f17b1fe3c1fac02",
- "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "289fd400d4959968c0ffccd787d613943c8534527913d0dbed69e8a7251ca32c",
- "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "2e655b764843cea5f0e70e2a5b2a0f13dd5fa65c4055f42c547e36372af08296",
- "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "07f6657648d1d7033030e9e2d05bfb9ea0022e63ae72320074a3d09ac9639d09",
- "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b78878ec58d6b932d3d1f8e1fefdb7871b1404c701ab0d2f8645246b458ba650",
- "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "dfa79cb51708794d2c814bff6a60a63ca5358df3670179f9a9ae828811e72ad8",
- "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "017de1a82a0e3988d1216771082b5d0e3e083dc51d4a0f0266f1e610bac166da",
- "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "a0a46a62b9af14d2147939967e545ad812d9acebe3d1ed861321a6dfd8d554ca",
- "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "54dff0daec5dd2a2ab23cf4e92bf9b2d71839c37144b52e5b5aa899ddf027bda",
- "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "e743e45dc695e0bd9a1ce5fdd183f89951a329ec433bb510d37c47b435152a7b",
- "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0e04ae69e03d9e7e8d1d60a265c7ed3c3608a19aaef6ad4aa7ae2b280d3552b8",
- "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6ec865bd38b0fde2c9c823f4cb110b96c2aac4f7976cc2a6be48ffa214aa4bc7",
- "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "3b833517415dee73b1e0d381df441a96856e3bac77f101545624c382aad7902c",
- "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a8a447cc2167d0a998ad3858dfec88beb8658043655087d208affbc94aa3e62",
- "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "20de8ad3aa7507dd9657c4a4b959c38cc7f732a87bb757183033f78a96288e45",
- "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "99561b207ba61b455d1522d95143ca4ccc6474187be2f38f1ebff2ed63d0092e",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "145eb25cc3b295060c5f5a354ea2321cd39df17ea4e3a5c73c3eea105f7454a4",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "356ede5cd8a7d51f9e25a54c329b1be1da7d6fe418cbe86fdae9c8bcd9970ac4",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "0cc0f10763b73c5e4c8bdcd15a563d7e9d705b192ed6e8edc50dd6a71b874761",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "d734aefabe95fa03710dc75e9851c8f2e654f19cec1381ecb18281837d19db38",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "e1c28472a81312560ca36719f0b61b7212a07d63e85d745f97cd8e3b9ea8f191",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4d6a62738f842e54666c608a466c64f896097ffa65d10d30361704e4b8496eed",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "75b21690480f6214ed174ca86297d9a41f37731560adf5782ccd7116b0df583a",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "5c08f45f557da789d39bf203dfbcf2667f4196dedad327a19dc3ad5bb783079d",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a7d579672b94978e8427584f7e9d2b6534f320719252db46fc6ee85082d646ff",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "6ffbdb558b9d25e9d923534413b25dc99bb5b9cc92b4774d5255cf70ec20b20d",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "fba0e7bc1401b830223b5207b63808e28403f48d1591c7d47c1681519c1883f7",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "644b3acc47cd7bbbb5405683ce94e7f32a8313ad265da753026bdb6c3687b608",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "3f152caa88299ab8aca2c6d39a5e36af995b95e3394c7d514ed94e87f7c61fa3",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "5f92b4d12a9eaa50b29b81a3dff1959e59966f362b67c346b74403138fdb320d"
+ "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.gz": "b81ef641492ff2f03a93c8fbfbcfa78db2f6574d1998569d68dd2ba0e08ee186",
+ "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.xz": "925090782ad982202ca554a84e9d4a7b190f94b0b220c23e73235383d6ca367d",
+ "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "eba42edfebc85c744f4c6874337847748df65e430915f47238a93b1b7e96840a",
+ "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "fd04a8c4058ff287ea0256fd9f33a4b04b4f098d6911e8d827525cdeda6f169e",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c7abbf1f265435cc9f6f0773d30321fc99353e0ddbf0004d00f47433eb3aaab1",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "3363dfdcd7106841edbd9029676ac339ff54c142921d71d92e308bee2ee33066",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fbc5d5f70a36fc73f4d34d101aef4be78e38b5009ebf690fe46ba32eff6c1fce",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "220f23f50645532df4e5a4b1d6d894ce66a6ee2e5576fdf552081644a74a1c8f",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "94b42b8639ce541c1a355991f20d9934c72e766b6200d742d2d5b3b2f499f782",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e32e9df3ab261fe20c363406d655fdaeeefc9dbb3d69da4551cdf9c22c418eb2",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "301c303ec0db0e342ecce4e259e79810e082766bac8f9907c353bdf490177863",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6f9409076ab4e2dac5ac5c07bac6be30e83e281df9efe2fa68386928e2e6faf",
+ "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a4a82d48b2b1e6a49c0a765f9ee4d01e7ce4b0543128745d13cf4684c56eca8c",
+ "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c9ca524ba0e76d9fe38f0e4af337d14b97fd97dcd83d80ebf4725b5b03bea3ac",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "973eabda91963d58a9cdd1491bcea15834874fbca018287fb7f5c8bdcdf323d1",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "cbbc14d1ef0e4579167fce4a5fac43b22c87882049a3d0edfbace9fc5c103ad3",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "ef090943f6c90bb3327225e0256e73762ca2f73ae5d0d07b2c828709077e1132",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "42708683ba5ad855880ec69d92192bd9f99ebf102beaf6c53680cb8733fba9e7",
+ "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6c260ba19734482439bf6d12b8e87e82f269f1bec447ec85e59372ef6489eec",
+ "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "fb6036ff910d075fb5e483000af641328e6d7d01c33255c099ed1b0302239918",
+ "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.gz": "71e4e5fcf055251089ac0d37b5ad873eaee6aa0380438cd68f140a16d3a37cd1",
+ "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.xz": "b89acabf106b10c5c3421574bea83d8baf1f29d040c40d5522f85e2e6afa6373",
+ "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "f544ea08d2f6086dc49c4d635116f3b4b804e5b68251e5fad433d538ae5e8226",
+ "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "54b0cbb4292cc4733a704017775e5cd4a9be34d53a4c666d6fc556472b508e1c",
+ "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5e81253ec483f096e23ed98f939220b029814c041b4b72b93e994cead3dc4f4c",
+ "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1a66beee5ccfd8b0fb4de52bccd11a0057248ac7fe8daf4f4d6fe0c0088044ea",
+ "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "2a6cc2e98ed575df64661595b6e1ec2814ed79fb63fe697c0201193eb52d70e0",
+ "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ab3f70ea6977306c26c9cc368d64a116716f9ac6ad1a55eed23ddac894e7717b",
+ "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "ddd840c0c19077b4b45dc85920a2b2a37f176795b3d9390f1faccd44aa3d55e5",
+ "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f5c9f1df082a7c48a63e786e5104d31e616c31d47514e9233b4a86d24700159c",
+ "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "4d39fac4d45dd73221b93b1d1351988ab4bf07ab04187a815467ab9b992f9490",
+ "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3b6b0d38a3644028ca76347d5b82da6bac6e761a235516bf5b321d12ba909519",
+ "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d5992a6e66207e4ead98d5bd627c181a052775f03ebdd2a0313574092a12abc",
+ "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "217940928d5c22553f910f3abf7b56bc832ddcd36282cb85c4b8142f9411147f",
+ "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "67ce7cb12cbd06e114a2f5dedd1d94c844f091ab05a764579dccf30e6158ea46",
+ "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2cb17c66bdfcfeb567bb021c25c33a8c2b8df1366601d09fd9332278517a2f4c",
+ "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "e25a7fa310019a3457b317c9e3fe052602c82a25939c2ea8c012ff6016c622d9",
+ "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "1722ef69ea949c365f6b64735ee31dc92082db1177b94f0086b8aca790378398",
+ "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.gz": "f171fb45017640db15d437198b25758c49649b64338118501905f48ce957b93f",
+ "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.xz": "59c5f8ce9fa9dbf3e96dd8a38a52b8bff0ff0d97c081b1d343a654257df1e500",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "4f219f3661a03330b33d33cebadd5eac759968e1c4c3449f0f27433e715ab55e",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "5aed2d9631a2aa3fe016ae5e2ee312aa5357ce470c26c01171d14a159af7750c",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c9dfb9c486cedac794cab6ac524805c10d2853c15416f3037ff4a5098514427a",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "a1e0aca8a32700e62fbc73b17dbb0be711db4e9caf535440b08bb1465d6a9c9c",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "61c041ba51632c029d916f274ed8ff92f1f7b23b5e9641591828e6251e205f6b",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b61464e9e1c2e820a237f1f3d91cae8b0e62cda16dea51b32a8cf695b7a5707c",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "1f9b7e500b22c34fa3080e4a15397a3a3827797c237d21459841055b5cb6cbaa",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "97aba07cede4a9228ff1b937b8e884b23e9e246afe39b9d68896e6b4a346d972",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c82bf6a11f468ba1d865a3cdc036b03f01e63a23272512583afa9dd9bbf95824",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "2efde3ef57e877f7a0aaba264ec14bc94d0cf3e4451b072c004c37e3f86288a9",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "17df9a194a8cd80871981fbde5fc333794e36a4ab219aafa7849ffeaf07d95c1",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "54fd84ff5bdf3221b151945ceacd71f51e71898927fe4b57887a0eba5d3e3676",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0bd987dd970f98b297afbb7cf4906b1d2045ad09df929e8ebd291125e3c36126",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "054af5ef3148902a8fe07c2c445ea98a526f63203c13b849ba464d17145afe07",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "2228315b5b7280a7ea9b3acfdfa1a8f0921391f67d792f32f53c1b303565a20b",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "777d4c1c6bd3430771280dad79aaa16a6903901875529391e4779f0c2fadb0d8",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "1d2a74d8ff44feae6551613c182a87d078c0d4cc8f5117c6a3763f28d0af306e",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "67ab7519c7182a582fbd3e477b8bbbcba143a76e442cef94a47f0a03fa36ed05",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.gz": "2c2a8ca955cc99e86823bf7ede5492b04ea28c182a94d0f59b0d542f10128e88",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.xz": "bfd421654ad72aaff2610a104d0ea2afec579803ed16ac70ab594067cac292aa",
+ "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.gz": "b06020ac4aa9b5236d1888a59e2dc3519ac63c760ed0ef47b706466df437d5ba",
+ "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.xz": "92ffbe22d8fe9474aef42cd3bbe4808c4afa212a3f65f07828b39848dc03a1f9",
+ "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.gz": "55aa7b2b3b79aba674bfc496efba37400086e192e6c7fa8483f5501ba31e68a8",
+ "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.xz": "6219a156e46b7056a9046ab5a58af1a5386024b2961528a54fe6b1c3ec09a91f",
+ "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f43fecdf75ac81f8b18ba5ec59625ce93b0debd27c0016edd76d5058e8182118",
+ "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a032b56685b2b8431068565d652e5a174dbc9febe6de96945c037b96359d5cfe",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "bdb7d197cc36c774fe4d59a1c86b46325e93d82462c1cbe87e8ab415aba78e4c",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "061cb27b6d5b8e416457137334969733cd0727afe75d63d7954ccf547b7edc51",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "895d936a579c9642efcfdca400662264b8ba84ab9130f88e4dcd11c968a81e4d",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "29f3aa4005c64fa28f99af20221956ad21aff4a37c5cab9723959ddebb3c2b9d",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1e326b0ab30a2f9172a55272926cfa62dca9fbc2c590579f6c7685b8b4ad789",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "616fa68272334400c9110cf5a2cbd7d5c6e462cef8d2c5bc443c3ef6e9843e3b",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.gz": "ec7d513787434a3cf2d523dcff7e37c28cff4b09b13be93c024729cbbbb5aa83",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.xz": "5a396cc0499690193879d10da333f5a3acc6586f1c216f751a1e62bf1a8b6618",
+ "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.gz": "f9baf9d74b094cabdab59c1eaaf5238caa175e7865c3497c34eba68be5b2d756",
+ "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.xz": "0c5f14f311e29233057ea466123ef9c33e3fffdc798358f0f339ce3869ffe9e4",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "e3c2ffd3d69ba9035048fad22103989ec97b892de955a94015e16578e42481e9",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "3e716d6aab270f764233f50a25a33d37a6d34c2dea23b3cd1aa5733c72c13958",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "65b74540b47fcf7fc8a88cbc5cfe54ad67c1060722c37af7e31bebe2b3c204ed",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4bf4f75f7c4ed171ef7705764f71eb899763205a9a4727343b96cb209691a97c",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "be073a69a1e9de0f87511a5a8b3454b3a2d24319571c25f347f7213c872a54bf",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "57be5edb2c00745235dc486b4e6e6f0e6b40edf16481405abe3ac360190040e1",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "53c39c89d7b19e45e1a4f32b07eac8214a7d5d277a83e4a88d7ab8820bf2de86",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b9f058907117e3f1921fb5ee73e04c6114154870067dc8791382f3099aeb5c0a",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "bc3d93dd7381749a7d24eb904c7fa74aa6e2a575ad1af5ef7e34ffa07e91105e",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "b605ced5cb597a2973417f4de55fb39cfe12b1209c4249ced9232091395d8e91",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "315432af4541ceabb14891da9ab6af6717bba88f1caaf216053f75405ff8997f",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "aa643ea7978ea7911e50ab65ba0af7bf018a4bf9ded1da8e161ee7ab13decbfa",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "3f780d36c780b1379fde18fbcd6a1f75efa766b56a4aa6933c9bb88dcd4f4ba8",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d0c87b4127f10c85368254377013053747c10d2d7dafae2f5643a3526f938f48",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fb4a610676f9102dd206a1762be6bf7838b3eb0fa08629df8199573246bfc38e",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "192d9bf1354737dc576bfdcc310c936e065039f39303370008dd0fe3d3e8ec65",
+ "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "5dd746bb8db14ca9f968a651f3ae7e3c3c5a505800c0c3da8f6469809a81230a",
+ "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "2cd651fad1f2820a2bb9b828faf292d3029ce633d24283d9a5363a726a024044",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "06f337db74903b607d09151f8a5178ce48e8b5905af407ae9b37445fe78aeed0",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8851247487823bbee990937a1f83578d910985ed4055fe3bf339871a7aa28bce",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5696a2c0fc2c3141d43f2d97d8e4959310032756cbdf0140dde28a5843b431e8",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d8f9a3669d550f1c6f338d99ea74f4e48771620d4125bbd408cc750a70ee4686",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "326e4ac48ef1e1a60c434699b5fb09b9d0581e020bb745196011f2f61af41a13",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "cbd10db975412fe275d12b81cdfd5e97c0b464194639dcc439cd72a65790d601",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "977c9e94e25fa9a1db5f93ec800d529d80d874ceb2ed3a10bff63639fd24da59",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0729470e2138e90d9140e30779d7397e58ebfc1ec243e55caf90ab12ef904da4",
+ "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3115e3b7f0981dba799902b212f350608042a2beff3bc3b32e930e9c9c3cca17",
+ "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.xz": "75b3d8eba51877916129d8dec07bc86ec6e88076af79cc221e8543695e64da63",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.gz": "9787d23a7078c94b4ac33d34cdfb68da586d777f020a6284bb1540b54069f476",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.xz": "c8f9b933b2e9c955e6bbcb141082f6b5833f89f34de16e14f54e8d4aac02c473",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "ce9ea3ade0886bf7ea40a1066981d172d915aff4c54ca325d72ed823c7e17787",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "2d2442ed2ac017777d3fab1a3f69a578a9db1139fa1aa63dc87113071f08a6f8",
+ "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "98258ea791d398c6a29e1ebe28557aceb59ac228a0bb1332bdbd9f702c61a4bd",
+ "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "a4172c8c2b719d0391654968377fdba932343e444bc78482f19f731ca45806ca",
+ "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2221360e32bdbbdbf073a4bc1fbbb98b86bd0a1df526cb8dd05dd521ea402c7a",
+ "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "03c53e31762e5ccc58d1296a8fcee123592dc6d3b88d0c81ed1f8305545faca1",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "612eb9bc2a06779ec05f6033f44b18f283d6cc8dccac0d5c81a6d09f515fc077",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "70ad4e52227ae069a9e99cf53e07470267abf1f2ae0398192ac854cfd31d50d9",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "8a5dd3dd62cb31c77aec2e00847812ba53e951fb284c74671cf3875b18a015eb",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "10650efcfda713c2a3053a9c505847dd021bed19b1e3af12d58742deb76cb421",
+ "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.gz": "6fb4f4ac2b448bebade72ba2080bdcf579b6a40041b311301452ee41ea267ea1",
+ "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.xz": "6e0e8feb477ad35bab1ef599f51f64b4720dc37194dd6354a7a4bfdbacbf2c82",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0b0c0e86be0fb63dd56b419f0b8d05eb59841649120e16a8216bbe490a76db1c",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "c54a116404d31591d6a6a1a332e4bb8ee177ea7a0367b11eef6a8cae6c1c0325",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "14313eb7b20a3a3739a28406b1544cfe421c593a3198b081956a1a54387cd0b8",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "54fb4abc77fb6c97929641095ef86e559a4cb116cdac7dc4bf34a81aafa03681",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "9a2a5b2d3d5cd98cb3f9a43fc34d3dd0dcdf9bd104798380f70373440edaefa4",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "d0165b16890da11196a1e4cd6b48d545f44ddb996ba9515a919ecad85cddaceb",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a42e125c252eed17664a50713d5e2f0c43f0f9ffe54e471500db75352d1e2147",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "705185a2b4b98f6ac16a9106af60f30618c24d6d93ffb0283a41cd31f992750e",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1a01712d4b8b470548c22a24e7e9524c0ddacfcf15459b490531e68e62b8a400",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "a86f8080ea25267f7e127f23bb75538cc3032091061b1fc3ce95c917d2a1cc92",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d6d06becfaa6a4b0cb7131fbadd6cc6ff58edfa11fc6d98e69d2cf5388e8bdef",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "65bafaa34e506e8bab15d2442742fc075dab2ea8687c69f6090acf0204b6fb06",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "53a48c17c4ed3740049d0c88b14d2a1189e7ef5fa08a926c8ca26ec5b2b298b8",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "14525b83b69fc54d4c808ffb69e06f015850ea9186837c670dcc23b5bc66d4bd",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1b8f11cb2ab076f00cd601c1465ff3a2e3857cdec255c8ecc1697efa713f5626",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "31e824a6243a6e15ea96a2984c69711e312eefa5214ba349ef6d6a4c42fffffa",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "89178cf43cfbffea696390c317230d39108e529803e28ca60d37b6167e589dbd",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "8b9fc0f9a2297d15abc86db95ac8768e872ec1acd21461e599a1aacb80f4b182",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "13ec0039303d3df358ccfa4fc19924df0ce17b31e8f57b13e7367db68bb9dfe8",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1266340a228c8cd657d0ee7ef257d80a33b193c4ecb742cdb82d469772311499",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "b100adc79e776116a267bc918ded30c4c8d27d83ed21f65f9428ed8831d101b6",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "6966af76ccf83f37657efc4aff88887de81642dddc3f2ef59dcaa91219d4f674",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "0b7a859f952741a740458609cd207d5f7291c054fc6d9a0191d3acf0f216bd17",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "2e6e61f68fc3772a6c3b3f0b3be6d99bca1a57b5f568e87397765cf6fe867dd1",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "881946b261399e50992beb3cc613ca2141736a7480103fa1fb117c1e7df2b1db",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "223a78a4c5055ca00a7d5b40491aef9498a204759cb388e734408e305999713b",
+ "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "76d81922eb6f61d33c10f2754ccc9b1394ae09feee5818b23b62f768f0e6a370",
+ "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "be57410669ba5a516dc935fd1eaa73b2d0d3d237a2eb184a8dadce919bf1975f",
+ "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cebf48de57e57285c91092abc01ab1fd9bc7eb660eaad3db2ce71877bd6b9352",
+ "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "30a8fc47441c4f7b34f540f5132b3d7ff9756e8906ac6e2b9df5ea8fb622ad65",
+ "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "7deb058683792cd3fcab92b950f653a4ba0d2a2997bef508c6d1d04be319f057",
+ "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c5d26bbe5b6c64ce9cae78465d22faa98ef956dc4d8bacc91a127a7f439f7b11",
+ "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bf06959a991270e9e15d538e70d078a5241b6e87d62a55a655e4c2f9e8ea2964",
+ "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d85b330532cb6743071ffa117fbe8bc26b9c6167a0ff76c0ba32fb17c0247c70",
+ "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "7dda5e010ddb4afd6e6efeb9f43ef17cb30af7ed9f172b59e6c737b2f9d66ef8",
+ "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "35d8feb28897bead99c17d952b711888f2f6f613fef767f28e3593fb4aa2dc36",
+ "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "2e7067692c10447d50df8e9871f95b4ea925a88c5792f973b3c51325afaa8457",
+ "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "4b2d3bc61727c87f7c2ba129e9147621c3e3efd542feba3acb6596ea91d10d71",
+ "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "093aa10e425beef7d66e9986b045543b3dc04c296fa3b3fdd9071fd6d61b269b",
+ "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "8f3512c368b7c44c7d8ec9e1dbdbaed344859ebe2d0dcee22118397d41b841b3",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "adab0b58b93d37949eb35d4a6f3ba9e6b43630e4a82f1d9047116f1462cd1809",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "6a0410d1194ec0c471e384c5d02aba555efbd47b36a3544c56674fc2080c51e7",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "19c8be8430ab59b92006e0bccf186687569ca172b54f934ff4763da20cebdb58",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "6cb9647a504683fa5c67e5ab2e737bf1d6004dd4a7ffbaf593dea0f9844ced6f",
+ "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "cc2d94e753035ff0b49490173b042d21f1ea58711f7c6ce5cfdfd79a76e539b1",
+ "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "de398391e577f2fa09f369fbea4114c6cc0f1412884c6f52c97d71c74920462b",
+ "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "feefd67b9c9dceee7ef7947753ebd990a914d7a54562b718e6704d35a1f5c75f",
+ "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1b550a911a51514f8d69b9b763cc3379cd674615090652a253eeb7b585d2d97d",
+ "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "4d7d78589d6d72e5ce60d6997394c4d7ff03fd2bae471ef3334f1d5bff9f18d7",
+ "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "ec499330b2f63047eb43bf98b1e66d301d7ea7015447c83307ab528421387502",
+ "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "7e48f11954d44dade640c86cc87d5841ebd708643cd5220ae7d07127f71ff333",
+ "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5038770dbb2dda71d32c4270653fd3ece96062b24ad55dc8def6475e464210df",
+ "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b8b9a59bf1a9127b26aff54dde3a1da9992a99fd3d601be7cc1daa6ce3c7b6e4",
+ "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "e0a96a8b105466a3279da3d9bf589724def7326448bc6f51ae6f8e8aee2ac880",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc3a8d935ae2101cff8af86fb066c09672f9fd0297cd9d6b960c9f4877618e98",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9bafbfbcb01e23f58b1adc7fab26e8ebd135c5c20589887278065f75cb5b5350",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8dd7c2cbc2c24e5220ff6a7f5caffcca6605f3d76ff66f766af00ba4bb316067",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "963a698d49c8742ec5c7520fdefa1668db573eb01bd7774f80133496122b0517",
+ "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "3a01a35a10f0efe48cef64d45e80fccab31df8287f500bf280b5d9bd5784ea3a",
+ "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "84a5b9d9cc21a13cf1e2e1c29e7af63c75690cbb2293c63fe95e075ebf59815d",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "946e96f404b8a9f4c8139e90172ea26f3a6c509effc6e1ff16a49dc9ff6cc1e4",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "787cd874aeb33e4a4fed2726a571d39f6687da20625aa9a485a95d7167b321b5",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "70fd17c069fe4b6a318d887794c54a142275cc65f088a7bcbda5bbbd7c9d6aa7",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "15ce829bd9ea0a1ee918e7887392ce1e74e00b23509b802f5f45550176d78768",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2edc66ee89c319ef7c9520c5203185a5b5203ca4ea9996e0142075273ccf84b6",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c129a2557639fad501c7f1474f45535a55c33813a889f08521f4a7d527010ab",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "354e644c51ad5863bb0eea09e0c5d1aa32858e7025c039d693e2e433e1c18c04",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "6996a329a81624537d45b2401b8dba81911e5c61d2fff6bcd63c5fb15b2fbec3",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "97d6aa47e209650860e97d442f7ec5c5da385399aa5f06bca4c7f9a08767026d",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "dac5cadd67e5d162e00861ec5d2c96166fe1a80954237068aed6072afe0f728e",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e0161120cb6cefb23514c839eb2be13a54139d4f408563bd9dc1d6b9d665496a",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "94bcd63f3712cb3b09948ed62c8db889e2bc78b97d868c89386f912d0daa1b4d",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "00a37ebbf36bd66ab6e0b957e93c7a2e5c2d8567583c65873abc1c79b37bbabf",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "75589caa1835ee12362a2ad581828c9faf0d527f48d5a07c1d7f0b810e035def",
+ "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.gz": "2276b9ef2ff2faa665f15d3572abe0d13a5bb9ec0ad08a6a0c00d9e143464993",
+ "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.xz": "fa132a08849d7c583dbf37db97f3702c263b17de595823d87fa14e56ff21ef3c",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "47454a419e6a87b057047c002932cd2f0f52a77ed4c3b4e4d9b65cc4f4ddaaf4",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "f9040fa310d122651461d026f43873aa18d5f2c63a9f3bdd47f9a034e4153348",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.gz": "e143c4c8d394810c7734824476dbbfb2a73b3b62cb8a708f796e0c0332deede9",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.xz": "53c660ef68e1898574f62725c2f50fc2f26539143c0be0675327a33511142f8f",
+ "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "e419db2f8f12467335c8571902f1ed163a5407394914f55416fe948525140ec5",
+ "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "efd2b6df7dd439b0ae0312831afd4517cf19adf619916eeda1f571daf1dae723",
+ "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.gz": "e669378ed5da5948dbe232323ef3926f37ad430feb8c398259229fd18675de20",
+ "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.xz": "5a26a35164ae44467d256e6fab0e8f45731e8840204635ac9b1dd1d7d8f96810",
+ "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.gz": "0d922ff7d7658c296246c22f4440a8975c8036f7159508e2fa964d1f2ad3aebb",
+ "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.xz": "d775ecb6054216f0f48dbd0acb7710fc097ef6d61df9c1f59139721ada7bef8a",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1e830dc490e9b00b86c9d55c974feefdd87efc06c1bb90088b41737151987dce",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "cb37a89a871d61849f9aa262bee7248813a8c7a422872aa3926f20c1adf4ec63",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d83a17c374e937b9a06a364d0be980f4dc953df01efccdb3a0bf853ffd889718",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "94fb51d1db6482adf683b9953fcc942923fa5c85cbb63f7b05ad19c24272a21e",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4b7cc0a0a6b07054bb1da0b75d5f687fb38653a7b31f7610f5a90a402839e481",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "267f634ec4e08d0a76a75ec0f4ae037aaba44db3ac2969ed3f34d74db43bea1a",
+ "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "3648f1129895e89467a569219570061a6c50937d87bbb407e6b3b6b1f488bac3",
+ "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "3a7d686102d9f2469e180a80679db52b6c8dc8ca35adf3e50a25b7bd35f4c6a5",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cb296c0d9e07e00b8561c2f39a7dad9c9d74e224658fa9a7039e34d4b5f3aa7",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9e951fec5ee4a4a655693d1c9e205413aeb3120a7b2c0bb6673f4392cdf9fa6d",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "35b6775e13b79b946398a65d6cd4f15d26e160dbf44718cf177679964b2f3cec",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "84d127ce90d62f1698a948ffb247cba400bd162b9864d2ca7c0240a46b23c88b",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53a627ff89fbfd2abe9b4354e25e02d2ae8d05fcf6f6cefe99b84aec9775acd0",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "7692b0b44eea139874fb8c6cbaca46b8f156ce392454ee4891daad532a5c6baa",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "853db076a2c469e37003fc8e52af2d0a2e31cd7f74c51147f00b04532df5721e",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6925429b5f25d0454abbd68ee333623ccec9d706fe0ec528fb619b2688528770",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "13e920a779485d04952e4c402b42fac9b7570098e5e32394996cd985889682fc",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "158062a56de043afc4acefc8eafaa536c3018cbdc7696b6d909c757050062b42",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1701a13827b3ab22fe78569704d39a2f699f463b2f6f159407a39eaf4c7fd6d8",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f10ff1def90cb101179f11b4b07ceeec0ae26ee15c7a85f80e4e31c61baf846c",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "20c6c718322cc341f0e1f69a9dc42f3146d10f32075d32376a241a90a2e40f48",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "d0429de3b0391f063836c765ad17e2fd1940f737b69961f501eb9d2573cba6e5",
+ "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.gz": "31d16857f6fec033e6f79121040eb025c28a1d049014c6047fbf1057450f86d6",
+ "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.xz": "997a9aa6db5e23f476aefd3f4799f986a51fda3e31e2b293309fb65fa92b0370",
+ "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "73fb943292d50a372f2df490e47235f395ff7eceac353be74fde3adcf45d363f",
+ "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "30a4a4cbe3fb683b8e846052a83a3185d1b8d714251bd6ad0bfc251b49a72121",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b238cffde0b9ae2305e501970cb9cff1782331f1cccbf8dff84979d1ffdf0625",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "5d01b8e471419036703886fc7dcceb89ffc88fa62994727109865339fbe0c92c",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8b8b48fc67a2093502baf21c372870bad42840377548e250023c9f83884322b5",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "a9e73e67a7120968474040dbde7b12668bd6e3a6b4f9d91b8c9a66474f68e40b",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "4e83419922b4f02b1c1c62ca14db65863f4226cbaa61674ac792e860c026a948",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "20d7369422ebb89f8e1064616a9842cbc98d9056910a2d0ba46f8bcf144cb794",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "05ab3071cdb3ea4e39f53e179c754d2cf64800ca1c38ff887e45f60294d6e222",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "e8509c60955ecf4938575a7a40091ba5d7aff77c9c3e24208623882d1bb45e6f",
+ "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "185a3e399dcc67d8fb43a0174ef8e15c36a068b82aa33db8b42c948c2ee15689",
+ "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "69be7881ba1b2d4348ea06fc2d31a62fe484843e660f399349c49a17852cfaa7",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "74c3a25a67b10abbefadf63bc09f6069242267a9ca8a9177e2f46e2b29869b75",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "9f0d3ce0a00b33bb591d6b615f9cc80a714f3ea0d787f410da7d643ac5e1144a",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "feac518beb813b2d553d6ee1ce03daf890c956918f0de69d5f59d4067f2f60d3",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "aad640ae5e48f489148e1edf5e815a78b19288d916615e2af8805f0023e15686",
+ "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "c5996c458e6e1a3f3dbcb70debe562bb5d0f4a6eadd97932d8935209fbbe6809",
+ "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d5ed640d08bcf3770b80386282c442d79af38e4c7e73be9617d0ac72d553c507",
+ "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.gz": "aa0dd3e77f92c1cc21f550c59761a437d3a8ddf31b23040e8849dd116e209835",
+ "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.xz": "3c7bfcd663507730ad3d07024e1d884dee6adb49343bef0cfb8fd07b8a56c6e4",
+ "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0370337cce565e6e363e6de59aaa8c2e17db49d79496086c20f00d80198635c8",
+ "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "30413f65a4fcafbbb6a5302cc65bc35edc549cded8ce6a32277ae9a499adfe59",
+ "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "0e6ee26e237a185a26068c2c69ef095ff37f24af7984bad91196ad253dae196b",
+ "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f0185e074bb0c6811d244502ce93384cd7256840fbf64025e074d97e4ccb03a9",
+ "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a2c1f733c16d62300adef3ed41f9c5926f704e6b3d47e98cc615665496aa4f17",
+ "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "3945ad08c0b296a700bfca778994fd93bd3cbe643517ba20a60aa1f9a88eb2cf",
+ "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "e3871e21ac938b4bf3a1ed44fed2f05fa3a27d3eb000d98876f9f220a5fe9175",
+ "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bdc7cddaf0031af1b737fd0c2510ef018d68ebed914200ae8acbfd31ad38ad06",
+ "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9ea42f7e50864bb514293461d3622096fd7a73e8f487578ba1425a3e8d26a970",
+ "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "c39cf38c563b16d303bc2cde8c67527e7d2a74e8c5375af73744d9a9e3dc5e1e",
+ "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "dee289bd99b3b573493160446f923fb2f2b66926a5a69c0a7704eb2aaaac3ea8",
+ "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e3c89f1baa358b6a28ae567981d5efd457d2df61f2eeee19bceeac715793510b",
+ "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "748df03717e997a01a6d222bdb6d6c0b1e206d9be55b74c14c3374a333ad8d55",
+ "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5cbef13c038d0fe822920eabf91c152a7130e50824fd203e3fffff4a44b10bcc",
+ "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "dd0ec4dba66712a10c3ee5e5ef1835210d8632766c17a4afa1ba0594b6fdd35c",
+ "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "30d736ad6f32019435613fec04b4474795c8915e878a528c46de453a25df1bd9",
+ "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.gz": "14c1ba057a56a0c34f129ebae29c6a9453faa03125f1fe88b564355c186d42bb",
+ "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.xz": "67d1c23c910e038c6238d286af0141f0a954799dc12a6b935d47239f4d2e8bd9",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "7685e5b408bf70aa4c8af5ce7b5e5d5a6ac7125c75e7b10a9b3dc0e2dbd4cca1",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a52b846d34cfaeddb57d00d0209b1829fb129049ef61212937c0f19fff5efc91",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a5c2dce3211ec671959abb8b2f7fc34b572e3bd44362c61b98e0850c0530d1bb",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "ba948c4a665c349732de9f8faddc2f7e0f7be5995ad88af44f8f4f5ffd4b9387",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "edf7d1c9c9288cca973a0bc3a90bf005d25df324c592b0b8d051f0de98b85f78",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "0c01b34ed39016866e945e0f01de830a68c54f7eef2ac83c3ab85318b01debb0",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "6ddf6e92653ab0c00ec524e1274be3e644868cfa867933bc383e8e3e7674945f",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "14353a439a306d0803d89a3ce3da5e5c91b9236ed84759fecf8b38ebe1d8a8b1",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "4d7feace1b414919ba2e682c748e24b31d811d7b54d710a7cf70e0b3c9c1a591",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "35593657a752a66f3052752c67c380e7ebace191a0be78c5def2cc3c1fb3a18a",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "04e752df5371b5d3879c8514b7dab27bcb35a7b8c7eaec0ec6e3ec5f51ff84a2",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b0ef02ff310386b80a9b6113a6e44a437ab78b42480b4d0a86e828d97d92a3dc",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "387040cfbb92e6b2acc52067ab2184313de2588a6af65c0af003432bc9e69c75",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "a617e0ee647908038bd1b3f233b99db1a82b0f32875c9093cb66387f3b2bf430",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "5ef7d34a33925b7af081f2e135a0fd20ebb18f711372d432a570f8983243c93b",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "6003e9f8fb4b2a581e359e2e4f1bad83b9055d5a0c60fa0b752ef1aa15957f28",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "838f7773a9aaec82c4323d8412a441eb3db94da8384bc1a4a50969c5beea9aa8",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "403a2141367854a281302f9cdcc2d1b37a2415e8aca4cd5e5308af5fa254601d",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "6a3b69c8352c8262a37ba0104043a66bc579fb033166434a1b9eeaf115d8d1c2",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f272195798b40df211b1d2e817e91bba68a1083026159cab4414ecc88ddb06f3",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "5ec04606fc7196f9a5cd130dc4c98e8df58994278ab50f7ea6baf2cdca957b07",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "a24513ffce8f76fa3334932268aed073958f904b1988d337df7bd4277d3a139b",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "8f078b404db9fabd8b0a45deb5110fab32e2ffe5f604f74ef787d9baf3f857ad",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "3569e3ed42cd9b4dd6f8b2838329c7864c6d3f7a5242cbdbcd9a756e6f2ca5ea",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "afa42b42631320a68d6a99902fd48b1e72d2daeb07a5be34b833f22ba6dcb67a",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "839a8576012332bb2ad01d5b4ab24d46af8644e38b3019b36c0ba5a9417bfd07",
+ "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "aa59c2ebf3bbff46b6c09aa1e7784ebf83dccd6df60e1295935ff3cc954fa755",
+ "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e7f479891368cebb99f41b59508a3904321d600e20cc2507954f78386a448601",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "a971a861cc76d0a2a4c5fecfc4537c8e1c14f4d43013bceeed395722e8620cbd",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5879a7a9af9c6ef6397f75e4b062527fee5006d655fac5b7538915b176d9faa8",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "dc66ac568c709f4b580b46d567bf2d79481566688e0ae55df1edd2a5f07fe0a9",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a2ea4554d52b1181c589eefdf67c60bc0831f2e26430bd6e5e7bb4094db5dfc5",
+ "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8d9ef4755d32e8dc480db1b130943f47b45cc2ba69b1e9fa3dfa128d63780b70",
+ "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "3cac0853da192779f4edc5bc3c913e4b93a02ae98b883cfe2717cc58329d7469",
+ "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "14c5197f4884f418a392bccce9ac3c9a09dcd0a710a337bba5959f5570c41e98",
+ "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f9b14921e3a6bd006479a01579e6601787082ecc0ec8e631b8cea6a4f1c0b967",
+ "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "9f4efc8229a5a8561bea614a3df0da49349dc4118d72905ecd6feb6b6e1eba9f",
+ "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02d829ac6d9013f7268e505aa2b0aa99db7e25ddc3d6555ca8f9a4c5ed3f01e7",
+ "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8192413e5e376bf957a2caffe8ab15b3c235c714f8214a0f3a46711a79fe33c5",
+ "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "be155309daae3cb39dbbc874b2ddaebd1ad303b09f40e130ea8429cc7c9c366f",
+ "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "318c3e8235913f64c9e90b0e7c1fb50229caf59c02f0ddc702cf0728d54dc41c",
+ "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "50bf71e32ae2228142ad88d67e794ab00b632147fb554ebbfcda7ec79304ae2f",
+ "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80f5b76c38d7300c5aa6a71a8b3325b28290b1bb936dd59287fa87d6dee044da",
+ "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "30a71791c6ed0cf3e0fb955fa697549dcd13d2c0f3e357d9723fa729c3a03698",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7e5dc3dc89cb21638b452eb9b5c9f008803ee5845c973f2547f59db01b7a0100",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e1a949b29d249361b306af38bba7118aa1931c14061b6fa7621027e9994b519f",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "ae4186e4faebc9ad8a13f06a97f96c48cbb35353ad649e25f2e80e519a9d272a",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "ca4466d872bb050cabce20ae04eb915ac3e39e4788899db7bec5b51ed7d5b579",
+ "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0f39f27e2ee437df69975578c6e32b6e293bf3129f7e63bde83091330aaa496c",
+ "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "55700dff4b4f3f7d9dfee3317d984afe2b44681deb7b074441b41cfd59e497ed",
+ "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6273db29aa2715ffe38593802c520adafcbb2300ed2595121bff628686eae675",
+ "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a4ce848a1083c16bc17bd22345427ba4c920cb887e90d612a8c3d1ddcf802ed",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "12a715fca796c192514157b43b0296d688cc46e9d81416a67a0019184c1703d4",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9a651e94a0cdddef7c7a56e356e25d0f35d0c592b6a54f2cbeeb3364fc5d457c",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2ea52a8413a43a10165322135064692faee0d03a453c4b28ddea480b153de5c8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "843b06b9b21c56fe1749e8a5bda908dcc2b6d8206faabd04d050ce83f8c32b73",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "69210991cca5a07c0421254a2e18a29de28ab5019b490a576f7bb94496ca10b8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3f5a59ba68e004c06cb07ce83d4a567b77179e11071a8b5b8ab6fe3a70bdb872",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "7225fde4655ed5b4479ff9f4e61237a16280541f44aa751c5a06d5916e8fde3f",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e844e80d99418bea9e7cf96cd389056d17f3be60e9412983d91c64e107a28b92",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "6c1b031bc408349c5d15bf494881dd75aa68df8e7417e6c72c061c7d3270cdf8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "d24b970a15dfd41cb1b0027a4a5822e8c2b0217dd1984503d60a85fc6acf7414",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "5b5aec4bfde07863d2d5bb71f38d3459db0659df75f53567be6fbaacec33c7b3",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "851b9582bd2518a3e050127c46e59f7bb6b24d354c6e89a9b0fe4d3e09cfbbb9",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "758a05277e99d00e21ff9d8abf96a6da71350664a1eb85adbb1ad4cfa1934255",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "6431dabc8ef72ca252b257683fd2f5ce3c1347b18ff1d4b7ee7758c6906ba2af",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "51bdea94714c0892ca7020ddcc7c55bb20ac69eaf5152a38f83925d793b90eb1",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "660a23d1430164b01b3e1e8b50233be07fa0988d90e9880bb9044fe661537cde"
}
}
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
-// min-llvm-version: 12.0
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target armv7-unknown-linux-gnueabihf
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target armv7-unknown-linux-gnueabihf
// compile-flags: -C target-feature=+neon
-// min-llvm-version: 10.0.1
// only-x86_64
// assembly-output: emit-asm
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target hexagon-unknown-linux-musl
// needs-llvm-components: hexagon
-// min-llvm-version: 10.0.1
// revisions: mips32 mips64
// assembly-output: emit-asm
//[mips32] compile-flags: --target mips-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target nvptx64-nvidia-cuda
// compile-flags: --crate-type cdylib
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
// revisions: powerpc powerpc64
// assembly-output: emit-asm
//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// revisions: riscv64 riscv32
// assembly-output: emit-asm
//[riscv64] compile-flags: --target riscv64imac-unknown-none-elf
//[riscv32] compile-flags: --target riscv32imac-unknown-none-elf
//[riscv32] needs-llvm-components: riscv
// compile-flags: -C target-feature=+d
-// min-system-llvm-version: 12.0
#![feature(no_core, lang_items, rustc_attrs)]
#![crate_type = "rlib"]
-// min-llvm-version: 10.0.1
// revisions: s390x
// assembly-output: emit-asm
//[s390x] compile-flags: --target s390x-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target wasm32-unknown-unknown
// compile-flags: --crate-type cdylib
-// min-llvm-version: 10.0.1
// revisions: x86_64 i686
// assembly-output: emit-asm
// compile-flags: -O
-// min-llvm-version: 10.0.1
// revisions: x86_64 i686
// assembly-output: emit-asm
//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
-// min-llvm-version: 12.0.0
// revisions: x64 A64 ppc64le
// assembly-output: emit-asm
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
--- /dev/null
+// compile-flags:-Zprint-mono-items=lazy
+
+// rust-lang/rust#90405
+// Ensure implicit panic calls are collected
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![crate_type = "lib"]
+#![no_core]
+#![no_std]
+
+#[lang = "panic_location"]
+struct Location<'a> {
+ _file: &'a str,
+ _line: u32,
+ _col: u32,
+}
+
+#[lang = "panic"]
+#[inline]
+#[track_caller]
+fn panic(_: &'static str) -> ! {
+ loop {}
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "freeze"]
+trait Freeze {}
+
+impl Copy for i32 {}
+
+#[lang = "div"]
+trait Div<Rhs = Self> {
+ type Output;
+ fn div(self, rhs: Rhs) -> Self::Output;
+}
+
+impl Div for i32 {
+ type Output = i32;
+ fn div(self, rhs: i32) -> i32 {
+ self / rhs
+ }
+}
+
+#[allow(unconditional_panic)]
+pub fn foo() {
+ // This implicitly generates a panic call.
+ let _ = 1 / 0;
+}
+
+//~ MONO_ITEM fn foo
+//~ MONO_ITEM fn <i32 as Div>::div
+//~ MONO_ITEM fn panic
//
// no-system-llvm
-// min-llvm-version: 10.0.1
// compile-flags: -O
#![crate_type="lib"]
-// min-llvm-version: 10.0.1
// revisions: powerpc powerpc64 powerpc64le
//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
//[powerpc] needs-llvm-components: powerpc
-// min-llvm-version: 11.0.0
// compile-flags: -O
// ignore-debug: the debug assertions get in the way
#![crate_type = "lib"]
// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
// CHECK: !DISubrange(count: 3
+// NONMSVC-LABEL: !DIGlobalVariable(name: "<debug_vtable::bar::{closure#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
+// MSVC-LABEL: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"
+
#![crate_type = "lib"]
pub struct Foo;
let z: &dyn SomeTraitWithGenerics<u64, i8> = x;
(y.method1(), z.method1(), x as &dyn Send)
}
+
+// Constructing the debuginfo name for the FnOnce vtable below initially caused an ICE on MSVC
+// because the trait type contains a late bound region that needed to be erased before the type
+// layout for the niche enum `Option<&dyn Fn()>` could be computed.
+pub fn bar() -> Box<dyn FnOnce(Option<&dyn Fn()>)> {
+ Box::new(|_x: Option<&dyn Fn()>| {})
+}
// This test checks an optimization that is not guaranteed to work. This test case should not block
// a future LLVM update.
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// This test checks an optimization that is not guaranteed to work. This test case should not block
// a future LLVM update.
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// compile-flags: -O -C no-prepopulate-passes
-//
-// min-system-llvm-version: 12.0
#![crate_type = "lib"]
#![feature(rustc_attrs)]
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 11.0.0
// compile-flags: -O
// ignore-debug: the debug assertions get in the way
#![crate_type = "lib"]
// This test checks that bounds checks are elided when
// index is part of a (x | y) < C style condition
-// min-llvm-version: 11.0.0
// compile-flags: -O
#![crate_type = "lib"]
// Regression test for #75525, verifies that no bounds checks are generated.
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// ignore-arm
// ignore-aarch64
// ignore-mips
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// ignore-aarch64
// ignore-emscripten
// ignore-mips64
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// only-mips64
// See repr-transparent.rs
--- /dev/null
+// Verifies that "CFI Canonical Jump Tables" module flag is added.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 2, !"CFI Canonical Jump Tables", i32 1}
--- /dev/null
+// Verifies that pointer type membership tests for indirect calls are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+ // CHECK: start:
+ // CHECK-NEXT: %0 = bitcast i32 (i32)* %f to i8*
+ // CHECK-NEXT: %1 = call i1 @llvm.type.test(i8* %0, metadata !"{{[[:print:]]+}}")
+ // CHECK-NEXT: br i1 %1, label %type_test.pass, label %type_test.fail
+ // CHECK: type_test.pass:
+ // CHECK-NEXT: %2 = call i32 %f(i32 %arg)
+ // CHECK-NEXT: br label %bb1
+ // CHECK: type_test.fail:
+ // CHECK-NEXT: call void @llvm.trap()
+ // CHECK-NEXT: unreachable
+ f(arg)
+}
--- /dev/null
+// Verifies that type metadata for functions are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1")
+ f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2")
+ f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3")
+ f(arg1, arg2, arg3)
+}
+
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"}
// compile-flags: -g -Z src-hash-algorithm=sha256
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// ignore-debug: the debug assertions get in the way
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// Ensure that trivial casts of vec elements are O(1)
// only-wasm32
// compile-flags: -C target-feature=-nontrapping-fptoint
-// min-llvm-version: 12.0
#![crate_type = "lib"]
// CHECK-LABEL: @cast_f64_i64
--- /dev/null
+// rustc-env:RUSTC_LOG=debug
+#[cfg(rpass1)]
+pub fn foo() {}
+
+#[cfg(rpass2)]
+pub fn foo() {
+ println!();
+}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck, promoted_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
#[rustc_clean(cfg="cfail6")]
pub fn change_iteration_variable_pattern() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_iterable() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn add_loop_label_to_break() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn add_loop_label_to_continue() {
let mut _x = 0;
--- /dev/null
+// revisions: rpass1 rpass2
+// This test is just checking that we won't ICE if logging is turned
+// on; don't bother trying to compare that (copious) output.
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+// aux-build: rustc-rust-log-aux.rs
+// rustc-env:RUSTC_LOG=debug
+
+#[cfg(rpass1)]
+fn main() {}
+
+#[cfg(rpass2)]
+fn main() {
+ println!();
+}
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11
- let _1: std::ops::GeneratorState<<impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Yield, <impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Return>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
- let mut _2: std::pin::Pin<&mut impl std::ops::Generator<bool>>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
- let mut _3: &mut impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
- let mut _4: impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+ let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
+ let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+ let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
+ let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+ let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46
scope 1 {
debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11
--- /dev/null
+// compile-flags: -Z mir-opt-level=3 -Z inline-mir
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR issue_78442.bar.RevealAll.diff
+// EMIT_MIR issue_78442.bar.Inline.diff
+pub fn bar<P>(
+ // Error won't happen if "bar" is not generic
+ _baz: P,
+) {
+ hide_foo()();
+}
+
+fn hide_foo() -> impl Fn() {
+ // Error won't happen if "iterate" hasn't impl Trait or has generics
+ foo
+}
+
+fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
+}
--- /dev/null
+- // MIR for `bar` before Inline
++ // MIR for `bar` after Inline
+
+ fn bar(_1: P) -> () {
+ debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+ let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++ scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17
++ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- // mir::Constant
+- // + span: $DIR/issue-78442.rs:11:5: 11:15
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17
+ }
+
+ bb2: {
+- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+- _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+ }
+
+- bb3: {
+- return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
++ bb3 (cleanup): {
++ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb4 (cleanup): {
+- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+ }
+
+- bb5 (cleanup): {
+- resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
++ bb5: {
++ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
++ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+ }
+
--- /dev/null
+- // MIR for `bar` before RevealAll
++ // MIR for `bar` after RevealAll
+
+ fn bar(_1: P) -> () {
+ debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+ let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- let mut _3: &impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let _4: impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ nop; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:15
+ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+ drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+ }
+
+ bb4 (cleanup): {
+ drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb5 (cleanup): {
+ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+ }
+ }
+
# needs-profiler-support
-# min-llvm-version: 11.0
-include ../coverage/coverage_tools.mk
# needs-profiler-support
# ignore-windows-gnu
-# min-llvm-version: 11.0
# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
# properly. Since we only have GCC on the CI ignore the test for now.
// are caught by catch_unwind. Also tests that Rust panics can unwind through
// C++ code.
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
#![feature(c_unwind)]
use std::panic::{catch_unwind, AssertUnwindSafe};
use rustc_interface::interface::Compiler;
use rustc_interface::{Config, Queries};
use rustc_middle::ty::query::query_values::mir_borrowck;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use std::cell::RefCell;
}
}
-fn override_queries(_session: &Session, local: &mut Providers, external: &mut Providers) {
+fn override_queries(_session: &Session, local: &mut Providers, _external: &mut ExternProviders) {
local.mir_borrowck = mir_borrowck;
- external.mir_borrowck = mir_borrowck;
}
// Since mir_borrowck does not have access to any other state, we need to use a
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foobar_macro --crate-type dylib --print file-names -)
+
+all:
+ $(RUSTC) src/proc.rs --crate-name foobar_macro --edition=2021 --crate-type proc-macro --emit=dep-info,link
+
+ $(RUSTC) src/lib.rs --crate-name foobar --edition=2021 --crate-type lib --emit=dep-info,link
+
+ $(RUSTDOC) examples/ex.rs --crate-name ex --crate-type bin --output $(OUTPUT_DIR) \
+ --extern foobar=$(TMPDIR)/libfoobar.rlib --extern foobar_macro=$(TMPDIR)/$(DYLIB_NAME) \
+ -Z unstable-options --scrape-examples-output-path $(TMPDIR)/ex.calls --scrape-examples-target-crate foobar
+
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+ -Z unstable-options --with-examples $(TMPDIR)/ex.calls
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
--- /dev/null
+extern crate foobar;
+extern crate foobar_macro;
+
+use foobar::*;
+use foobar_macro::*;
+
+a_proc_macro!(); // no
+
+#[an_attr_macro]
+fn a() {
+ f(); // no
+}
+
+#[an_attr_macro(with_span)]
+fn b() {
+ f(); // yes
+}
+
+fn c() {
+ a_rules_macro!(f()); // yes
+}
+
+fn d() {
+ a_rules_macro!(()); // no
+}
+
+fn main(){}
--- /dev/null
+// Scraped example should only include line numbers for items b and c in ex.rs
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '14'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '15'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '21'
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '22'
+
+pub fn f() {}
+
+#[macro_export]
+macro_rules! a_rules_macro {
+ ($e:expr) => { ($e, foobar::f()); }
+}
--- /dev/null
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn a_proc_macro(_item: TokenStream) -> TokenStream {
+ "fn ex() { foobar::f(); }".parse().unwrap()
+}
+
+// inserts foobar::f() to the end of the function
+#[proc_macro_attribute]
+pub fn an_attr_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let new_call: TokenStream = "foobar::f();".parse().unwrap();
+
+ let mut tokens = item.into_iter();
+
+ let fn_tok = tokens.next().unwrap();
+ let ident_tok = tokens.next().unwrap();
+ let args_tok = tokens.next().unwrap();
+ let body = match tokens.next().unwrap() {
+ TokenTree::Group(g) => {
+ let new_g = Group::new(g.delimiter(), new_call);
+ let mut outer_g = Group::new(
+ g.delimiter(),
+ [TokenTree::Group(g.clone()), TokenTree::Group(new_g)].into_iter().collect(),
+ );
+
+ if attr.to_string() == "with_span" {
+ outer_g.set_span(g.span());
+ }
+
+ TokenTree::Group(outer_g)
+ }
+ _ => unreachable!(),
+ };
+
+ let tokens = vec![fn_tok, ident_tok, args_tok, body].into_iter().collect::<TokenStream>();
+
+ tokens
+}
-include ../tools.mk
-# min-llvm-version: 11.0
-
all: off packed unpacked
ifeq ($(UNAME),Darwin)
-include ../tools.mk
# only-linux
-# min-llvm-version: 11.0
all:
$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
# that it is compiled with the expectation that pthreads is dynamically
# linked as a DLL and will fail to link with a statically linked libpthread.
#
- # So we end up with the following hack: we link use static-nobundle to only
+ # So we end up with the following hack: we link use static:-bundle to only
# link the parts of libstdc++ that we actually use, which doesn't include
# the dependency on the pthreads DLL.
- EXTRARSCXXFLAGS := -l static-nobundle=stdc++
+ EXTRARSCXXFLAGS := -l static:-bundle=stdc++ -Z unstable-options
endif
else
ifeq ($(UNAME),Darwin)
// Tests that linking to C++ code with global destructors works.
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
-
extern "C" {
fn get() -> u32;
}
--- /dev/null
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+pub struct Foo([usize; foobar::f()]);
+fn main() {}
--- /dev/null
+pub const fn f() -> usize { 5 }
--- /dev/null
+deps := ex ex2
+
+-include ./scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::ok();
+ foobar::ok();
+}
--- /dev/null
+fn main() {
+ foobar::ok();
+}
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
+ $(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
+ --extern foobar=$(TMPDIR)/libfoobar.rmeta \
+ -Z unstable-options \
+ --scrape-examples-output-path $@ \
+ --scrape-examples-target-crate foobar
+
+$(TMPDIR)/lib%.rmeta: src/lib.rs
+ $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
+
+scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+ -Z unstable-options \
+ $(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
--- /dev/null
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+// @has src/ex/ex.rs.html
+// @has foobar/fn.ok.html '//a[@href="../src/ex/ex.rs.html#2"]' ''
+
+pub fn ok() {}
--- /dev/null
+deps := ex1 ex2
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::ok(0);
+
+ // this is a
+
+ // ..
+
+ // BIG
+
+ // item
+}
--- /dev/null
+fn main() {
+ foobar::ok(1);
+ // small item
+}
+
+fn f() {
+ foobar::ok(2);
+}
--- /dev/null
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1'
+// @has foobar/fn.ok.html '//*[@class="highlight"]' '2'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0'
+
+pub fn ok(_x: i32) {}
--- /dev/null
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::b::foo();
+ foobar::c::foo();
+}
--- /dev/null
+pub fn foo() {}
--- /dev/null
+// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+
+#[path = "a.rs"]
+pub mod b;
+
+#[path = "a.rs"]
+pub mod c;
--- /dev/null
+// The `impl Foo` heading underneath `Implementations` has a §
+// anchor to its left (used for linking to that heading). The anchor only shows
+// up when hovering the `impl Foo`. This test ensures there's no gap between the
+// anchor and the `impl Foo`. If there were a gap, this would cause an annoying
+// problem: you hover `impl Foo` to see the anchor, then when you move your
+// mouse to the left, the anchor disappears before you reach it.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// We check that ".item-info" is bigger than its content.
+move-cursor-to: ".impl"
+assert-property: (".impl > a.anchor", {"offsetWidth": "9"})
+assert-css: (".impl > a.anchor", {"left": "-8px"})
goto: file://|DOC_PATH|/test_docs/index.html
assert: ("#functions")
goto: ./struct.Foo.html
-assert: ("div.type-decl")
+assert: ("div.item-decl")
--- /dev/null
+// This test ensures that the docblock elements have the appropriate left margin.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+// The top docblock elements shouldn't have left margin...
+assert-css: ("#main .docblock.item-decl", {"margin-left": "0px"})
+// ... but all the others should!
+assert-css: ("#main .docblock:not(.item-decl)", {"margin-left": "24px"})
--- /dev/null
+// Checks that the setting "line numbers" is working as expected.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+
+// We check that without this setting, there is no line number displayed.
+assert-false: "pre.line-number"
+
+// We now set the setting to show the line numbers on code examples.
+local-storage: {"rustdoc-line-numbers": "true" }
+// We reload to make the line numbers appear.
+reload:
+
+// We wait for them to be added into the DOM by the JS...
+wait-for: "pre.line-number"
+// If the test didn't fail, it means that it was found!
+// Let's now check some CSS properties...
+assert-css: ("pre.line-number", {
+ "margin": "0px",
+ "padding": "13px 8px",
+ "text-align": "right"
+})
+// The first code block has two lines so let's check its `<pre>` elements lists both of them.
+assert-text: ("pre.line-number", "1\n2")
goto: file://|DOC_PATH|/lib2/struct.Foo.html
// This test checks that the font weight is correctly applied.
-assert-css: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
assert-css: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"})
// This is a complex selector, so here's how it works:
//
-// * //*[@class='docblock type-decl'] — selects element of any tag with classes docblock and type-decl
+// * //*[@class='docblock item-decl'] — selects element of any tag with classes docblock and item-decl
// * /pre[@class='rust trait'] — selects immediate child with tag pre and classes rust and trait
// * /code — selects immediate child with tag code
// * /a[@class='constant'] — selects immediate child with tag a and class constant
//
// This uses '/parent::*' as a proxy for the style of the text node.
// We can't just select the '<a>' because intermediate tags could be added.
-assert-count: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1)
-assert-css: ("//*[@class='docblock type-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"})
+assert-count: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1)
+assert-css: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"})
assert-count: (".methods .type", 1)
assert-css: (".methods .type", {"font-weight": "600"})
--- /dev/null
+// This test check that headers (a) have the correct heading level, (b) are the right size,
+// and (c) have the correct underlining (or absence of underlining).
+// The sizes may change as design changes, but try to make sure a lower header is never bigger than
+// its parent headers. Also make sure lower headers don't have underlines when their parents lack
+// an underline.
+// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
+// default 16px font size:
+// 24px 1.5em
+// 22.4px 1.4em
+// 20.8px 1.3em
+// 18.4px 1.15em
+// 17.6px 1.1em
+// 16px 1em
+// 15.2px 0.95em
+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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+assert-css: ("h3#title-for-field", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+
+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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#variants", {"font-size": "22.4px"})
+assert-css: ("h2#variants", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#none-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#none-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#none-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#none-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h3#wrapped-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#wrapped-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#wrapped0-prose-title", {"font-size": "16px"})
+assert-css: ("h4#wrapped0-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#structy-prose-title", {"font-size": "16px"})
+assert-css: ("h4#structy-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#structy-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#structy-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+
+assert-text: (".sidebar .others h3", "Modules")
+assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
+
+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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+
+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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
--- /dev/null
+// When JavaScript is disabled, we hide the search bar, because it
+// can't be used without JS.
+javascript: false
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-css: (".sub", {"display": "none"})
// This test checks that the correct font is used on module items (in index.html pages).
goto: file://|DOC_PATH|/test_docs/index.html
-assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, sans-serif'}, ALL)
-assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'}, ALL)
+assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL)
+assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL)
// modules
-assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// structs
-assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// enums
-assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// traits
-assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// functions
-assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// keywords
-assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
--- /dev/null
+// The goal of this test is to ensure that the tooltip `.information` class doesn't
+// have overflow and max-width CSS rules set because they create a bug in firefox on
+// mac. For more information: https://github.com/rust-lang/rust/issues/89185
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".docblock > .information", {
+ "overflow-x": "visible",
+ "max-width": "none"
+}, ALL)
--- /dev/null
+// This test ensures that the reexport of a macro doesn't make the original macro
+// displayed twice in the sidebar.
+goto: file://|DOC_PATH|/test_docs/macro.repro.html
+wait-for: ".sidebar-elems .macro .macro"
+assert-count: ("//*[@class='sidebar-elems']//*[@class='block macro']//a[text()='repro']", 1)
assert-count: (".sidebar .location", 1)
assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
// We check that we have the crates list and that the "current" on is "test_docs".
-assert-text: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
// And we're also supposed to have the list of items in the current module.
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords")
assert-text: ("#structs + .item-table .item-left > a", "Foo")
click: "#structs + .item-table .item-left > a"
assert-false: ".sidebar-elems > .crate"
// We now go back to the crate page to click on the "lib2" crate link.
goto: file://|DOC_PATH|/test_docs/index.html
-click: ".sidebar-elems > .crate > ul > li:first-child > a"
+click: ".sidebar-elems .crate > ul > li:first-child > a"
// PAGE: lib2/index.html
goto: file://|DOC_PATH|/lib2/index.html
assert-text: (".sidebar > .location", "Crate lib2")
// We check that we have the crates list and that the "current" on is now "lib2".
-assert-text: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
// We now go to the "foobar" function page.
assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
goto: ./sub_module/sub_sub_module/index.html
assert-text: (".sidebar > .location", "Module sub_sub_module")
// We check that we don't have the crate list.
-assert-false: ".sidebar-elems > .crate"
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert-false: ".sidebar-elems .crate"
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
assert-text: ("#functions + .item-table .item-left > a", "foo")
/// | content | content |
pub struct Foo;
}
+
+pub mod too_long {
+pub type ReallyLongTypeNameLongLongLong = Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>;
+
+pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0;
+
+pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+ pub a: u32,
+}
+
+impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+ /// ```
+ /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 };
+ /// ```
+ pub fn foo(&self) {}
+ }
+}
///
/// ```
/// println!("nothing fancy");
+/// println!("but with two lines!");
/// ```
///
/// A failing to compile one:
/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
pub mod long_code_block {}
+
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+pub use crate::repro as repro2;
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub struct HeavilyDocumentedStruct {
+ /// # Title for field
+ /// ## Sub-heading for field
+ pub nothing: (),
+}
+
+/// # Title for struct impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for struct impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for struct impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedStruct {
+ /// # Title for struct impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for struct impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for struct impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub enum HeavilyDocumentedEnum {
+ /// # None prose title
+ /// ## None prose sub-heading
+ None,
+ /// # Wrapped prose title
+ /// ## Wrapped prose sub-heading
+ Wrapped(
+ /// # Wrapped.0 prose title
+ /// ## Wrapped.0 prose sub-heading
+ String,
+ String,
+ ),
+ Structy {
+ /// # Structy prose title
+ /// ## Structy prose sub-heading
+ alpha: String,
+ beta: String,
+ },
+}
+
+/// # Title for enum impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for enum impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for enum impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedEnum {
+ /// # Title for enum impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for enum impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for enum impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+pub union HeavilyDocumentedUnion {
+ /// # Title for union variant
+ /// ## Sub-heading for union variant
+ pub nothing: (),
+ pub something: f32,
+}
+
+/// # Title for union impl doc
+/// ## Sub-heading for union impl doc
+impl HeavilyDocumentedUnion {
+ /// # Title for union impl-item doc
+ /// ## Sub-heading for union impl-item doc
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+#[macro_export]
+macro_rules! heavily_documented_macro {
+ () => {};
+}
-// This test ensures that the type declaration content overflow is handled inside the <pre> directly.
+// This test ensures that the items declaration content overflow is handled inside the <pre> directly.
goto: file://|DOC_PATH|/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html
// We set a fixed size so there is no chance of "random" resize.
size: (1100, 800)
// Logically, the <body> scroll width should be the width of the window.
assert-property: ("body", {"scrollWidth": "1100"})
// However, since there is overflow in the type declaration, its scroll width is bigger.
-assert-property: (".type-decl pre", {"scrollWidth": "1324"})
+assert-property: (".item-decl pre", {"scrollWidth": "1324"})
+
+// We now make the same check on type declaration...
+goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
+assert-property: ("body", {"scrollWidth": "1100"})
+// We now check that the section width hasn't grown because of it.
+assert-property: ("#main", {"scrollWidth": "840"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "1103"})
+
+// ... and constant.
+// On a sidenote, it also checks that the (very) long title isn't changing the docblock width.
+goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html
+assert-property: ("body", {"scrollWidth": "1100"})
+// We now check that the section width hasn't grown because of it.
+assert-property: ("#main", {"scrollWidth": "840"})
+// And now checking that it has scrollable content.
+assert-property: (".item-decl pre", {"scrollWidth": "950"})
// exact-check
const QUERY = [
- '"R<P>"',
- '"P"',
- 'P',
- '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ '"R<P>"',
+ '"P"',
+ 'P',
+ '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ 'TraitCat',
+ 'TraitDog',
];
const EXPECTED = [
{
'returned': [
{ 'path': 'generics', 'name': 'alef' },
+ { 'path': 'generics', 'name': 'bet' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
+ { 'path': 'generics', 'name': 'beta' },
],
},
{
],
'returned': [],
},
+ {
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
+ {
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
];
pub fn redherringmatchforextracredit(
_param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>
) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
--- /dev/null
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @count macro.json "$.index[*][?(@.name=='macro')].inner.items[*]" 2
+
+// @set repro_id = macro.json "$.index[*][?(@.name=='repro')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro_id
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+// @set repro2_id = macro.json "$.index[*][?(@.inner.name=='repro2')].id"
+// @has - "$.index[*][?(@.name=='macro')].inner.items[*]" $repro2_id
+pub use crate::repro as repro2;
pub const AssocConst: Self::AssocTy = 42;
//~^ ERROR ambiguous associated type
//~| HELP use fully-qualified syntax
- // FIXME: for some reason, the error is shown twice with rustdoc but only once with rustc
//~| ERROR ambiguous associated type
//~| HELP use fully-qualified syntax
}
//~^ ERROR missing code example in this documentation
pub fn bar() {}
}
+
+// This impl is here to ensure the lint isn't emitted for foreign traits implementations.
+impl std::ops::Neg for Foo {
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ Self
+ }
+}
LL | | /// Some docs.
LL | |
... |
-LL | | pub fn bar() {}
+LL | | }
LL | | }
| |_^
|
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:15:12
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: aborting due to 6 previous errors
--- /dev/null
+// check-pass
+
+// ICE found in https://github.com/rust-lang/rust/issues/83123
+
+pub struct Attribute;
+
+pub struct Map<'hir> {}
+impl<'hir> Map<'hir> {
+ pub fn attrs(&self) -> &'hir [Attribute] { &[] }
+}
+
+pub struct List<T>(T);
+
+impl<T> std::ops::Deref for List<T> {
+ type Target = [T];
+ fn deref(&self) -> &[T] {
+ &[]
+ }
+}
--- /dev/null
+// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar
--- /dev/null
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
--- /dev/null
+// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls
--- /dev/null
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
#[export_name = "bar"]
pub extern "C" fn g() {}
-// @has foo/struct.Repr.html '//*[@class="docblock type-decl"]' '#[repr(C, align(8))]'
+// @has foo/struct.Repr.html '//*[@class="docblock item-decl"]' '#[repr(C, align(8))]'
#[repr(C, align(8))]
pub struct Repr;
--- /dev/null
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels and across multiple crates.
+// For `Deref` on non-foreign types, look at `deref-recursive.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
+// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+use std::path::PathBuf;
+
+pub struct Foo(PathBuf);
+
+impl Deref for Foo {
+ type Target = PathBuf;
+ fn deref(&self) -> &PathBuf { &self.0 }
+}
--- /dev/null
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels if needed.
+// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
+// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+
+pub struct Foo(Bar);
+pub struct Bar(Baz);
+pub struct Baz;
+
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar { &self.0 }
+}
+
+impl Deref for Bar {
+ type Target = Baz;
+ fn deref(&self) -> &Baz { &self.0 }
+}
+
+impl Bar {
+ /// This appears under `Foo` methods
+ pub fn bar(&self) {}
+}
+
+impl Baz {
+ /// This should also appear in `Foo` methods when recursing
+ pub fn baz(&self) {}
+}
#![crate_name = "foo"]
// @has 'foo/struct.Bar.html'
-// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
--- /dev/null
+#![feature(doc_auto_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
+#[cfg(not(test))]
+pub fn foo() {}
#![crate_name = "oud"]
-#![feature(doc_cfg, doc_cfg_hide)]
+#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)]
#![doc(cfg_hide(feature = "solecism"))]
#![crate_name = "funambulism"]
-#![feature(doc_cfg)]
+#![feature(doc_auto_cfg, doc_cfg)]
// @has 'funambulism/struct.Disorbed.html'
// @count - '//*[@class="stab portability"]' 1
--- /dev/null
+#![feature(doc_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0
+#[cfg(not(test))]
+pub fn foo() {}
--- /dev/null
+// edition:2018
+
+#![no_core]
+#![feature(no_core)]
+
+// @matches 'issue_89852/sidebar-items.js' '"repro"'
+// @!matches 'issue_89852/sidebar-items.js' '"repro".*"repro"'
+
+#[macro_export]
+macro_rules! repro {
+ () => {};
+}
+
+pub use crate::repro as repro2;
fn deref(&self) -> &B { todo!() }
}
-// @!has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
+// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
impl Deref for B {
type Target = C;
fn deref(&self) -> &C { todo!() }
use std::ops::Deref;
+// Cyclic deref with the parent (which is not the top parent).
pub struct A;
pub struct B;
+pub struct C;
+
+impl C {
+ pub fn c(&self) {}
+}
// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
impl Deref for A {
type Target = B;
}
// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
impl Deref for B {
- type Target = A;
+ type Target = C;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
+impl Deref for C {
+ type Target = B;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with the grand-parent (which is not the top parent).
+pub struct D;
+pub struct E;
+pub struct F;
+pub struct G;
+
+impl G {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn g() {}
+}
+
+// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for D {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for E {
+ type Target = F;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for F {
+ type Target = G;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
+impl Deref for G {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with top parent.
+pub struct H;
+pub struct I;
+
+impl I {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn i() {}
+}
+
+// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
+// @!has '-' '//*[@id="deref-methods-I"]'
+impl Deref for H {
+ type Target = I;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
+impl Deref for I {
+ type Target = H;
fn deref(&self) -> &Self::Target {
panic!()
extern crate reexports;
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock type-decl"]' 'pub macro addr_of($place : expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
pub use reexports::addr_of;
-// @has 'foo/macro.addr_of_crate.html' '//*[@class="docblock type-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
+// @has 'foo/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
pub(crate) use reexports::addr_of_crate;
-// @has 'foo/macro.addr_of_self.html' '//*[@class="docblock type-decl"]' 'pub(crate) macro addr_of_self($place : expr) {'
+// @has 'foo/macro.addr_of_self.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_self($place : expr) {'
pub(self) use reexports::addr_of_self;
-// @has 'foo/struct.Foo.html' '//*[@class="docblock type-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
-// @has 'foo/struct.FooCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) struct FooCrate;'
+// @has 'foo/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;'
pub(crate) use reexports::FooCrate;
-// @has 'foo/struct.FooSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) struct FooSelf;'
+// @has 'foo/struct.FooSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooSelf;'
pub(self) use reexports::FooSelf;
-// @has 'foo/enum.Bar.html' '//*[@class="docblock type-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
-// @has 'foo/enum.BarCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) enum BarCrate {'
+// @has 'foo/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {'
pub(crate) use reexports::BarCrate;
-// @has 'foo/enum.BarSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) enum BarSelf {'
+// @has 'foo/enum.BarSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarSelf {'
pub(self) use reexports::BarSelf;
// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
// @has 'foo/type.TypeSelf.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeSelf ='
pub(self) use reexports::TypeSelf;
-// @has 'foo/union.Union.html' '//*[@class="docblock type-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
pub use reexports::Union;
-// @has 'foo/union.UnionCrate.html' '//*[@class="docblock type-decl"]' 'pub(crate) union UnionCrate {'
+// @has 'foo/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {'
pub(crate) use reexports::UnionCrate;
-// @has 'foo/union.UnionSelf.html' '//*[@class="docblock type-decl"]' 'pub(crate) union UnionSelf {'
+// @has 'foo/union.UnionSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionSelf {'
pub(self) use reexports::UnionSelf;
pub mod foo {
extern crate reexports;
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock type-decl"]' 'pub macro addr_of($place : expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
pub use reexports::addr_of;
// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
// @!has 'foo/macro.addr_of_self.html'
pub(self) use reexports::addr_of_self;
-// @has 'foo/struct.Foo.html' '//*[@class="docblock type-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
// @!has 'foo/struct.FooCrate.html'
pub(crate) use reexports::FooCrate;
// @!has 'foo/struct.FooSelf.html'
pub(self) use reexports::FooSelf;
-// @has 'foo/enum.Bar.html' '//*[@class="docblock type-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
// @!has 'foo/enum.BarCrate.html'
pub(crate) use reexports::BarCrate;
// @!has 'foo/type.TypeSelf.html'
pub(self) use reexports::TypeSelf;
-// @has 'foo/union.Union.html' '//*[@class="docblock type-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
pub use reexports::Union;
// @!has 'foo/union.UnionCrate.html'
pub(crate) use reexports::UnionCrate;
// @has 'toggle_item_contents/struct.PrivStruct.html'
// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
+// @has - '//div[@class="docblock item-decl"]' 'fields omitted'
pub struct PrivStruct {
a: usize,
b: usize,
// @has foo/index.html '//a[@class="traitalias"]' 'Alias2'
// @has foo/index.html '//a[@class="traitalias"]' 'Foo'
-// @has foo/traitalias.CopyAlias.html '//section[@id="main"]/pre' 'trait CopyAlias = Copy;'
+// @has foo/traitalias.CopyAlias.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;'
pub trait CopyAlias = Copy;
-// @has foo/traitalias.Alias2.html '//section[@id="main"]/pre' 'trait Alias2 = Copy + Debug;'
+// @has foo/traitalias.Alias2.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
pub trait Alias2 = Copy + Debug;
-// @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
+// @has foo/traitalias.Foo.html
+// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;
// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
pub fn bar<T>() where T: Alias2 {}
LL | extern "x86-interrupt" fn x86() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 7 previous errors; 2 warnings emitted
+error: aborting due to 8 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
LL | extern "x86-interrupt" fn x86() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
extern "x86-interrupt" fn x86() {}
//[aarch64]~^ ERROR is not a supported ABI
//[arm]~^^ ERROR is not a supported ABI
-extern "stdcall" fn stdcall() {}
-//[x64]~^ WARN use of calling convention not supported
-//[x64]~^^ WARN this was previously accepted
-//[aarch64]~^^^ WARN use of calling convention not supported
-//[aarch64]~^^^^ WARN this was previously accepted
-//[arm]~^^^^^ WARN use of calling convention not supported
-//[arm]~^^^^^^ WARN this was previously accepted
extern "thiscall" fn thiscall() {}
+//[x64]~^ ERROR is not a supported ABI
+//[aarch64]~^^ ERROR is not a supported ABI
+//[arm]~^^^ ERROR is not a supported ABI
+extern "stdcall" fn stdcall() {}
//[x64]~^ WARN use of calling convention not supported
//[x64]~^^ WARN this was previously accepted
//[aarch64]~^^^ WARN use of calling convention not supported
LL | extern "avr-interrupt" fn avr() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
-// min-llvm-version: 10.0.1
// only-aarch64
// run-pass
// revisions: mirunsafeck thirunsafeck
-// min-llvm-version: 10.0.1
// only-aarch64
// build-fail
// compile-flags: -Ccodegen-units=1
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:11:15
+ --> $DIR/srcloc.rs:10:15
|
LL | asm!("invalid_instruction");
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:15:13
+ --> $DIR/srcloc.rs:14:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:20:13
+ --> $DIR/srcloc.rs:19:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:26:13
+ --> $DIR/srcloc.rs:25:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:33:13
+ --> $DIR/srcloc.rs:32:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:38:14
+ --> $DIR/srcloc.rs:37:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:42:14
+ --> $DIR/srcloc.rs:41:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:48:14
+ --> $DIR/srcloc.rs:47:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:55:14
+ --> $DIR/srcloc.rs:54:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:62:13
+ --> $DIR/srcloc.rs:61:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:69:13
+ --> $DIR/srcloc.rs:68:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:76:14
+ --> $DIR/srcloc.rs:75:14
|
LL | "invalid_instruction1",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:77:14
+ --> $DIR/srcloc.rs:76:14
|
LL | "invalid_instruction2",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:83:13
+ --> $DIR/srcloc.rs:82:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:83:13
+ --> $DIR/srcloc.rs:82:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:92:13
+ --> $DIR/srcloc.rs:91:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:92:13
+ --> $DIR/srcloc.rs:91:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:96:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:96:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:107:13
+ --> $DIR/srcloc.rs:106:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:107:13
+ --> $DIR/srcloc.rs:106:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:111:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:111:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
-// min-llvm-version: 10.0.1
// only-aarch64
// only-linux
// run-pass
-// min-llvm-version: 10.0.1
// only-x86_64
// run-pass
// revisions: mirunsafeck thirunsafeck
--- /dev/null
+// build-pass
+// only-x86_64
+
+#![feature(asm, target_feature_11)]
+
+#[target_feature(enable = "avx")]
+fn main() {
+ unsafe {
+ asm!(
+ "/* {} */",
+ out(ymm_reg) _,
+ );
+ }
+}
-// min-llvm-version: 10.0.1
// only-x86_64
// build-fail
// compile-flags: -Ccodegen-units=1
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:11:15
+ --> $DIR/srcloc.rs:10:15
|
LL | asm!("invalid_instruction");
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:15:13
+ --> $DIR/srcloc.rs:14:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:20:13
+ --> $DIR/srcloc.rs:19:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:26:13
+ --> $DIR/srcloc.rs:25:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:33:13
+ --> $DIR/srcloc.rs:32:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:38:14
+ --> $DIR/srcloc.rs:37:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
| ^^^^^^^^^^^^^^^^^^^
warning: scale factor without index register is ignored
- --> $DIR/srcloc.rs:41:15
+ --> $DIR/srcloc.rs:40:15
|
LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
| ^
| ^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:45:14
+ --> $DIR/srcloc.rs:44:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:51:14
+ --> $DIR/srcloc.rs:50:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:58:14
+ --> $DIR/srcloc.rs:57:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:65:13
+ --> $DIR/srcloc.rs:64:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:72:13
+ --> $DIR/srcloc.rs:71:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:79:14
+ --> $DIR/srcloc.rs:78:14
|
LL | "invalid_instruction1",
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:80:14
+ --> $DIR/srcloc.rs:79:14
|
LL | "invalid_instruction2",
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:86:13
+ --> $DIR/srcloc.rs:85:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:86:13
+ --> $DIR/srcloc.rs:85:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:94:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:94:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:99:13
+ --> $DIR/srcloc.rs:98:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:99:13
+ --> $DIR/srcloc.rs:98:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:109:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:109:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:114:13
+ --> $DIR/srcloc.rs:113:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:114:13
+ --> $DIR/srcloc.rs:113:13
|
LL | concat!(
| ^
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
// only-x86_64
// only-linux
// run-pass
pub fn f1_uint_uint() {
f1(2u32, 4u32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f1_uint_int() {
f1(2u32, 4i32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f2_int() {
| ~~~
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:29:14
+ --> $DIR/associated-types-path-2.rs:29:5
|
LL | f1(2u32, 4u32);
- | -- ^^^^ the trait `Foo` is not implemented for `u32`
- | |
- | required by a bound introduced by this call
+ | ^^ the trait `Foo` is not implemented for `u32`
|
note: required by a bound in `f1`
--> $DIR/associated-types-path-2.rs:13:14
| ^^^ required by this bound in `f1`
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:34:14
+ --> $DIR/associated-types-path-2.rs:29:14
+ |
+LL | f1(2u32, 4u32);
+ | ^^^^ the trait `Foo` is not implemented for `u32`
+
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+ --> $DIR/associated-types-path-2.rs:35:8
|
LL | f1(2u32, 4i32);
- | -- ^^^^ the trait `Foo` is not implemented for `u32`
+ | -- ^^^^ the trait `Foo` is not implemented for `u32`
| |
| required by a bound introduced by this call
|
LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
| ^^^ required by this bound in `f1`
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+ --> $DIR/associated-types-path-2.rs:35:14
+ |
+LL | f1(2u32, 4i32);
+ | ^^^^ the trait `Foo` is not implemented for `u32`
+
error[E0308]: mismatched types
- --> $DIR/associated-types-path-2.rs:39:18
+ --> $DIR/associated-types-path-2.rs:41:18
|
LL | let _: i32 = f2(2i32);
| --- ^^^^^^^^ expected `i32`, found `u32`
LL | let _: i32 = f2(2i32).try_into().unwrap();
| ++++++++++++++++++++
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:49:5
+ --> $DIR/async-fn-nonsend.rs:49:17
|
LL | assert_send(local_dropped_before_await());
- | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
| ^^^^ required by this bound in `assert_send`
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:51:5
+ --> $DIR/async-fn-nonsend.rs:51:17
|
LL | assert_send(non_send_temporary_in_match());
- | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
| ^^^^ required by this bound in `assert_send`
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:53:5
+ --> $DIR/async-fn-nonsend.rs:53:17
|
LL | assert_send(non_sync_with_method_call());
- | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
= help: the trait `Send` is not implemented for `dyn std::fmt::Write`
note: future is not `Send` as this value is used across an await
error: future cannot be shared between threads safely
- --> $DIR/issue-64130-1-sync.rs:21:5
+ --> $DIR/issue-64130-1-sync.rs:21:13
|
LL | is_sync(bar());
- | ^^^^^^^ future returned by `bar` is not `Sync`
+ | ^^^^^ future returned by `bar` is not `Sync`
|
= help: within `impl Future`, the trait `Sync` is not implemented for `Foo`
note: future is not `Sync` as this value is used across an await
error: future cannot be sent between threads safely
- --> $DIR/issue-64130-2-send.rs:21:5
+ --> $DIR/issue-64130-2-send.rs:21:13
|
LL | is_send(bar());
- | ^^^^^^^ future returned by `bar` is not `Send`
+ | ^^^^^ future returned by `bar` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Foo`
note: future is not `Send` as this value is used across an await
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future`
- --> $DIR/issue-64130-3-other.rs:24:5
+ --> $DIR/issue-64130-3-other.rs:24:12
|
LL | async fn bar() {
| - within this `impl Future`
...
LL | is_qux(bar());
- | ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
+ | ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
|
note: future does not implement `Qux` as this value is used across an await
--> $DIR/issue-64130-3-other.rs:18:5
// edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
// This tests the basic example case for the async-await-specific error.
error: future cannot be sent between threads safely
- --> $DIR/issue-64130-non-send-future-diags.rs:21:5
+ --> $DIR/issue-64130-non-send-future-diags.rs:23:13
|
LL | is_send(foo());
- | ^^^^^^^ future returned by `foo` is not `Send`
+ | ^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+ --> $DIR/issue-64130-non-send-future-diags.rs:17:5
|
LL | let g = x.lock().unwrap();
| - has type `MutexGuard<'_, u32>` which is not `Send`
LL | }
| - `g` is later dropped here
note: required by a bound in `is_send`
- --> $DIR/issue-64130-non-send-future-diags.rs:7:15
+ --> $DIR/issue-64130-non-send-future-diags.rs:9:15
|
LL | fn is_send<T: Send>(t: T) { }
| ^^^^ required by this bound in `is_send`
// edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
use std::future::Future;
use std::sync::Mutex;
error: future cannot be sent between threads safely
- --> $DIR/issue-71137.rs:20:3
+ --> $DIR/issue-71137.rs:22:14
|
LL | fake_spawn(wrong_mutex());
- | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
+ | ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-71137.rs:12:5
+ --> $DIR/issue-71137.rs:14:5
|
LL | let mut guard = m.lock().unwrap();
| --------- has type `MutexGuard<'_, i32>` which is not `Send`
LL | }
| - `mut guard` is later dropped here
note: required by a bound in `fake_spawn`
- --> $DIR/issue-71137.rs:6:27
+ --> $DIR/issue-71137.rs:8:27
|
LL | fn fake_spawn<F: Future + Send + 'static>(f: F) { }
| ^^^^ required by this bound in `fake_spawn`
fn main() {
g(issue_67893::run())
- //~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely
+ //~^ ERROR generator cannot be sent between threads safely
}
-error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
- --> $DIR/issue-67893.rs:9:5
+error: generator cannot be sent between threads safely
+ --> $DIR/issue-67893.rs:9:7
|
LL | g(issue_67893::run())
- | ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
- |
- ::: $DIR/auxiliary/issue_67893.rs:7:20
- |
-LL | pub async fn run() {
- | - within this `impl Future`
+ | ^^^^^^^^^^^^^^^^^^ generator is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
- = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
- = note: required because it appears within the type `[static generator@run::{closure#0}]`
- = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
- = note: required because it appears within the type `impl Future`
- = note: required because it appears within the type `impl Future`
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
error: lifetime may not live long enough
- --> $DIR/ret-impl-trait-one.rs:10:65
+ --> $DIR/ret-impl-trait-one.rs:10:85
+ |
+LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ | ________________________________--__--_______________________________________________^
+ | | | |
+ | | | lifetime `'b` defined here
+ | | lifetime `'a` defined here
+LL | |
+LL | | (a, b)
+LL | | }
+ | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/ret-impl-trait-one.rs:16:65
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- | -- -- ^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
- | | |
- | | lifetime `'b` defined here
- | lifetime `'a` defined here
+ | -- ^^^^^^^^^^^^^^
+ | |
+ | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+ |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
- = help: consider adding the following bound: `'b: 'a`
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ | ++++
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0700`.
trait Trait<'a> { }
impl<T> Trait<'_> for T { }
+// Fails to recognize that both 'a and 'b are mentioned and should thus be accepted
+async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ //~^ ERROR lifetime mismatch
+ (a, b)
+}
+
// Only `'a` permitted in return type, not `'b`.
async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- //~^ ERROR lifetime mismatch
+ //~^ ERROR captures lifetime that does not appear in bounds
(a, b)
}
error[E0623]: lifetime mismatch
--> $DIR/ret-impl-trait-one.rs:10:65
|
+LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ | ------ ^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | ...but data from `a` is held across an await point here
+ | | this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a> + 'b>`
+ | this parameter and the returned future are declared with different lifetimes...
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/ret-impl-trait-one.rs:16:65
+ |
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
- | ------ ^^^^^^^^^^^^^^
- | | |
- | | ...but data from `b` is held across an await point here
- | | this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a>>`
- | this parameter and the returned future are declared with different lifetimes...
+ | -- ^^^^^^^^^^^^^^
+ | |
+ | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
+ |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+ |
+LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
+ | ++++
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0623`.
+Some errors have detailed explanations: E0623, E0700.
+For more information about an error, try `rustc --explain E0623`.
error[E0277]: `PhantomPinned` cannot be unpinned
- --> $DIR/pin-needed-to-poll-2.rs:43:9
+ --> $DIR/pin-needed-to-poll-2.rs:43:18
|
LL | Pin::new(&mut self.sleep).poll(cx)
- | ^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+ | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+ | |
+ | required by a bound introduced by this call
|
= note: consider using `Box::pin`
note: required because it appears within the type `Sleep`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:15:12
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: aborting due to 6 previous errors
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
--> $DIR/ambiguity-item.rs:14:13
|
LL | let v = f;
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
--> $DIR/ambiguity-item.rs:16:9
|
LL | f => {}
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
--- /dev/null
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+ struct Foo(u32);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("dropped {}", self.0);
+ }
+ }
+
+ let f0 = Foo(0);
+ let f1 = Foo(1);
+
+ let c0 = move || {
+ let _ = &f0;
+ //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+ //~| NOTE for more information
+ let _ = f0;
+ //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+ };
+
+ let c1 = move || {
+ let _ = &f1;
+ };
+
+ println!("dropping 0");
+ drop(c0);
+ println!("dropping 1");
+ drop(c1);
+ println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
--- /dev/null
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+ struct Foo(u32);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("dropped {}", self.0);
+ }
+ }
+
+ let f0 = Foo(0);
+ let f1 = Foo(1);
+
+ let c0 = move || {
+ //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+ //~| NOTE for more information
+ let _ = f0;
+ //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+ };
+
+ let c1 = move || {
+ let _ = &f1;
+ };
+
+ println!("dropping 0");
+ drop(c0);
+ println!("dropping 1");
+ drop(c1);
+ println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
--- /dev/null
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/issue-90465.rs:17:14
+ |
+LL | let c0 = move || {
+ | ^^^^^^^
+...
+LL | let _ = f0;
+ | -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+...
+LL | }
+ | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
+ |
+note: the lint level is defined here
+ --> $DIR/issue-90465.rs:3:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f0` to be fully captured
+ |
+LL ~ let c0 = move || {
+LL + let _ = &f0;
+ |
+
+error: aborting due to previous error
+
let mut f = 10;
let fptr = SendPointer(&mut f as *mut i32);
thread::spawn(move || { let _ = &fptr; unsafe {
- //~^ ERROR: `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0 = 20;
let f = CustomInt(&mut f as *mut i32);
let fptr = SyncPointer(f);
thread::spawn(move || { let _ = &fptr; unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0.0 = 20;
let f = U(S(Foo(0)), T(0));
let c = || {
let _ = &f;
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
let f_1 = f.1;
let mut f = 10;
let fptr = SendPointer(&mut f as *mut i32);
thread::spawn(move || unsafe {
- //~^ ERROR: `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0 = 20;
let f = CustomInt(&mut f as *mut i32);
let fptr = SyncPointer(f);
thread::spawn(move || unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0.0 = 20;
fn test_clone_trait() {
let f = U(S(Foo(0)), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
let f_1 = f.1;
-error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/auto_traits.rs:22:19
|
LL | thread::spawn(move || unsafe {
- | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
...
LL | *fptr.0 = 20;
| ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
LL | *fptr.0 = 20;
...
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/auto_traits.rs:42:19
|
LL | thread::spawn(move || unsafe {
- | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ | ^^^^^^^^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync`
+ | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send`
...
LL | *fptr.0.0 = 20;
| --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
LL |
LL |
LL |
-LL | *fptr.0.0 = 20;
+LL |
...
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/auto_traits.rs:66:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/auto_traits.rs:67:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone`
...
LL | let f_1 = f.1;
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
--- /dev/null
+// Test that rustc doesn't ICE as in #90024.
+// check-pass
+// edition=2018
+
+#![warn(rust_2021_incompatible_closure_captures)]
+
+// Checks there's no double-subst into the generic args, otherwise we get OOB
+// MCVE by @lqd
+pub struct Graph<N, E, Ix> {
+ _edges: E,
+ _nodes: N,
+ _ix: Vec<Ix>,
+}
+fn graph<N, E>() -> Graph<N, E, i32> {
+ todo!()
+}
+fn first_ice() {
+ let g = graph::<i32, i32>();
+ let _ = || g;
+}
+
+// Checks that there is a subst into the fields, otherwise we get normalization error
+// MCVE by @cuviper
+use std::iter::Empty;
+struct Foo<I: Iterator> {
+ data: Vec<I::Item>,
+}
+pub fn second_ice() {
+ let v = Foo::<Empty<()>> { data: vec![] };
+
+ (|| v.data[0])();
+}
+
+pub fn main() {
+ first_ice();
+ second_ice();
+}
let f = panic::AssertUnwindSafe(f);
let result = panic::catch_unwind(move || {
let _ = &f;
- //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
f.0()
{
let f = panic::AssertUnwindSafe(f);
let result = panic::catch_unwind(move || {
- //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
f.0()
-error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/mir_calls_to_shims.rs:20:38
|
LL | let result = panic::catch_unwind(move || {
- | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ | ^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe`
+ | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe`
...
LL | f.0()
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
}
}
-
struct S(Foo);
#[derive(Clone)]
let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
let _ = (&f1, &f2);
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
let _f_1 = f1.0;
let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_1 = f1.0;
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let mut f2 = 10;
let fptr2 = SendPointer(&mut f2 as *mut i32);
thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
*fptr1.0.0 = 20;
}
}
-
struct S(Foo);
#[derive(Clone)]
let f1 = U(S(Foo::from("foo")), T(0));
let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
let _f_1 = f1.0;
fn test_capturing_all_disjoint_fields_individually() {
let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_1 = f1.0;
fn test_capturing_several_disjoint_fields_individually_1() {
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
fn test_capturing_several_disjoint_fields_individually_2() {
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let mut f2 = 10;
let fptr2 = SendPointer(&mut f2 as *mut i32);
thread::spawn(move || unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
*fptr1.0.0 = 20;
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:38:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:37:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_1 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = (&f1, &f2);
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:57:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:56:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_1 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:82:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:81:13
|
LL | let c = || {
| ^^
| |
- | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone`
...
LL | let _f_0 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:101:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:100:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_0 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:134:19
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:133:19
|
LL | thread::spawn(move || unsafe {
| ^^^^^^^^^^^^^^
| |
- | in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync`
+ | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send`
...
LL | *fptr1.0.0 = 20;
| ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
| expected due to this
|
= note: expected unit type `()`
- found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]`
+ found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected unit type `()`
- found closure `[f<T>::{closure#0} closure_substs=(unavailable)]`
+ found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected fn pointer `fn(u8) -> u8`
- found closure `[main::{closure#0} closure_substs=(unavailable)]`
+ found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> $DIR/closure-print-verbose.rs:10:39
|
// build-fail
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
// needs-llvm-components: arm
-// min-llvm-version: 11.0
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
#![no_core]
#[lang="sized"]
// build-fail
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
// needs-llvm-components: arm
-// min-llvm-version: 11.0
#![feature(cmse_nonsecure_entry, no_core, lang_items)]
#![no_core]
#[lang="sized"]
--- /dev/null
+#![crate_type = "lib"]
+#![feature(negative_impls)]
+
+pub trait Error {}
+impl !Error for &str {}
--- /dev/null
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
+// FIXME this should work, we should implement an `assemble_neg_candidates` fn
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `C` for type `u32`
+ --> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
+ |
+LL | impl<T: AB> C for T {}
+ | ------------------- first implementation here
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+ | ^^^^^^^^^^^^^^ conflicting implementation for `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+//~^ ERROR: conflicting implementations of trait `Foo` for type `&_` [E0119]
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `Foo` for type `&_`
+ --> $DIR/coherence-overlap-negate-not-use-feature-gate.rs:5:1
+ |
+LL | impl<T: DerefMut> Foo for T {}
+ | --------------------------- first implementation here
+LL | impl<U> Foo for &U {}
+ | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: A + B> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(negative_impls)]
+
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+
+fn main() {}
--- /dev/null
+// check-pass
+// aux-build:error_lib.rs
+//
+// Check that if we promise to not impl what would overlap it doesn't actually overlap
+
+#![feature(negative_impls)]
+
+extern crate error_lib as lib;
+use lib::Error;
+
+trait From<T> {}
+
+impl From<&str> for Box<dyn Error> {}
+impl<E> From<E> for Box<dyn Error> where E: Error {}
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl A for u32 {}
+impl B for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR
+// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc
+// attribute and an artificial code path for testing purposes
+
+fn main() {}
--- /dev/null
+error[E0283]: type annotations needed
+ --> $DIR/coherence-overlap-trait-alias.rs:15:6
+ |
+LL | impl C for u32 {}
+ | ^ cannot infer type for type `u32`
+ |
+note: multiple `impl`s satisfying `u32: C` found
+ --> $DIR/coherence-overlap-trait-alias.rs:13:1
+ |
+LL | impl<T: AB> C for T {}
+ | ^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+ | ^^^^^^^^^^^^^^
+note: required by a bound in `C`
+ --> $DIR/coherence-overlap-trait-alias.rs:11:1
+ |
+LL | trait C {}
+ | ^^^^^^^ required by this bound in `C`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
--- /dev/null
+// Regression test for issue #89358.
+
+// compile-flags: --cfg a"
+// error-pattern: unterminated double quote string
+// error-pattern: this error occurred on the command line
--- /dev/null
+error[E0765]: unterminated double quote string
+ |
+ = note: this error occurred on the command line: `--cfg=a"`
+
#![feature(staged_api)]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
-// FIXME(const_generics): It seems like we aren't testing the right thing here,
+// FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
// I would assume that we want the attributes to apply to the const parameter defaults
// themselves.
#![stable(feature = "const_default_test", since="none")]
--- /dev/null
+#![feature(const_generics_defaults)]
+
+// test that defaulted const params are not used to help type inference
+
+struct Foo<const N: u32 = 2>;
+
+impl<const N: u32> Foo<N> {
+ fn foo() -> Self { loop {} }
+}
+
+fn main() {
+ let foo = Foo::<1>::foo();
+ let foo = Foo::foo();
+ //~^ error: type annotations needed for `Foo<{_: u32}>`
+}
--- /dev/null
+error[E0282]: type annotations needed for `Foo<{_: u32}>`
+ --> $DIR/doesnt_infer.rs:13:15
+ |
+LL | let foo = Foo::foo();
+ | --- ^^^^^^^^ cannot infer the value of const parameter `N`
+ | |
+ | consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// run-pass
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr<const N: u32>() -> impl Trait {
+ Uwu::<N>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N> for u32 {}
+impl Traitor<1, 1> for u64 {}
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+ 1_u32
+}
+
+fn owo() -> impl Traitor {
+ 1_u64
+}
+
+fn main() {
+ rawr::<3>();
+ rawr::<7>();
+ uwu::<{ u8::MAX }>();
+ owo();
+}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr() -> impl Trait {
+ //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+ Uwu::<10, 12>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N, 2> for u32 {}
+impl Traitor<1, 2> for u64 {}
+
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+ //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
+ 1_u32
+}
+
+fn owo() -> impl Traitor {
+ //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+ 1_u64
+}
+
+fn main() {
+ rawr();
+ uwu();
+ owo();
+}
--- /dev/null
+error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:8:14
+ |
+LL | fn rawr() -> impl Trait {
+ | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+ |
+ = help: the following implementations were found:
+ <Uwu<N> as Trait>
+
+error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:19:26
+ |
+LL | fn uwu<const N: u8>() -> impl Traitor<N> {
+ | ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
+ |
+ = help: the following implementations were found:
+ <u32 as Traitor<N, 2_u8>>
+
+error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:24:13
+ |
+LL | fn owo() -> impl Traitor {
+ | ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
+ |
+ = help: the following implementations were found:
+ <u64 as Traitor<1_u8, 2_u8>>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+ fn uwu(&self) -> u8 {
+ N
+ }
+}
+
+impl Trait for u32 {}
+
+impl Trait<12> for u64 {
+ fn uwu(&self) -> u8 {
+ *self as u8
+ }
+}
+
+fn foo(arg: &dyn Trait) -> u8 {
+ arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+ fn owo(&self) -> u8 {
+ M
+ }
+}
+
+impl Traitor<2> for bool { }
+impl Traitor for u8 {
+ fn owo(&self) -> u8 {
+ *self
+ }
+}
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+ arg.owo()
+}
+
+fn main() {
+ assert_eq!(foo(&10_u32), 12);
+ assert_eq!(foo(&3_u64), 3);
+
+ assert_eq!(bar(&true), 2);
+ assert_eq!(bar(&1_u8), 1);
+}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+ fn uwu(&self) -> u8 {
+ N
+ }
+}
+
+impl Trait<2> for u32 {}
+
+fn foo(arg: &dyn Trait) -> u8 {
+ arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+ fn owo(&self) -> u8 {
+ M
+ }
+}
+
+impl Traitor<2, 3> for bool { }
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+ arg.owo()
+}
+
+fn main() {
+ foo(&10_u32);
+ //~^ error: the trait bound `u32: Trait` is not satisfied
+ bar(&true);
+ //~^ error: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `u32: Trait` is not satisfied
+ --> $DIR/trait_objects_fail.rs:28:9
+ |
+LL | foo(&10_u32);
+ | --- ^^^^^^^ the trait `Trait` is not implemented for `u32`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <u32 as Trait<2_u8>>
+ = note: required for the cast to the object type `dyn Trait`
+
+error[E0277]: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+ --> $DIR/trait_objects_fail.rs:30:9
+ |
+LL | bar(&true);
+ | --- ^^^^^ the trait `Traitor<{_: u8}, {_: u8}>` is not implemented for `bool`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <bool as Traitor<2_u8, 3_u8>>
+ = note: required for the cast to the object type `dyn Traitor<{_: u8}, {_: u8}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+//~^ error: evaluation of constant value failed
+
+trait Trait<const N: u8> {}
+impl Trait<3> for () {}
+struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+//~^ error: the trait bound `(): Trait<2_u8>` is not satisfied
+
+trait Traitor<T, const N: u8> {}
+struct WhereClauseTooGeneric<T = u32, const N: u8 = 2>(T) where (): Traitor<T, N>;
+
+// no error on struct def
+struct DependentDefaultWfness<const N: u8 = 1, T = WhereClause<N>>(T);
+fn foo() -> DependentDefaultWfness {
+ //~^ error: the trait bound `(): Trait<1_u8>` is not satisfied
+ loop {}
+}
+
+fn main() {}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/wfness.rs:3:33
+ |
+LL | struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+ | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
+
+error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied
+ --> $DIR/wfness.rs:8:47
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <() as Trait<3_u8>>
+note: required by `WhereClause`
+ --> $DIR/wfness.rs:8:1
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied
+ --> $DIR/wfness.rs:16:13
+ |
+LL | fn foo() -> DependentDefaultWfness {
+ | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <() as Trait<3_u8>>
+note: required by a bound in `WhereClause`
+ --> $DIR/wfness.rs:8:47
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^ required by this bound in `WhereClause`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
arg: T,
}
+struct Foo<const N: u8 = 3, T>(T);
+//~^ error: generic parameters with a default must be trailing
+
fn main() {}
LL | struct A<T = u32, const N: usize> {
| ^
-error: aborting due to previous error
+error: generic parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:8:18
+ |
+LL | struct Foo<const N: u8 = 3, T>(T);
+ | ^
+
+error: aborting due to 2 previous errors
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait Foo<const N: usize> {}
+pub trait Bar: Foo<{ 1 }> { }
+
+fn main() {}
error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied
- --> $DIR/issue-85848.rs:24:5
+ --> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
- | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `_Contains<&C>` is not implemented for `()`
+ | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`
+ | |
+ | required by a bound introduced by this call
|
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
--> $DIR/issue-85848.rs:21:12
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
error: unconstrained generic constant
- --> $DIR/issue-85848.rs:24:5
+ --> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ----------------------- ^^^^
+ | |
+ | required by a bound introduced by this call
|
= help: try adding a `where` bound using this expression: `where [(); { contains::<T, U>() }]:`
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
|
= help: consider moving this anonymous constant into a `const` function
-error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:5:12
- |
-LL | struct Bug<T> {
- | ^ unused parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0392`.
#![cfg_attr(full, feature(generic_const_exprs))]
struct Bug<T> {
- //~^ ERROR parameter `T` is never used
+ //[min]~^ ERROR parameter `T` is never used
inner: [(); { [|_: &T| {}; 0].len() }],
//[min]~^ ERROR generic parameters may not be used in const operations
//[full]~^^ ERROR overly complex generic constant
= note: expected type parameter `S`
found union `MaybeUninit<_>`
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:7:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
use std::mem::MaybeUninit;
struct Bug<S> {
- //~^ ERROR parameter `S` is never used
+ //[min]~^ ERROR parameter `S` is never used
A: [(); {
let x: S = MaybeUninit::uninit();
//[min]~^ ERROR generic parameters may not be used in const operations
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+struct ConstAssert<const COND: bool>;
+trait True {}
+impl True for ConstAssert<true> {}
+
+struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+//~| ERROR the type of const parameters must not depend on other generic parameters
+where
+ ConstAssert<{ MIN <= MAX }>: True;
+
+fn main() {}
--- /dev/null
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-88997.rs:8:40
+ |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-88997.rs:8:54
+ |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
--- /dev/null
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct GenericStruct<const T: usize> { val: i64 }
+
+impl<const T: usize> From<GenericStruct<T>> for GenericStruct<{T + 1}> {
+ fn from(other: GenericStruct<T>) -> Self {
+ Self { val: other.val }
+ }
+}
+
+impl<const T: usize> From<GenericStruct<{T + 1}>> for GenericStruct<T> {
+ fn from(other: GenericStruct<{T + 1}>) -> Self {
+ Self { val: other.val }
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait AnotherTrait{
+ const ARRAY_SIZE: usize;
+}
+pub trait Shard<T: AnotherTrait>:
+ AsMut<[[u8; T::ARRAY_SIZE]]>
+where
+ [(); T::ARRAY_SIZE]: Sized
+{
+}
+
+fn main() {}
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<T, const H: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+where
+ [(); 1]:;
+
+fn main() {}
--- /dev/null
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-90364.rs:4:28
+ |
+LL | pub struct Foo<T, const H: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0770`.
--- /dev/null
+// Regression test for issue 90013.
+// check-pass
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+
+fn main() {
+ const { || {} };
+}
--- /dev/null
+// build-pass
+
+trait Foo {}
+
+struct Bar {
+ bytes: &'static [u8],
+ func: fn(&Box<dyn Foo>),
+}
+fn example(_: &Box<dyn Foo>) {}
+
+const BARS: &[Bar] = &[
+ Bar {
+ bytes: "0".as_bytes(),
+ func: example,
+ },
+ Bar {
+ bytes: "0".as_bytes(),
+ func: example,
+ },
+];
+
+fn main() {
+ let x = todo!();
+
+ for bar in BARS {
+ (bar.func)(&x);
+ }
+}
--- /dev/null
+// Regression test for issue #89938.
+// check-pass
+// compile-flags: --crate-type=lib
+#![feature(const_precise_live_drops)]
+
+pub const fn f() {
+ let _: Option<String> = None;
+ let _: &'static Option<String> = &None;
+}
let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
};
+const TEST_DROP: String = String::new();
+
fn main() {
// We must not promote things with interior mutability. Not even if we "project it away".
let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
+
+ // No promotion of temporaries that need to be dropped.
+ let _val: &'static _ = &TEST_DROP;
+ //~^ ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &&TEST_DROP;
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &(&TEST_DROP,);
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &[&TEST_DROP; 1];
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
}
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:44:29
+ --> $DIR/promote-not.rs:46:29
|
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:45:29
+ --> $DIR/promote-not.rs:47:29
|
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:48:29
+ --> $DIR/promote-not.rs:50:29
|
LL | let _val: &'static _ = &(1/0);
| ---------- ^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:49:29
+ --> $DIR/promote-not.rs:51:29
|
LL | let _val: &'static _ = &(1/(1-1));
| ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:50:29
+ --> $DIR/promote-not.rs:52:29
|
LL | let _val: &'static _ = &(1%0);
| ---------- ^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:51:29
+ --> $DIR/promote-not.rs:53:29
|
LL | let _val: &'static _ = &(1%(1-1));
| ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
-LL | let _val: &'static _ = &([1,2,3][4]+1);
+...
LL | }
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:52:29
+ --> $DIR/promote-not.rs:54:29
|
LL | let _val: &'static _ = &([1,2,3][4]+1);
| ---------- ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:57:29
+ |
+LL | let _val: &'static _ = &TEST_DROP;
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:59:29
+ |
+LL | let _val: &'static _ = &&TEST_DROP;
+ | ---------- ^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:59:30
+ |
+LL | let _val: &'static _ = &&TEST_DROP;
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:62:29
+ |
+LL | let _val: &'static _ = &(&TEST_DROP,);
+ | ---------- ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
LL | }
| - temporary value is freed at the end of this statement
-error: aborting due to 13 previous errors
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:62:31
+ |
+LL | let _val: &'static _ = &(&TEST_DROP,);
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:65:29
+ |
+LL | let _val: &'static _ = &[&TEST_DROP; 1];
+ | ---------- ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:65:31
+ |
+LL | let _val: &'static _ = &[&TEST_DROP; 1];
+ | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary which is freed while still in use
+ | type annotation requires that borrow lasts for `'static`
+
+error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+#![feature(const_trait_impl)]
+#![feature(const_mut_refs)]
+
+struct A();
+
+impl const Drop for A {
+ fn drop(&mut self) {}
+}
+
+const C: A = A();
+
+fn main() {
+ let _: &'static A = &A(); //~ ERROR temporary value dropped while borrowed
+ let _: &'static [A] = &[C]; //~ ERROR temporary value dropped while borrowed
+}
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promoted-const-drop.rs:13:26
+ |
+LL | let _: &'static A = &A();
+ | ---------- ^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | let _: &'static [A] = &[C];
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promoted-const-drop.rs:14:28
+ |
+LL | let _: &'static [A] = &[C];
+ | ------------ ^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+// Check that storage statements reset local qualification.
+// check-pass
+use std::cell::Cell;
+
+const C: Option<Cell<u32>> = {
+ let mut c = None;
+ let mut i = 0;
+ while i == 0 {
+ let mut x = None;
+ c = x;
+ x = Some(Cell::new(0));
+ let _ = x;
+ i += 1;
+ }
+ c
+};
+
+fn main() {
+ let _: &'static _ = &C;
+}
--- /dev/null
+// compile-flags: --crate-type=lib
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+#![feature(const_swap)]
+#![feature(raw_ref_op)]
+
+// Mutable borrow of a field with drop impl.
+pub const fn f() {
+ let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructors cannot be evaluated
+ let _ = &mut a.1;
+}
+
+// Mutable borrow of a type with drop impl.
+pub const A1: () = {
+ let mut x = None; //~ ERROR destructors cannot be evaluated
+ let mut y = Some(String::new());
+ let a = &mut x;
+ let b = &mut y;
+ std::mem::swap(a, b);
+ std::mem::forget(y);
+};
+
+// Mutable borrow of a type with drop impl.
+pub const A2: () = {
+ let mut x = None;
+ let mut y = Some(String::new());
+ let a = &mut x;
+ let b = &mut y;
+ std::mem::swap(a, b);
+ std::mem::forget(y);
+ let _z = x; //~ ERROR destructors cannot be evaluated
+};
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g1<T>() {
+ let x: Option<T> = None; //~ ERROR destructors cannot be evaluated
+ let _ = x.is_some();
+}
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g2<T>() {
+ let x: Option<T> = None;
+ let _ = x.is_some();
+ let _y = x; //~ ERROR destructors cannot be evaluated
+}
+
+// Mutable raw reference to a Drop type.
+pub const fn address_of_mut() {
+ let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ &raw mut x;
+
+ let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ std::ptr::addr_of_mut!(y);
+}
+
+// Const raw reference to a Drop type. Conservatively assumed to allow mutation
+// until resolution of https://github.com/rust-lang/rust/issues/56604.
+pub const fn address_of_const() {
+ let x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ &raw const x;
+
+ let y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ std::ptr::addr_of!(y);
+}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:9:9
+ |
+LL | let mut a: (u32, Option<String>) = (0, None);
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:15:9
+ |
+LL | let mut x = None;
+ | ^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:31:9
+ |
+LL | let _z = x;
+ | ^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:36:9
+ |
+LL | let x: Option<T> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:44:9
+ |
+LL | let _y = x;
+ | ^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:52:9
+ |
+LL | let mut y: Option<String> = None;
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:49:9
+ |
+LL | let mut x: Option<String> = None;
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:62:9
+ |
+LL | let y: Option<String> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:59:9
+ |
+LL | let x: Option<String> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
--- /dev/null
+// compile-flags: --crate-type=lib
+// check-pass
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn f() {
+ let mut x: (Option<String>, u32) = (None, 0);
+ let mut a = 10;
+ *(&mut a) = 11;
+ x.1 = a;
+}
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn g() {
+ let mut a: (u32, Option<String>) = (0, None);
+ let _ = &mut a.0;
+}
+
+// Shared reference does not allow for mutation.
+pub const fn h() {
+ let x: Option<String> = None;
+ let _ = &x;
+}
--- /dev/null
+// Checks that unions use type based qualification. Regression test for issue #90268.
+#![feature(untagged_unions)]
+use std::cell::Cell;
+
+union U { i: u32, c: Cell<u32> }
+
+const C1: Cell<u32> = {
+ unsafe { U { c: Cell::new(0) }.c }
+};
+
+const C2: Cell<u32> = {
+ unsafe { U { i : 0 }.c }
+};
+
+const C3: Cell<u32> = {
+ let mut u = U { i: 0 };
+ u.i = 1;
+ unsafe { u.c }
+};
+
+const C4: U = U { i: 0 };
+
+const C5: [U; 1] = [U {i : 0}; 1];
+
+fn main() {
+ // Interior mutability should prevent promotion.
+ let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed
+}
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:27:26
+ |
+LL | let _: &'static _ = &C1;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:28:26
+ |
+LL | let _: &'static _ = &C2;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:29:26
+ |
+LL | let _: &'static _ = &C3;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:30:26
+ |
+LL | let _: &'static _ = &C4;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | let _: &'static _ = &C5;
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:31:26
+ |
+LL | let _: &'static _ = &C5;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
|
help: the following are the possible correct uses
|
-LL | #[deprecated]
- | ~~~~~~~~~~~~~
-LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | #[deprecated = "reason"]
| ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated]
+ | ~~~~~~~~~~~~~
error: aborting due to previous error
--> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
- | ^^^^^^ required by this bound in `std::hash::Hash::hash`
+ | ^ required by this bound in `std::hash::Hash::hash`
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
- | ^^^^^^ required by this bound in `std::hash::Hash::hash`
+ | ^ required by this bound in `std::hash::Hash::hash`
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
- | ^^^^^^ required by this bound in `std::hash::Hash::hash`
+ | ^ required by this bound in `std::hash::Hash::hash`
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
- | ^^^^^^ required by this bound in `std::hash::Hash::hash`
+ | ^ required by this bound in `std::hash::Hash::hash`
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
found type `usize`
help: try using a variant of the expected enum
|
-LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/issue-42764.rs:27:33
| |
| call expression requires function
|
-help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
+help: `E::Empty4` is a unit variant, you need to write it without the parentheses
|
LL | let e4 = E::Empty4;
| ~~~~~~~~~
| |
| call expression requires function
|
-help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
+help: `XE::XEmpty4` is a unit variant, you need to write it without the parentheses
|
LL | let xe4 = XE::XEmpty4;
| ~~~~~~~~~~~
#![feature(imported_main)]
-//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module)
+//~^ ERROR `main` is ambiguous
mod m1 { pub(crate) fn main() {} }
mod m2 { pub(crate) fn main() {} }
-error[E0659]: `main` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `main` is ambiguous
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `main` could refer to the function imported here
--> $DIR/imported_main_conflict.rs:6:5
|
--- /dev/null
+// run-pass
+
+#[repr(u32)]
+pub enum Foo {
+ // Greater than or equal to 2
+ A = 2,
+}
+
+pub enum Bar {
+ A(Foo),
+ // More than two const variants
+ B,
+ C,
+}
+
+fn main() {
+ match Bar::A(Foo::A) {
+ Bar::A(_) => (),
+ _ => unreachable!(),
+ }
+}
| this method call resolves to `T`
| help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
|
- = note: cannot satisfy `Impl: Into<_>`
+note: multiple `impl`s satisfying `Impl: Into<_>` found
+ --> $DIR/E0283.rs:17:1
+ |
+LL | impl Into<u32> for Impl {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ = note: and another `impl` found in the `core` crate:
+ - impl<T, U> Into<U> for T
+ where U: From<T>;
error: aborting due to 2 previous errors
| |
| call expression requires function
|
-help: `X::Entry` is a unit variant, you need to write it without the parenthesis
+help: `X::Entry` is a unit variant, you need to write it without the parentheses
|
LL | X::Entry;
| ~~~~~~~~
-struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here
-fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ //~^ ERROR: `'_` cannot be used here [E0637]
+ //~| ERROR: missing lifetime specifier
+ if str1.len() > str2.len() {
+ str1
+ } else {
+ str2
+ }
+}
-struct Bar<'a>(&'a u8);
-impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here
- fn bar() {}
+fn and_without_explicit_lifetime<T>()
+where
+ T: Into<&u32>, //~ ERROR: `&` without an explicit lifetime name cannot be used here [E0637]
+{
}
fn main() {}
error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:1:16
+ --> $DIR/E0637.rs:1:24
|
-LL | struct Foo<'a: '_>(&'a u8);
- | ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ | ^^ `'_` is a reserved lifetime name
-error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:2:12
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+ --> $DIR/E0637.rs:13:13
|
-LL | fn foo<'a: '_>(_: &'a u8) {}
- | ^^ `'_` is a reserved lifetime name
+LL | T: Into<&u32>,
+ | ^ explicit lifetime name needed here
-error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:5:10
+error[E0106]: missing lifetime specifier
+ --> $DIR/E0637.rs:1:62
+ |
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ | ------- ------- ^^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `str1` or `str2`
+help: consider introducing a named lifetime parameter
|
-LL | impl<'a: '_> Bar<'a> {
- | ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
+ | +++ ~~ ~~ ~~
error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0637`.
+Some errors have detailed explanations: E0106, E0637.
+For more information about an error, try `rustc --explain E0106`.
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/E0659.rs:15:15
|
LL | collider::foo();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the function imported here
--> $DIR/E0659.rs:10:13
|
// run-pass
-// only-i686
+// only-x86
trait A {
extern "fastcall" fn test1(i: i32);
// run-pass
-// only-i686
+// only-x86
#![feature(abi_thiscall)]
// run-pass
// revisions: x64 x32
// [x64]only-x86_64
-// [x32]only-i686
+// [x32]only-x86
#![feature(abi_vectorcall)]
+++ /dev/null
-// Test that we allow unsizing even if there is an unchanged param in the
-// field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
-
-fn main() {
- let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
- let y: &A<[u32; 1], [u32]> = &x; //~ ERROR mismatched types
- assert_eq!(y.1.1.len(), 1);
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/feature-gate-relaxed_struct_unsize.rs:8:34
- |
-LL | let y: &A<[u32; 1], [u32]> = &x;
- | ------------------- ^^ expected slice `[u32]`, found array `[u32; 1]`
- | |
- | expected due to this
- |
- = note: expected reference `&A<[u32; 1], [u32]>`
- found reference `&A<[u32; 1], [u32; 1]>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#[derive(Debug)]
+struct Machine<S> {
+ state: S,
+ common_field1: &'static str,
+ common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ common_field1: "hello",
+ common_field2: 2,
+ };
+ let m2: Machine<State2> = Machine {
+ state: State2,
+ ..m1 //~ ERROR mismatched types
+ };
+ // FIXME: this should trigger feature gate
+ assert_eq!(State2, m2.state);
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
+ |
+LL | ..m1
+ | ^^ expected struct `State2`, found struct `State1`
+ |
+ = note: expected struct `Machine<State2>`
+ found struct `Machine<State1>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
help: the following are the possible correct uses
|
-LL | #[macro_use] struct S;
- | ~~~~~~~~~~~~
LL | #[macro_use(name1, name2, ...)] struct S;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[macro_use] struct S;
+ | ~~~~~~~~~~~~
error: aborting due to 4 previous errors
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
// run-pass
-error[E0277]: the size for values of type `Self` cannot be known at compilation time
+error[E0277]: the trait bound `Self: Trait1` is not satisfied
--> $DIR/issue-74816.rs:9:5
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait1` is not implemented for `Self`
|
note: required by a bound in `Trait2::Associated`
- --> $DIR/issue-74816.rs:9:5
+ --> $DIR/issue-74816.rs:9:22
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated`
+ | ^^^^^^ required by this bound in `Trait2::Associated`
help: consider further restricting `Self`
|
-LL | trait Trait2: Sized {
- | +++++++
+LL | trait Trait2: Trait1 {
+ | ++++++++
-error[E0277]: the trait bound `Self: Trait1` is not satisfied
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> $DIR/issue-74816.rs:9:5
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait1` is not implemented for `Self`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Trait2::Associated`
- --> $DIR/issue-74816.rs:9:22
+ --> $DIR/issue-74816.rs:9:5
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^ required by this bound in `Trait2::Associated`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated`
help: consider further restricting `Self`
|
-LL | trait Trait2: Trait1 {
- | ++++++++
+LL | trait Trait2: Sized {
+ | +++++++
error: aborting due to 2 previous errors
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ type Assoc<'a>;
+
+ fn with_assoc(f: impl FnOnce(Self::Assoc<'_>));
+}
+
+impl Trait for () {
+ type Assoc<'a> = i32;
+
+ fn with_assoc(f: impl FnOnce(Self::Assoc<'_>)) {
+ f(5i32)
+ }
+}
+
+fn main() {}
| ^^
error[E0311]: the parameter type `T` may not live long enough
- --> $DIR/issue-86483.rs:9:19
+ --> $DIR/issue-86483.rs:9:5
|
LL | pub trait IceIce<T>
| - help: consider adding an explicit lifetime bound...: `T: 'a`
...
LL | type Ice<'v>: IntoIterator<Item = &'v T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
note: ...that is required by this bound
--> $DIR/issue-86483.rs:7:16
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+ type FooFuture<'a>: Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+ type FooFuture<'a> = impl Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ Struct(unimplemented!())
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/issue-87258_a.rs:19:21
+ |
+LL | fn foo<'a>() -> Self::FooFuture<'a> {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+ type FooFuture<'a>: Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+ type FooFuture<'a> = Helper<'c, 'a, S>;
+ fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ Struct(unimplemented!())
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/issue-87258_b.rs:21:21
+ |
+LL | fn foo<'a>() -> Self::FooFuture<'a> {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ type Assoc<'a>;
+}
+
+fn f<T: Trait>(_: T, _: impl Fn(T::Assoc<'_>)) {}
+
+struct Type;
+
+impl Trait for Type {
+ type Assoc<'a> = ();
+}
+
+fn main() {
+ f(Type, |_|());
+}
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Tsized`
- --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:17
+ --> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:14
|
LL | trait Tsized<P: Sized = [Self]> {}
- | ^^^^^ required by this bound in `Tsized`
+ | ^ required by this bound in `Tsized`
error: aborting due to previous error
// run-pass
// edition:2021
-// compile-flags: -Zunstable-options
fn main() {
println!("hello, 2021");
--- /dev/null
+// check-pass
+// See issue #85526.
+// This test should produce no warnings.
+
+#![deny(missing_docs)]
+//! Crate docs
+
+#[doc(hidden)]
+pub struct Foo;
+
+impl Foo {
+ pub fn bar() {}
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub trait Foo<'a> {
+ type Bar;
+ fn foo(&'a self) -> Self::Bar;
+}
+
+impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
+ type Bar = &'a T;
+ fn foo(&'a self) -> &'a T {
+ self
+ }
+}
+
+pub fn uncallable<T, F>(x: T, f: F)
+where
+ T: for<'a> Foo<'a>,
+ F: for<'a> Fn(<T as Foo<'a>>::Bar),
+{
+ f(x.foo());
+}
+
+pub fn catalyst(x: &i32) {
+ broken(x, |_| {})
+}
+
+pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
+ uncallable(x, |y| f(y));
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+fn foo<T>(t: T) -> usize
+where
+ for<'a> &'a T: IntoIterator,
+ for<'a> <&'a T as IntoIterator>::IntoIter: ExactSizeIterator,
+{
+ t.into_iter().len()
+}
+
+fn main() {
+ foo::<Vec<u32>>(vec![]);
+}
}
fn main() {
- task(annotate( //~ type mismatch
+ task(annotate(
//~^ the size
//~^^ the trait bound
Annotate::<RefMutFamily<usize>>::new(),
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-LL | | |value: &mut usize| {
- | | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
-LL | | *value = 2;
-LL | | }
-LL | | ));
- | |_____^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
- |
-note: required by a bound in `annotate`
- --> $DIR/issue-62529-1.rs:44:8
- |
-LL | fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static
- | -------- required by a bound in this
-LL | where
-LL | F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `annotate`
-
error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
--> $DIR/issue-62529-1.rs:80:10
|
LL | where P: Execute + 'static {
| ^^^^^^^ required by this bound in `task`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0277, E0631.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
+// check-pass
+
pub trait MyTrait<'a> {
type Output: 'a;
fn gimme_value(&self) -> Self::Output;
fn main() {
let struc = MyStruct;
- meow(struc, |foo| { //~ type mismatch
+ meow(struc, |foo| {
println!("{:?}", foo);
})
}
+++ /dev/null
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-70120.rs:26:5
- |
-LL | meow(struc, |foo| {
- | ^^^^ ----- found signature of `for<'r> fn(&'r usize) -> _`
- | |
- | expected signature of `for<'any2> fn(<MyStruct as MyTrait<'any2>>::Output) -> _`
- |
-note: required by a bound in `meow`
- --> $DIR/issue-70120.rs:18:8
- |
-LL | fn meow<T, F>(t: T, f: F)
- | ---- required by a bound in this
-...
-LL | F: for<'any2> Fn(<T as MyTrait<'any2>>::Output),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `meow`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
--- /dev/null
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: aborting due to 10 previous errors
+
--- /dev/null
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/issue-71955.rs:42:1
+ |
+LL | fn main() {
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// ignore-compare-mode-nll
+// revisions: migrate nll
+// [nll]compile-flags: -Zborrowck=mir
+// check-fail
+
+#![feature(rustc_attrs)]
+
+trait Parser<'s> {
+ type Output;
+
+ fn call(&self, input: &'s str) -> (&'s str, Self::Output);
+}
+
+impl<'s, F, T> Parser<'s> for F
+where F: Fn(&'s str) -> (&'s str, T) {
+ type Output = T;
+ fn call(&self, input: &'s str) -> (&'s str, T) {
+ self(input)
+ }
+}
+
+fn foo<F1, F2>(
+ f1: F1,
+ base: &'static str,
+ f2: F2
+)
+where
+ F1: for<'a> Parser<'a>,
+ F2: FnOnce(&<F1 as Parser>::Output) -> bool
+{
+ let s: String = base.to_owned();
+ let str_ref = s.as_ref();
+ let (remaining, produced) = f1.call(str_ref);
+ assert!(f2(&produced));
+ assert_eq!(remaining.len(), 0);
+}
+
+struct Wrapper<'a>(&'a str);
+
+// Because nll currently succeeds and migrate doesn't
+#[rustc_error]
+fn main() {
+ //[nll]~^ fatal
+ fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
+ (&s[..1], &s[..])
+ }
+
+ fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
+ (&s[..1], Wrapper(&s[..]))
+ }
+
+ foo(bar, "string", |s| s.len() == 5);
+ //[migrate]~^ ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ foo(baz, "string", |s| s.0.len() == 5);
+ //[migrate]~^ ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+}
--- /dev/null
+// check-pass
+
+use std::marker::PhantomData;
+
+trait A<'a> {
+ type B;
+ fn b(self) -> Self::B;
+}
+
+struct T;
+struct S<'a>(PhantomData<&'a ()>);
+
+impl<'a> A<'a> for T {
+ type B = S<'a>;
+ fn b(self) -> Self::B {
+ S(PhantomData)
+ }
+}
+
+fn s<TT, F>(t: TT, f: F)
+where
+ TT: for<'a> A<'a>,
+ F: for<'a> FnOnce(<TT as A<'a>>::B)
+{
+ f(t.b());
+}
+
+fn main() {
+ s(T, |_| {});
+}
--- /dev/null
+// check-pass
+
+use std::ops::Deref;
+
+struct Data {
+ boxed: Box<&'static i32>
+}
+
+impl Data {
+ fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target)) {
+ user(*self.boxed)
+ }
+}
+
+fn main() {}
fn main() {
let v = Unit2.m(
//~^ ERROR type mismatch
- //~| ERROR type mismatch
L {
+ //~^ ERROR type mismatch
f : |x| { drop(x); Unit4 }
});
}
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&'r u8,),)>>::Output == Unit3`
- --> $DIR/issue-62203-hrtb-ice.rs:38:19
+ --> $DIR/issue-62203-hrtb-ice.rs:40:9
|
-LL | let v = Unit2.m(
- | ^ expected struct `Unit4`, found struct `Unit3`
+LL | let v = Unit2.m(
+ | - required by a bound introduced by this call
+LL |
+LL | / L {
+LL | |
+LL | | f : |x| { drop(x); Unit4 }
+LL | | });
+ | |_________^ expected struct `Unit4`, found struct `Unit3`
|
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16
--- /dev/null
+// check-pass
+
+trait Base<'f> {
+ type Assoc;
+
+ fn do_something(&self);
+}
+
+trait ForAnyLifetime: for<'f> Base<'f> {}
+
+impl<T> ForAnyLifetime for T where T: for<'f> Base<'f> {}
+
+trait CanBeDynamic: ForAnyLifetime + for<'f> Base<'f, Assoc = ()> {}
+
+fn foo(a: &dyn CanBeDynamic) {
+ a.do_something();
+}
+
+struct S;
+
+impl<'a> Base<'a> for S {
+ type Assoc = ();
+
+ fn do_something(&self) {}
+}
+
+impl CanBeDynamic for S {}
+
+fn main() {
+ let s = S;
+ foo(&s);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Field {
+ RootCtxt,
+ MacroCtxt,
+}
+
+#[rustfmt::skip]
+macro x(
+ $macro_name:ident,
+ $macro2_name:ident,
+ $type_name:ident,
+ $field_name:ident,
+ $const_name:ident
+) {
+ #[derive(Copy, Clone)]
+ pub struct $type_name {
+ pub field: Field,
+ pub $field_name: Field,
+ }
+
+ pub const $const_name: $type_name =
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt };
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }};
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }};
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }},
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }},
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ }
+ }
+}
+
+x!(test_fields, test_fields2, MyStruct, field, MY_CONST);
+
+pub fn check_fields(s: MyStruct) {
+ test_fields!(check_fields_of s);
+}
+
+pub fn check_fields_local() {
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum Method {
+ DefaultMacroCtxt,
+ DefaultRootCtxt,
+ OverrideMacroCtxt,
+ OverrideRootCtxt,
+}
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) {
+ pub trait $trait_name {
+ fn method(&self) -> Method {
+ Method::DefaultMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::DefaultRootCtxt
+ }
+ }
+
+ impl $trait_name for () {}
+ impl $trait_name for bool {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ };
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ };
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ };
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ },
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ },
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ },
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ }
+ }
+}
+
+x!(test_trait, test_trait2, MyTrait, method);
+
+impl MyTrait for char {}
+test_trait!(impl for i32);
+test_trait2!(impl for i64);
+
+pub fn check_crate_local() {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+}
+
+// Check that any comparison of idents at monomorphization time is correct
+pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+
+ test_trait!(assert_no_override t);
+ test_trait2!(assert_no_override t);
+ test_trait!(assert_override u);
+ test_trait2!(assert_override u);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+macro x() {
+ pub struct MyStruct;
+}
+
+x!();
--- /dev/null
+#![feature(decl_macro)]
+
+macro x($macro_name:ident) {
+ #[macro_export]
+ macro_rules! $macro_name {
+ (define) => {
+ pub struct MyStruct;
+ };
+ (create) => {
+ MyStruct {}
+ };
+ }
+}
+
+x!(my_struct);
--- /dev/null
+#![feature(decl_macro)]
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) {
+ #[repr(u8)]
+ pub enum $type_name {
+ Variant = 0,
+ $variant_name = 1,
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }};
+ }
+
+ pub macro $macro2_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }},
+ }
+}
+
+x!(test_variants, test_variants2, MyEnum, Variant);
+
+pub fn check_variants() {
+ test_variants!();
+ test_variants2!();
+}
--- /dev/null
+// Check that a marco from another crate can define an item in one expansion
+// and use it from another, without it being visible to everyone.
+// This requires that the definition of `my_struct` preserves the hygiene
+// information for the tokens in its definition.
+
+// check-pass
+// aux-build:use_by_macro.rs
+
+#![feature(type_name_of_val)]
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+enum MyStruct {}
+my_struct!(define);
+
+fn main() {
+ let x = my_struct!(create);
+}
--- /dev/null
+// Test that fields on a struct defined in another crate are resolved correctly
+// their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:fields.rs
+
+extern crate fields;
+
+use fields::*;
+
+fn main() {
+ check_fields_local();
+
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ check_fields(s1);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ check_fields(s2);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+// Check that globs cannot import hygienic identifiers from a macro expansion
+// in another crate. `my_struct` is a `macro_rules` macro, so the struct it
+// defines is only not imported because `my_struct` is defined by a macros 2.0
+// macro.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+mod m {
+ use use_by_macro::*;
+
+ my_struct!(define);
+}
+
+use m::*;
+
+fn main() {
+ let x = my_struct!(create);
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-glob-hygiene.rs:21:13
+ |
+LL | let x = my_struct!(create);
+ | ^^^^^^^^^^^^^^^^^^ not found in this scope
+ |
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Test that methods defined in another crate are resolved correctly their
+// names differ only in `SyntaxContext`. This also checks that any name
+// resolution done when monomorphizing is correct.
+
+// run-pass
+// aux-build:methods.rs
+
+extern crate methods;
+
+use methods::*;
+
+struct A;
+struct B;
+struct C;
+
+impl MyTrait for A {}
+test_trait!(impl for B);
+test_trait2!(impl for C);
+
+fn main() {
+ check_crate_local();
+ check_crate_local_generic(A, B);
+ check_crate_local_generic(A, C);
+
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+ test_trait!(assert_no_override A);
+ test_trait2!(assert_no_override A);
+ test_trait!(assert_override B);
+ test_trait2!(assert_override B);
+ test_trait!(assert_override C);
+ test_trait2!(assert_override C);
+}
--- /dev/null
+// Check that two items defined in another crate that have identifiers that
+// only differ by `SyntaxContext` do not cause name collisions when imported
+// in another crate.
+
+// check-pass
+// aux-build:needs_hygiene.rs
+
+extern crate needs_hygiene;
+
+use needs_hygiene::*;
+
+fn main() {}
--- /dev/null
+// Check that an identifier from a 2.0 macro in another crate cannot be
+// resolved with an identifier that's not from a macro expansion.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding-2.rs:13:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that an item defined by a 2.0 macro in another crate cannot be used in
+// another crate.
+
+// aux-build:pub_hygiene.rs
+
+extern crate pub_hygiene;
+
+use pub_hygiene::*;
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding.rs:11:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that items with identical `SyntaxContext` conflict even when that
+// context involves a mark from another crate.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+//~^ ERROR the name `MyStruct` is defined multiple times
+my_struct!(define);
+
+fn main() {}
--- /dev/null
+error[E0428]: the name `MyStruct` is defined multiple times
+ --> $DIR/cross-crate-redefine.rs:10:1
+ |
+LL | my_struct!(define);
+ | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
+LL |
+LL | my_struct!(define);
+ | ------------------ previous definition of the type `MyStruct` here
+ |
+ = note: `MyStruct` must be defined only once in the type namespace of this module
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
--- /dev/null
+// Test that variants of an enum defined in another crate are resolved
+// correctly when their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:variants.rs
+
+extern crate variants;
+
+use variants::*;
+
+fn main() {
+ check_variants();
+
+ test_variants!();
+ test_variants2!();
+
+ assert_eq!(MyEnum::Variant as u8, 1);
+}
+++ /dev/null
-// check-pass
-// aux-build:needs_hygiene.rs
-
-extern crate needs_hygiene;
-
-use needs_hygiene::*;
-
-fn main() {}
--> $DIR/rustc-macro-transparency.rs:26:5
|
LL | Opaque;
- | ^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `opaque`
+ | ^^^^^^ not found in this scope
error[E0423]: expected value, found macro `semitransparent`
--> $DIR/rustc-macro-transparency.rs:29:5
|
+LL | struct SemiTransparent;
+ | ----------------------- similarly named unit struct `SemiTransparent` defined here
+...
LL | semitransparent;
| ^^^^^^^^^^^^^^^ not a value
|
|
LL | semitransparent!;
| +
+help: a unit struct with a similar name exists
+ |
+LL | SemiTransparent;
+ | ~~~~~~~~~~~~~~~
error[E0423]: expected value, found macro `opaque`
--> $DIR/rustc-macro-transparency.rs:30:5
|
+LL | struct Opaque;
+ | -------------- similarly named unit struct `Opaque` defined here
+...
LL | opaque;
| ^^^^^^ not a value
|
|
LL | opaque!;
| +
+help: a unit struct with a similar name exists
+ |
+LL | Opaque;
+ | ~~~~~~
error: aborting due to 3 previous errors
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
- --> $DIR/auto-trait-leak2.rs:13:5
+ --> $DIR/auto-trait-leak2.rs:13:10
|
LL | fn before() -> impl Fn(i32) {
| ------------ within this `impl Fn<(i32,)>`
...
LL | send(before());
- | ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
| ^^^^ required by this bound in `send`
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
- --> $DIR/auto-trait-leak2.rs:16:5
+ --> $DIR/auto-trait-leak2.rs:16:10
|
LL | send(after());
- | ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | ---- ^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
...
LL | fn after() -> impl Fn(i32) {
| ------------ within this `impl Fn<(i32,)>`
//~| expected `i32`, found `u32`
}
-fn sum_to(n: u32) -> impl Foo {
+fn sum_to(n: u32) -> impl Foo { //~ ERROR type annotations needed
if n == 0 {
0
} else {
|
= help: the trait `Add<impl Foo>` is not implemented for `u32`
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0283]: type annotations needed
+ --> $DIR/equality.rs:20:22
+ |
+LL | fn sum_to(n: u32) -> impl Foo {
+ | ^^^^^^^^ cannot infer type for type `{integer}`
+ |
+ = note: multiple `impl`s satisfying `{integer}: ToString` found in the `alloc` crate:
+ - impl ToString for i8;
+ - impl ToString for u8;
+note: required because of the requirements on the impl of `Foo` for `{integer}`
+ --> $DIR/equality.rs:5:26
+ |
+LL | impl<T: Copy + ToString> Foo for T {}
+ | ^^^ ^
+
+error: aborting due to 3 previous errors; 1 warning emitted
-Some errors have detailed explanations: E0277, E0308.
+Some errors have detailed explanations: E0277, E0283, E0308.
For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:16:74
- |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
- | -- ^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
- |
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
- |
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
- | ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0700`.
--> $DIR/ordinary-bounds-unrelated.rs:16:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
- | ^^^^^^^^^^^^^^^^^^
+ | -- ^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
-note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unrelated.rs:16:74
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
-LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
- | ^^^^^^^^^^^^^^^^^^
+LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
+ | ++++
error: aborting due to previous error
+++ /dev/null
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:18:62
- |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- | -- ^^^^^^^^^^^^^^^^^^
- | |
- | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
- |
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
- |
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
- | ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0700`.
--> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- | ^^^^^^^^^^^^^^^^^^
+ | -- ^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
-note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unsuited.rs:18:62
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
-LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- | ^^^^^^^^^^^^^^^^^^
+LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
+ | ++++
error: aborting due to previous error
-error: lifetime may not live long enough
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:3:23
|
LL | fn elided(x: &i32) -> impl Copy { x }
- | - ^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+ | ---- ^^^^^^^^^
| |
- | let's call the lifetime of this reference `'1`
+ | hidden type `&i32` captures the anonymous lifetime defined here
|
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
-error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:5:32
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/must_outlive_least_region_or_bound.rs:6:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+ | -- ^^^^^^^^^
| |
- | lifetime `'a` defined here
+ | hidden type `&'a i32` captures the lifetime `'a` as defined here
|
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++++
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:7:46
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| - ^ returning this value requires that `'1` must outlive `'static`
= help: consider replacing `'1` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:9:55
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:11:41
+ --> $DIR/must_outlive_least_region_or_bound.rs:13:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^ lifetime `'a` required
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:22:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:24:55
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
- | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+ | - ^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
| |
| let's call the lifetime of this reference `'1`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:28:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
-error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:32:61
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/must_outlive_least_region_or_bound.rs:33:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
- | |
- | lifetime `'a` defined here
+ | -- ^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+ |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
- = help: consider adding the following bound: `'b: 'a`
+LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
+ | ++++
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:37:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:38:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 9 previous errors
-Some errors have detailed explanations: E0310, E0621.
+Some errors have detailed explanations: E0310, E0621, E0700.
For more information about an error, try `rustc --explain E0310`.
use std::fmt::Debug;
-fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759
+fn elided(x: &i32) -> impl Copy { x }
+//~^ ERROR: captures lifetime that does not appear in bounds
-fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759
+fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+//~^ ERROR: captures lifetime that does not appear in bounds
fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759
fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
-//~^ ERROR E0759
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
// Tests that a closure type containing 'b cannot be returned from a type where
// only 'a was expected.
fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- //~^ ERROR lifetime mismatch
+ //~^ ERROR: captures lifetime that does not appear in bounds
move |_| println!("{}", y)
}
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:3:35
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/must_outlive_least_region_or_bound.rs:3:23
|
LL | fn elided(x: &i32) -> impl Copy { x }
- | ---- ^ ...is captured here...
+ | ---- ^^^^^^^^^
| |
- | this data with an anonymous lifetime `'_`...
- |
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+ | hidden type `&i32` captures the anonymous lifetime defined here
|
-LL | fn elided(x: &i32) -> impl Copy { x }
- | ^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
-error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:5:44
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/must_outlive_least_region_or_bound.rs:6:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | ------- ^ ...is captured here...
- | |
- | this data with lifetime `'a`...
+ | -- ^^^^^^^^^
+ | |
+ | hidden type `&'a i32` captures the lifetime `'a` as defined here
|
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:5:32
- |
-LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | ^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++++
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:7:46
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ---- ^ ...is captured here...
| this data with an anonymous lifetime `'_`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:7:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:24
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:9:55
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ------- ^ ...is captured here...
| this data with lifetime `'a`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:9:33
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:33
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:11:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:13:24
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^^^^^^^^^^^^^^ lifetime `'a` required
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:22:65
+ --> $DIR/must_outlive_least_region_or_bound.rs:24:65
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
| ++++
-error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:22:69
- |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
- | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here...
- |
-note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:22:41
- |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
- | ^^^^^^^^^^
-help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
- |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug + '_>, impl Debug) { (Box::new(x), x) }
- | ++++
-help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound
- |
-LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
- | ++++
-
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:28:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- this data with lifetime `'a`... ^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:28:34
+ --> $DIR/must_outlive_least_region_or_bound.rs:29:34
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
| ~~~~~~~~~~~~
-error[E0623]: lifetime mismatch
- --> $DIR/must_outlive_least_region_or_bound.rs:32:61
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/must_outlive_least_region_or_bound.rs:33:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
- | ------- ^^^^^^^^^^^^^^^^
- | | |
- | | ...but data from `y` is returned here
- | this parameter and the return type are declared with different lifetimes...
+ | -- ^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
+ |
+help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+ |
+LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
+ | ++++
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:37:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:38:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| help: consider adding an explicit lifetime bound...: `T: 'static +`
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:14:50
+ --> $DIR/must_outlive_least_region_or_bound.rs:16:50
|
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
| ++++
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:16:59
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:59
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| ------- ^ ...is captured here, requiring it to live as long as `'static`
| ++++
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:18:60
+ --> $DIR/must_outlive_least_region_or_bound.rs:20:60
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
| ~~~~~~~~~~~~
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/must_outlive_least_region_or_bound.rs:20:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static`
LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ~~~~~~~~~~~~
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
-Some errors have detailed explanations: E0310, E0621, E0623, E0759.
+Some errors have detailed explanations: E0310, E0621, E0700, E0759.
For more information about an error, try `rustc --explain E0310`.
|
LL | use foo::Bar;
|
+LL | use no_method_suggested_traits::Reexported;
+ |
LL | use no_method_suggested_traits::foo::PubPub;
|
LL | use no_method_suggested_traits::qux::PrivPub;
|
-LL | use no_method_suggested_traits::Reexported;
- |
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:26:44
|
LL | use foo::Bar;
|
+LL | use no_method_suggested_traits::Reexported;
+ |
LL | use no_method_suggested_traits::foo::PubPub;
|
LL | use no_method_suggested_traits::qux::PrivPub;
|
-LL | use no_method_suggested_traits::Reexported;
- |
error[E0599]: no method named `method` found for type `char` in the current scope
--> $DIR/no-method-suggested-traits.rs:30:9
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/static-return-lifetime-infered.rs:6:35
- |
-LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | - ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
- | |
- | let's call the lifetime of this reference `'1`
- |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
- |
-LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
- | ++++
-
-error: lifetime may not live long enough
- --> $DIR/static-return-lifetime-infered.rs:9:37
- |
-LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
- | |
- | lifetime `'a` defined here
- |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
- |
-LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
- | ++++
-
-error: aborting due to 2 previous errors
-
impl A {
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0) //~ ERROR E0759
+ //~^ ERROR: captures lifetime that does not appear in bounds
+ //~| ERROR: captures lifetime that does not appear in bounds
+ self.x.iter().map(|a| a.0)
}
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0) //~ ERROR E0759
+ //~^ ERROR: captures lifetime that does not appear in bounds
+ //~| ERROR: captures lifetime that does not appear in bounds
+ self.x.iter().map(|a| a.0)
}
}
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/static-return-lifetime-infered.rs:7:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/static-return-lifetime-infered.rs:6:35
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- this data with an anonymous lifetime `'_`...
-LL | self.x.iter().map(|a| a.0)
- | ------ ^^^^
- | |
- | ...is captured here...
+ | ----- ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+ |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
-note: ...and is required to live as long as `'static` here
+LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
+ | ++++
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/static-return-lifetime-infered.rs:6:35
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ^^^^^^^^^^^^^^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ | ----- ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
+ |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ++++
-error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/static-return-lifetime-infered.rs:10:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/static-return-lifetime-infered.rs:11:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | -------- this data with lifetime `'a`...
-LL | self.x.iter().map(|a| a.0)
- | ------ ^^^^
- | |
- | ...is captured here...
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
|
-note: ...and is required to live as long as `'static` here
- --> $DIR/static-return-lifetime-infered.rs:9:37
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+ |
+LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
+ | ++++
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/static-return-lifetime-infered.rs:11:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- | ^^^^^^^^^^^^^^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound
+ | -- ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
+ |
+help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ++++
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
|
= note: `foo` must be defined only once in the value namespace of this module
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:46:15
|
LL | use self::foo::bar;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the module imported here
--> $DIR/duplicate.rs:43:9
|
| ^^^^^^^^^^^
= help: consider adding an explicit import of `foo` to disambiguate
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:35:8
|
LL | f::foo();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the function imported here
--> $DIR/duplicate.rs:24:13
|
| ^^^^
= help: consider adding an explicit import of `foo` to disambiguate
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:49:9
|
LL | foo::bar();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the module imported here
--> $DIR/duplicate.rs:43:9
|
|
= note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `Vec` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `Vec` is ambiguous
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9
|
LL | Vec::panic!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `Vec` could refer to the crate imported here
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:5:9
|
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
--> $DIR/glob-shadowing.rs:11:17
|
LL | let x = env!("PATH");
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `env` could refer to a macro from prelude
note: `env` could also refer to the macro imported here
--> $DIR/glob-shadowing.rs:9:9
= help: consider adding an explicit import of `env` to disambiguate
= help: or use `self::env` to refer to this macro unambiguously
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
--> $DIR/glob-shadowing.rs:19:21
|
LL | let x = env!("PATH");
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `env` could refer to a macro from prelude
note: `env` could also refer to the macro imported here
--> $DIR/glob-shadowing.rs:17:13
| ^^^^
= help: consider adding an explicit import of `env` to disambiguate
-error[E0659]: `fenv` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `fenv` is ambiguous
--> $DIR/glob-shadowing.rs:29:21
|
LL | let x = fenv!();
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
note: `fenv` could refer to the macro imported here
--> $DIR/glob-shadowing.rs:27:13
|
LL | use nonexistent_module::mac;
| ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`?
-error[E0659]: `mac` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `mac` is ambiguous
--> $DIR/issue-53269.rs:8:5
|
LL | mac!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `mac` could refer to the macro defined here
--> $DIR/issue-53269.rs:3:1
|
-error[E0659]: `S` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `S` is ambiguous
--> $DIR/issue-55884-1.rs:19:12
|
LL | use m::S;
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `S` could refer to the struct imported here
--> $DIR/issue-55884-1.rs:14:13
|
LL | use empty::issue_56125;
| ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty`
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:6:9
|
LL | use issue_56125::last_segment::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::issue_56125` to refer to this module unambiguously
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:11:9
|
LL | use issue_56125::non_last_segment::non_last_segment::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::issue_56125` to refer to this module unambiguously
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:18:9
|
LL | use issue_56125::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
-error[E0659]: `core` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `core` is ambiguous
--> $DIR/issue-57539.rs:4:9
|
LL | use core;
| ^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `core` could refer to a built-in crate
= help: use `::core` to refer to this crate unambiguously
note: `core` could also refer to the module imported here
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:28:1
|
LL | exported!();
| ^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `exported` could refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:5:5
|
= help: consider adding an explicit import of `exported` to disambiguate
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:28:1
|
LL | exported!();
| ^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `exported` could refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:5:5
|
= help: consider adding an explicit import of `exported` to disambiguate
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:36:5
|
LL | panic!();
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:11:5
= help: use `crate::panic` to refer to this macro unambiguously
= note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `include` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `include` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:47:1
|
LL | include!();
| ^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `include` could refer to a macro from prelude
note: `include` could also refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:17:5
-error[E0659]: `bar` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `bar` is ambiguous
--> $DIR/macro-paths.rs:13:5
|
LL | bar::m! {
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `bar` could refer to the module defined here
--> $DIR/macro-paths.rs:14:9
|
| ^^^^^^
= help: consider adding an explicit import of `bar` to disambiguate
-error[E0659]: `baz` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `baz` is ambiguous
--> $DIR/macro-paths.rs:23:5
|
LL | baz::m! {
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `baz` could refer to the module defined here
--> $DIR/macro-paths.rs:24:9
|
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:16:5
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:18:13
|
| ^^^^^^^^^^^^^
= help: consider adding an explicit import of `m` to disambiguate
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:16:5
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:18:13
|
| ^^^^^^^^^^^^^
= help: consider adding an explicit import of `m` to disambiguate
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:30:9
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:31:17
|
-error[E0659]: `Foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `Foo` is ambiguous
--> $DIR/rfc-1560-warning-cycle.rs:9:17
|
LL | fn f(_: Foo) {}
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `Foo` could refer to the struct imported here
--> $DIR/rfc-1560-warning-cycle.rs:7:13
|
-error[E0659]: `panic` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:15:14
|
LL | fn f() { panic!(); }
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:14:9
= help: consider adding an explicit import of `panic` to disambiguate
= help: or use `self::panic` to refer to this macro unambiguously
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:33:5
|
LL | panic!();
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro defined here
--> $DIR/shadow_builtin_macros.rs:30:9
| ---- in this macro invocation
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `n` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `n` is ambiguous
--> $DIR/shadow_builtin_macros.rs:49:5
|
LL | n!();
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
note: `n` could refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:48:9
|
LL | #[macro_use(n)]
| ^
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:20:14
|
LL | fn f() { panic!(); }
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:19:26
--> $DIR/mismatched_trait_impl-2.rs:8:5
|
LL | fn deref(&self) -> &dyn Trait {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
|
::: $SRC_DIR/core/src/ops/deref.rs:LL:COL
|
LL | fn deref(&self) -> &Self::Target;
- | --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
+ | --------------------------------- expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
|
- = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
- found `fn(&Struct) -> &dyn Trait`
+ = note: expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
+ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
--> $DIR/mismatched_trait_impl.rs:9:5
|
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
- | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
|
- = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
- found `fn(&i32, &u32, &u32) -> &u32`
+ = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
--> $DIR/mismatched_trait_impl.rs:9:5
|
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
- | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
|
- = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
- found `fn(&i32, &u32, &u32) -> &u32`
+ = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
| |
| cannot infer type for type parameter `Q` declared on the associated function `get`
|
- = note: cannot satisfy `String: Borrow<_>`
+ = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+ - impl Borrow<str> for String;
+ - impl<T> Borrow<T> for T
+ where T: ?Sized;
error: aborting due to previous error
| |
| cannot infer type
|
- = note: cannot satisfy `String: PartialEq<_>`
+ = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
+ - impl PartialEq for String;
+ - impl<'a, 'b> PartialEq<&'a str> for String;
+ - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
+ - impl<'a, 'b> PartialEq<str> for String;
error: aborting due to previous error
//~^ ERROR expected a `FnOnce<()>` closure
const_eval_select((), 42, 0xDEADBEEF);
//~^ ERROR expected a `FnOnce<()>` closure
+ //~| ERROR expected a `FnOnce<()>` closure
}
const fn foo(n: i32) -> i32 {
error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
- --> $DIR/const-eval-select-bad.rs:6:34
+ --> $DIR/const-eval-select-bad.rs:6:27
|
LL | const_eval_select((), || {}, || {});
- | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+ | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
| |
| required by a bound introduced by this call
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
- --> $DIR/const-eval-select-bad.rs:8:31
+ --> $DIR/const-eval-select-bad.rs:8:27
|
LL | const_eval_select((), 42, 0xDEADBEEF);
- | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+ | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}`
| |
| required by a bound introduced by this call
|
LL | F: ~const FnOnce<ARG, Output = RET>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+ --> $DIR/const-eval-select-bad.rs:8:31
+ |
+LL | const_eval_select((), 42, 0xDEADBEEF);
+ | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `FnOnce<()>` is not implemented for `{integer}`
+ = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `const_eval_select`
+ --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | G: FnOnce<ARG, Output = RET> + ~const Drop,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
- --> $DIR/const-eval-select-bad.rs:27:5
+ --> $DIR/const-eval-select-bad.rs:28:5
|
LL | const_eval_select((1,), foo, bar);
| ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool`
| ^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0631]: type mismatch in function arguments
- --> $DIR/const-eval-select-bad.rs:32:37
+ --> $DIR/const-eval-select-bad.rs:33:32
|
LL | const fn foo(n: i32) -> i32 {
| --------------------------- found signature of `fn(i32) -> _`
...
LL | const_eval_select((true,), foo, baz);
- | ----------------- ^^^ expected signature of `fn(bool) -> _`
+ | ----------------- ^^^ expected signature of `fn(bool) -> _`
| |
| required by a bound introduced by this call
|
LL | F: ~const FnOnce<ARG, Output = RET>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0271, E0277, E0631.
For more information about an error, try `rustc --explain E0271`.
-error[E0283]: type annotations needed
+error[E0282]: type annotations needed
--> $DIR/issue-16966.rs:2:5
|
LL | panic!(std::default::Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
|
- = note: cannot satisfy `_: Any`
-note: required by a bound in `begin_panic`
- --> $SRC_DIR/std/src/panicking.rs:LL:COL
- |
-LL | pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
- | ^^^ required by this bound in `begin_panic`
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider specifying the type argument in the function call
- |
-LL | $crate::rt::begin_panic::<M>($msg)
- | +++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0282`.
--> $SRC_DIR/core/src/hash/mod.rs:LL:COL
|
LL | fn hash<H: Hasher>(&self, state: &mut H);
- | ^^^^^^ required by this bound in `std::hash::Hash::hash`
+ | ^ required by this bound in `std::hash::Hash::hash`
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
| -------------- variant or associated item `PIE` not found here
...
LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
- | ^^^ variant or associated item not found in `Delicious`
+ | ^^^
+ | |
+ | variant or associated item not found in `Delicious`
+ | help: there is a variant with a similar name: `Pie`
error: aborting due to previous error
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Next`
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
--> $DIR/issue-23122-2.rs:9:17
|
LL | type Next = <GetNext<T::Next> as Next>::Next;
LL | let _ = <S5<_>>::xxx;
| ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
|
- = note: cannot satisfy `S5<_>: Foo`
+note: multiple `impl`s satisfying `S5<_>: Foo` found
+ --> $DIR/issue-29147.rs:17:1
+ |
+LL | impl Foo for S5<u32> { fn xxx(&self) {} }
+ | ^^^^^^^^^^^^^^^^^^^^
+LL | impl Foo for S5<u64> { fn xxx(&self) {} }
+ | ^^^^^^^^^^^^^^^^^^^^
note: required by `Foo::xxx`
--> $DIR/issue-29147.rs:10:13
|
struct M(PtrBack<Vec<M>>);
+#[allow(unused_must_use)]
fn main() {
std::mem::size_of::<M>();
}
error[E0277]: `Rc<Foo>` cannot be shared between threads safely
- --> $DIR/issue-40827.rs:14:5
+ --> $DIR/issue-40827.rs:14:7
|
LL | f(Foo(Arc::new(Bar::B(None))));
- | ^ `Rc<Foo>` cannot be shared between threads safely
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
note: required because it appears within the type `Bar`
| ^^^^ required by this bound in `f`
error[E0277]: `Rc<Foo>` cannot be sent between threads safely
- --> $DIR/issue-40827.rs:14:5
+ --> $DIR/issue-40827.rs:14:7
|
LL | f(Foo(Arc::new(Bar::B(None))));
- | ^ `Rc<Foo>` cannot be sent between threads safely
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
note: required because it appears within the type `Bar`
+++ /dev/null
-pub trait Foo<'a> {
- type Bar;
- fn foo(&'a self) -> Self::Bar;
-}
-
-impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
- type Bar = &'a T;
- fn foo(&'a self) -> &'a T {
- self
- }
-}
-
-pub fn uncallable<T, F>(x: T, f: F)
-where
- T: for<'a> Foo<'a>,
- F: for<'a> Fn(<T as Foo<'a>>::Bar),
-{
- f(x.foo());
-}
-
-pub fn catalyst(x: &i32) {
- broken(x, |_| {})
-}
-
-pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
- uncallable(x, |y| f(y));
- //~^ type mismatch
-}
-
-fn main() {}
+++ /dev/null
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-44005.rs:26:5
- |
-LL | uncallable(x, |y| f(y));
- | ^^^^^^^^^^ -------- found signature of `for<'r> fn(&'r i32) -> _`
- | |
- | expected signature of `for<'a> fn(<&i32 as Foo<'a>>::Bar) -> _`
- |
-note: required by a bound in `uncallable`
- --> $DIR/issue-44005.rs:16:8
- |
-LL | pub fn uncallable<T, F>(x: T, f: F)
- | ---------- required by a bound in this
-...
-LL | F: for<'a> Fn(<T as Foo<'a>>::Bar),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `uncallable`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
|
= note: cannot satisfy `_: Tt`
note: required by a bound in `Tt::const_val`
- --> $DIR/issue-54954.rs:5:27
+ --> $DIR/issue-54954.rs:5:24
|
LL | const fn const_val<T: Sized>() -> usize {
- | ^^^^^ required by this bound in `Tt::const_val`
+ | ^ required by this bound in `Tt::const_val`
error: aborting due to 2 previous errors
// run-fail
// compile-flags: -C opt-level=3
-// min-llvm-version: 11.0
// error-pattern: index out of bounds: the len is 0 but the index is 16777216
// ignore-wasm no panic or subprocess support
// ignore-emscripten no panic or subprocess support
fn main() {
let xs: Vec<u64> = vec![1, 2, 3];
println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed
+ //~^ ERROR type annotations needed
}
LL | println!("{}", 23u64.test(xs.iter().sum()));
| ^^^^ cannot satisfy `<u64 as Test<_>>::Output == _`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/issue-69455.rs:29:26
+ |
+LL | println!("{}", 23u64.test(xs.iter().sum()));
+ | ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+ |
+note: multiple `impl`s satisfying `u64: Test<_>` found
+ --> $DIR/issue-69455.rs:11:1
+ |
+LL | impl Test<u32> for u64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Test<u64> for u64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: consider specifying the type argument in the method call
+ |
+LL | println!("{}", 23u64.test(xs.iter().sum::<S>()));
+ | +++++
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
let b: [u8; 3] = [0u8; 3];
0u16.foo(b); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
//<u16 as Foo<[(); 3]>>::foo(0u16, b);
}
LL | 0u16.foo(b);
| ^^^ cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/issue-69683.rs:30:10
+ |
+LL | 0u16.foo(b);
+ | ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+ |
+note: multiple `impl`s satisfying `u8: Element<_>` found
+ --> $DIR/issue-69683.rs:5:1
+ |
+LL | impl<T> Element<()> for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl<T: Element<S>, S> Element<[S; 3]> for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
fn err() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn arg_pat_closure_err() {
|x| String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
fn local_pat_closure_err() {
fn err_first_arg_pat() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
|x: String| x;
}
fn err_second_arg_pat() {
|x: String| x;
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn err_mid_arg_pat() {
|x: String| x;
|x: String| x;
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
|x: String| x;
|x: String| x;
|x: String| x;
fn err_first_local_pat() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
let _ = String::from("x");
}
fn err_second_local_pat() {
let _ = String::from("x");
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn err_mid_local_pat() {
let _ = String::from("x");
let _ = String::from("x");
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
let _ = String::from("x");
let _ = String::from("x");
let _ = String::from("x");
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:7:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
error[E0282]: type annotations needed
- --> $DIR/issue-72690.rs:11:6
+ --> $DIR/issue-72690.rs:12:6
|
LL | |x| String::from("x".as_ref());
| ^ consider giving this closure parameter a type
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:12:9
+ |
+LL | |x| String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for reference `&_`
+ |
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
+note: required by `from`
+ --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ |
+LL | fn from(_: T) -> Self;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:12:26
+ |
+LL | |x| String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
error[E0283]: type annotations needed for `&T`
- --> $DIR/issue-72690.rs:15:17
+ --> $DIR/issue-72690.rs:18:17
|
LL | let _ = "x".as_ref();
| - ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
| |
| consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
|
- = note: cannot satisfy `str: AsRef<_>`
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:19:5
+ --> $DIR/issue-72690.rs:22:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:25:5
+ --> $DIR/issue-72690.rs:22:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:29:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:33:5
+ --> $DIR/issue-72690.rs:29:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:38:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:41:5
+ --> $DIR/issue-72690.rs:38:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:47:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:47:5
+ --> $DIR/issue-72690.rs:47:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:54:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:55:5
+ --> $DIR/issue-72690.rs:54:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:63:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:63:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error: aborting due to 18 previous errors
Some errors have detailed explanations: E0282, E0283.
For more information about an error, try `rustc --explain E0282`.
| |_^
help: try to construct one of the enum's variants
|
-LL | let x = A::TupleWithFields(3);
- | ~~~~~~~~~~~~~~~~~~
LL | let x = A::Tuple(3);
| ~~~~~~~~
+LL | let x = A::TupleWithFields(3);
+ | ~~~~~~~~~~~~~~~~~~
error[E0532]: expected tuple struct or tuple variant, found enum `A`
--> $DIR/issue-73427.rs:42:12
| |_^
help: try to match against one of the enum's variants
|
-LL | if let A::TupleWithFields(3) = x { }
- | ~~~~~~~~~~~~~~~~~~
LL | if let A::Tuple(3) = x { }
| ~~~~~~~~
+LL | if let A::TupleWithFields(3) = x { }
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 6 previous errors
// check-pass
// edition:2021
-// compile-flags: -Zunstable-options
use std::array::IntoIter;
use std::ops::Deref;
--- /dev/null
+// check-pass
+
+// RSplit<T, P> previously required T: Clone in order to be Clone
+
+struct NotClone;
+
+fn main() {
+ let elements = [NotClone, NotClone, NotClone];
+ let rsplit = elements.rsplit(|_| false);
+ rsplit.clone();
+}
--- /dev/null
+#![feature(let_else)]
+
+fn main() {
+ // FIXME: more precise diagnostics
+ let Some(ref mut meow) = Some(()) else { return };
+ //~^ ERROR: cannot borrow value as mutable, as `val` is not declared as mutable
+}
--- /dev/null
+error[E0596]: cannot borrow value as mutable, as `val` is not declared as mutable
+ --> $DIR/issue-89960.rs:5:14
+ |
+LL | let Some(ref mut meow) = Some(()) else { return };
+ | ---------^^^^^^^^^^^^-----------------------------
+ | | |
+ | | cannot borrow as mutable
+ | help: consider changing this to be mutable: `mut val`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
LL | let true = true && false else { return };
| ^^^^^^^^^^^^^
|
-help: wrap the expression in parenthesis
+help: wrap the expression in parentheses
|
LL | let true = (true && false) else { return };
| + +
LL | let true = true || false else { return };
| ^^^^^^^^^^^^^
|
-help: wrap the expression in parenthesis
+help: wrap the expression in parentheses
|
LL | let true = (true || false) else { return };
| + +
LL | let Some(1) = { Some(1) } else {
| ^
|
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
|
LL | let Some(1) = ({ Some(1) }) else {
| + +
LL | let Some(1) = loop { break Some(1) } else {
| ^
|
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
|
LL | let Some(1) = (loop { break Some(1) }) else {
| + +
LL | let 2 = 1 + match 1 { n => n } else {
| ^
|
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
|
LL | let 2 = 1 + (match 1 { n => n }) else {
| + +
LL | let Some(1) = unsafe { unsafe_fn() } else {
| ^
|
-help: try wrapping the expression in parenthesis
+help: try wrapping the expression in parentheses
|
LL | let Some(1) = (unsafe { unsafe_fn() }) else {
| + +
--- /dev/null
+#![feature(let_else)]
+
+fn main() {
+ let Some(_) = Some(()) else if true {
+ //~^ ERROR conditional `else if` is not supported for `let...else`
+ return;
+ } else {
+ return;
+ };
+}
--- /dev/null
+error: conditional `else if` is not supported for `let...else`
+ --> $DIR/let-else-if.rs:4:33
+ |
+LL | let Some(_) = Some(()) else if true {
+ | ^^ expected `{`
+ |
+help: try placing this code inside a block
+ |
+LL ~ let Some(_) = Some(()) else { if true {
+LL +
+LL + return;
+LL + } else {
+LL + return;
+LL ~ } };
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:3:40
+ |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:5:44
+ |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:7:63
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// run-rustfix
+
+pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:3:47
+ |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | --- --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:5:51
+ |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+ | ------ --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ~~ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:7:70
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | --- --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++ ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
| --- --- these two types are declared with different lifetimes...
LL | *v = x;
| ^ ...but data from `x` flows here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | z.push((x,y));
| ^ ...but data flows into `z` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ex3-both-anon-regions-3.rs:2:15
| --- --- these two types are declared with different lifetimes...
LL | z.push((x,y));
| ^ ...but data flows into `z` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) {
+ | ++++ ++ ++
error: aborting due to 2 previous errors
| --- --- these two types are declared with different lifetimes...
LL | y.push(z);
| ^ ...but data from `z` flows into `y` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | y.push(z);
| ^ ...but data from `z` flows into `y` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | x.push(y);
| ^ ...but data from `y` flows into `x` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
--> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
|
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
- | ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
+ | ------------------------------------------- expected `fn(&'1 i32, &'a i32) -> &'a i32`
...
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
|
- = note: expected `fn(&i32, &'a i32) -> &'a i32`
- found `fn(&i32, &i32) -> &i32`
+ = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
+ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
// --force-warn $LINT causes $LINT (which is deny-by-default) to warn
// despite $LINT being allowed on command line
-// compile-flags: -A const_err --force-warn const_err -Zunstable-options
+// compile-flags: -A const_err --force-warn const_err
// check-pass
const C: i32 = 1 / 0;
// --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn
// despite $LINT being allowed on command line
-// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms -Zunstable-options
+// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms
// check-pass
pub trait SomeTrait {}
// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
// despite being allowed in one submodule (but not the other)
-// compile-flags: --force-warn dead_code -Zunstable-options
+// compile-flags: --force-warn dead_code
// check-pass
mod one {
// --force-warn warnings is an error
-// compile-flags: --force-warn warnings -Zunstable-options
+// compile-flags: --force-warn warnings
// error-pattern: `warnings` lint group is not supported
fn main() {}
error[E0602]: `warnings` lint group is not supported with ´--force-warn´
-error[E0602]: `warnings` lint group is not supported with ´--force-warn´
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0602`.
--- /dev/null
+// check-pass
+// Allowing the code lint should work without warning and
+// the text flow char in the comment should be ignored.
+
+#![allow(text_direction_codepoint_in_comment)]
+
+fn main() {
+ // U+2066 LEFT-TO-RIGHT ISOLATE follows:
+}
--- /dev/null
+// edition:2018
+#![deny(must_not_suspend)] //~ ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+
+async fn other() {}
+
+pub async fn uhoh(m: std::sync::Mutex<()>) {
+ let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+ other().await;
+}
+
+fn main() {
+}
--- /dev/null
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error: `MutexGuard` held across a suspend point, but should not be
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+LL | other().await;
+ | ------------- the value is held across this suspend point
+ |
+note: the lint level is defined here
+ --> $DIR/gated.rs:2:9
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^
+note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// edition:2018
+// run-pass
+
+use std::sync::Mutex;
+
+// Copied from the issue. Allow-by-default for now, so run-pass
+pub async fn foo() {
+ let foo = Mutex::new(1);
+ let lock = foo.lock().unwrap();
+
+ // Prevent mutex lock being held across `.await` point.
+ drop(lock);
+
+ bar().await;
+}
+
+async fn bar() {}
+
+fn main() {}
// edition:2018
+#![feature(must_not_suspend)]
#![deny(must_not_suspend)]
async fn other() {}
error: `MutexGuard` held across a suspend point, but should not be
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
| ------------- the value is held across this suspend point
|
note: the lint level is defined here
- --> $DIR/mutex.rs:2:9
+ --> $DIR/mutex.rs:3:9
|
LL | #![deny(must_not_suspend)]
| ^^^^^^^^^^^^^^^^
note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
// edition:2018
// run-pass
#![feature(must_not_suspend)]
+#![warn(must_not_suspend)]
#[must_not_suspend = "You gotta use Umm's, ya know?"]
struct Umm {
warning: `Umm` held across a suspend point, but should not be
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
LL | other().await;
| ------------- the value is held across this suspend point
|
- = note: `#[warn(must_not_suspend)]` on by default
+note: the lint level is defined here
+ --> $DIR/warn.rs:4:9
+ |
+LL | #![warn(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^
note: You gotta use Umm's, ya know?
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":597,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));
+{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":577,"byte_end":578,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));
--> $DIR/unused_parens_json_suggestion.rs:16:14
|
LL | let _a = (1 / (2 + 3));
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":501,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":481,"byte_end":482,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {
--> $DIR/unused_parens_remove_json_suggestion.rs:17:8
|
LL | if (_b) {
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":632,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":612,"byte_end":613,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {
--> $DIR/unused_parens_remove_json_suggestion.rs:28:7
|
LL | if(c) {
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":712,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":692,"byte_end":693,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){
--> $DIR/unused_parens_remove_json_suggestion.rs:32:8
|
LL | if (c){
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:36:11
|
LL | while (false && true){
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":802,"byte_end":803,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {
--> $DIR/unused_parens_remove_json_suggestion.rs:37:12
|
LL | if (c) {
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":919,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":899,"byte_end":900,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {
--> $DIR/unused_parens_remove_json_suggestion.rs:43:10
|
LL | while(true && false) {
|
"}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":988,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":968,"byte_end":969,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){
--> $DIR/unused_parens_remove_json_suggestion.rs:44:18
|
LL | for _ in (0 .. 3){
|
"}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1089,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1069,"byte_end":1070,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {
--> $DIR/unused_parens_remove_json_suggestion.rs:49:14
|
LL | for _ in (0 .. 3) {
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1148,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1128,"byte_end":1129,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {
--> $DIR/unused_parens_remove_json_suggestion.rs:50:15
|
LL | while (true && false) {
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
--> $DIR/ambiguity-legacy-vs-modern.rs:31:9
|
LL | m!()
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `m` could refer to the macro defined here
--> $DIR/ambiguity-legacy-vs-modern.rs:26:5
|
LL | macro m() { 0 }
| ^^^^^^^^^^^^^^^
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
--> $DIR/ambiguity-legacy-vs-modern.rs:43:5
|
LL | m!()
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `m` could refer to the macro defined here
--> $DIR/ambiguity-legacy-vs-modern.rs:40:9
|
-error[E0659]: `std` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/macro-path-prelude-shadowing.rs:29:9
|
LL | std::panic!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `std` could refer to a built-in crate
note: `std` could also refer to the module imported here
--> $DIR/macro-path-prelude-shadowing.rs:27:9
= note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
= note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `foo` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `foo` is ambiguous
--> $DIR/macro-shadowing.rs:17:1
|
LL | foo!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `foo` could refer to the macro defined here
--> $DIR/macro-shadowing.rs:10:5
|
--- /dev/null
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules! foo {
+ //~^ ERROR expected `!` after `macro_rules`
+ () => {};
+}
+
+macro_rules! bar {
+ //~^ ERROR expected `!` after `macro_rules`
+ //~^^ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules foo {
+ //~^ ERROR expected `!` after `macro_rules`
+ () => {};
+}
+
+macro_rules bar! {
+ //~^ ERROR expected `!` after `macro_rules`
+ //~^^ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+error: expected `!` after `macro_rules`
+ --> $DIR/missing-bang-in-decl.rs:5:1
+ |
+LL | macro_rules foo {
+ | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: expected `!` after `macro_rules`
+ --> $DIR/missing-bang-in-decl.rs:10:1
+ |
+LL | macro_rules bar! {
+ | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: macro names aren't followed by a `!`
+ --> $DIR/missing-bang-in-decl.rs:10:16
+ |
+LL | macro_rules bar! {
+ | ^ help: remove the `!`
+
+error: aborting due to 3 previous errors
+
-error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `bar` is ambiguous
--> $DIR/out-of-order-shadowing.rs:5:1
|
LL | bar!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `bar` could refer to the macro defined here
--> $DIR/out-of-order-shadowing.rs:4:1
|
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:101:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:139:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:148:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:164:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:180:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:218:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:232:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:262:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:104:17
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:147:33
|
LL | macro gen_invoc() { m!() }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:156:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:172:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:190:17
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:233:33
|
LL | macro gen_invoc() { m!() }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
LL | impl<'a> A for (&'static (), &'a ()) {}
| ^ cannot infer type for tuple `(&'static (), &'a ())`
|
- = note: cannot satisfy `(&'static (), &'a ()): A`
+note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found
+ --> $DIR/region-overlap.rs:5:1
+ |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A`
--> $DIR/region-overlap.rs:4:1
|
LL | impl<'a> A for (&'a (), &'static ()) {}
| ^ cannot infer type for tuple `(&'a (), &'static ())`
|
- = note: cannot satisfy `(&'a (), &'static ()): A`
+note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found
+ --> $DIR/region-overlap.rs:5:1
+ |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A`
--> $DIR/region-overlap.rs:4:1
|
// run-pass
// edition:2021
-// compile-flags: -Zunstable-options
// regression test for https://github.com/rust-lang/rust/pull/85678
// we couldn't infer the type of the vector just based on calling foo()...
let mut x = Vec::new();
//~^ ERROR type annotations needed
- x.foo();
+ x.foo(); //~ ERROR type annotations needed
}
fn m2() {
| |
| consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+error[E0283]: type annotations needed
+ --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
+ |
+LL | x.foo();
+ | ^^^ cannot infer type for struct `Vec<_>`
+ |
+note: multiple `impl`s satisfying `Vec<_>: Foo` found
+ --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1
+ |
+LL | impl Foo for Vec<usize> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo for Vec<isize> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
|
LL | let y: usize = x.foo().try_into().unwrap();
| ++++++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0282, E0308.
+Some errors have detailed explanations: E0282, E0283, E0308.
For more information about an error, try `rustc --explain E0282`.
+++ /dev/null
-// compile-flags: -Zunleash-the-miri-inside-of-you
-
-// This test demonstrates a shortcoming of the `MaybeMutBorrowedLocals` analysis. It does not
-// handle code that takes a reference to one field of a struct, then use pointer arithmetic to
-// transform it to another field of that same struct that may have interior mutability. For now,
-// this is UB, but this may change in the future. See [rust-lang/unsafe-code-guidelines#134].
-//
-// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
-
-#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)]
-
-use std::cell::UnsafeCell;
-use std::intrinsics::rustc_peek;
-
-#[repr(C)]
-struct PartialInteriorMut {
- zst: [i32; 0],
- cell: UnsafeCell<i32>,
-}
-
-#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)]
-const BOO: i32 = {
- let x = PartialInteriorMut {
- zst: [],
- cell: UnsafeCell::new(0),
- };
-
- let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable.
-
- let rmut_cell = unsafe {
- // Take advantage of the fact that `zst` and `cell` are at the same location in memory.
- // This trick would work with any size type if miri implemented `ptr::offset`.
- let p_cell = p_zst as *const UnsafeCell<i32>;
-
- let pmut_cell = (*p_cell).get();
- &mut *pmut_cell
- };
-
- *rmut_cell = 42; // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
- let val = *rmut_cell;
- rustc_peek(x); //~ ERROR rustc_peek: bit not set
-
- val
-};
-
-fn main() {
- println!("{}", BOO);
-}
+++ /dev/null
-error: rustc_peek: bit not set
- --> $DIR/indirect-mutation-offset.rs:41:5
- |
-LL | rustc_peek(x);
- | ^^^^^^^^^^^^^
-
-error: stop_after_dataflow ended compilation
-
-error: aborting due to 2 previous errors
-
--> $DIR/issue-75361-mismatched-impl.rs:18:3
|
LL | fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
- | --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
+ | --------------------------------------------------------------------- expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
...
LL | fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
|
- = note: expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
- found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+ = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/issue-75361-mismatched-impl.rs:12:55
|
error[E0277]: `NoSync` cannot be shared between threads safely
- --> $DIR/mutable-enum-indirect.rs:17:5
+ --> $DIR/mutable-enum-indirect.rs:17:9
|
LL | bar(&x);
- | ^^^ `NoSync` cannot be shared between threads safely
+ | --- ^^ `NoSync` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`
note: required because it appears within the type `Foo`
struct Foo<'a>(&'a [u8]);
impl<'a> Foo<'a> {
- fn make_it(&self) -> impl Iterator<Item = u8> { //~ ERROR lifetime may not live
+ fn make_it(&self) -> impl Iterator<Item = u8> {
+ //~^ ERROR: captures lifetime that does not appear in bounds
self.0.iter().copied()
}
}
-error: lifetime may not live long enough
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/issue-73159-rpit-static.rs:9:26
|
LL | impl<'a> Foo<'a> {
- | -- lifetime `'a` defined here
+ | -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here
LL | fn make_it(&self) -> impl Iterator<Item = u8> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0700`.
--- /dev/null
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {
+ type A;
+
+ fn f() -> Self::A;
+}
+
+pub trait Tr2<'a, 'b> {}
+
+pub struct A<T>(T);
+pub trait Tr {
+ type B;
+}
+
+impl<'a, 'b, T: Tr<B = dyn Tr2<'a, 'b>>> Trait for A<T> {
+ type A = impl core::fmt::Debug;
+
+ fn f() -> Self::A {}
+}
+
+fn main() {}
impl<'a, T> Foo<'a> for T { }
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-//~^ ERROR explicit lifetime required in the type of `x` [E0621]
+//~^ ERROR captures lifetime that does not appear in bounds
x
}
-error[E0621]: explicit lifetime required in the type of `x`
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/impl-trait-captures.rs:10:25
|
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
- | ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required
+ | -- ^^^^^^^^^^^^
+ | |
+ | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
|
-help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x`
+help: to declare that the `impl Trait` captures ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)), you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0))` lifetime bound
|
-LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> {
- | ~~~~~~~~~~~~~~~~~~~~~~
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) {
+ | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0621`.
+For more information about this error, try `rustc --explain E0700`.
error[E0277]: `NoSend` cannot be sent between threads safely
- --> $DIR/no_send-enum.rs:16:5
+ --> $DIR/no_send-enum.rs:16:9
|
LL | bar(x);
- | ^^^ `NoSend` cannot be sent between threads safely
+ | --- ^ `NoSend` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Foo`, the trait `Send` is not implemented for `NoSend`
note: required because it appears within the type `Foo`
error[E0277]: `NoSync` cannot be shared between threads safely
- --> $DIR/no_share-enum.rs:14:5
+ --> $DIR/no_share-enum.rs:14:9
|
LL | bar(x);
- | ^^^ `NoSync` cannot be shared between threads safely
+ | --- ^ `NoSync` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Foo`, the trait `Sync` is not implemented for `NoSync`
note: required because it appears within the type `Foo`
|
help: the following are the possible correct uses
|
-LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
- |
LL | #[rustc_on_unimplemented = "message"]
|
+LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
+ |
error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
--> $DIR/bad-annotation.rs:22:1
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,file
+
+fn main() {
+ panic!("column-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:6:0
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+ panic!("file-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'file-redacted', <redacted>:6:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=file,column
+
+fn main() {
+ panic!("line-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'line-redacted', $DIR/location-detail-panic-no-line.rs:0:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+ let opt: Option<u32> = None;
+ opt.unwrap();
+}
--- /dev/null
+thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:7:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(ICE)]
+pub fn derive(_: TokenStream) -> TokenStream {
+ r#"#[allow(missing_docs)] struct X { }"#.parse().unwrap()
+}
--- /dev/null
+// aux-build:issue-89971-outer-attr-following-inner-attr-ice.rs
+
+#[macro_use]
+extern crate issue_89971_outer_attr_following_inner_attr_ice;
+
+fn main() {
+ Mew();
+ X {};
+}
+
+#![deny(missing_docs)]
+//~^ ERROR an inner attribute is not permitted in this context
+#[derive(ICE)]
+#[deny(missing_docs)]
+struct Mew();
--- /dev/null
+error: an inner attribute is not permitted in this context
+ --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:11:1
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | struct Mew();
+ | ------------- the inner attribute doesn't annotate this struct
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the struct, change the attribute from inner to outer style
+ |
+LL - #![deny(missing_docs)]
+LL + #[deny(missing_docs)]
+ |
+
+error: aborting due to previous error
+
for ( elem in vec ) {
//~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in`
- //~| ERROR unexpected parenthesis surrounding `for` loop head
+ //~| ERROR unexpected parentheses surrounding `for` loop head
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
}
}
LL | for ( elem in vec ) {
| ^^ expected one of `)`, `,`, `@`, or `|`
-error: unexpected parenthesis surrounding `for` loop head
+error: unexpected parentheses surrounding `for` loop head
--> $DIR/recover-for-loop-parens-around-head.rs:10:9
|
LL | for ( elem in vec ) {
| ^ ^
|
-help: remove parenthesis in `for` loop
+help: remove parentheses in `for` loop
|
LL - for ( elem in vec ) {
LL + for elem in vec {
--- /dev/null
+fn main() {
+ // if access_level != "user" { // Check if admin
+ //~^ ERROR unicode codepoint changing visible direction of text present in comment
+ println!("us\u{202B}e\u{202A}r");
+ println!("{:?}", r#"us\u{202B}e\u{202A}r"#);
+ println!("{:?}", b"us\u{202B}e\u{202A}r");
+ //~^ ERROR unicode escape in byte string
+ //~| ERROR unicode escape in byte string
+ println!("{:?}", br##"us\u{202B}e\u{202A}r"##);
+
+ println!("{:?}", "/* } if isAdmin begin admins only ");
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+
+ println!("{:?}", r##"/* } if isAdmin begin admins only "##);
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+ println!("{:?}", b"/* } if isAdmin begin admins only ");
+ //~^ ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ //~^ ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ println!("{:?}", '');
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+}
+
+//"/* } if isAdmin begin admins only */"
+//~^ ERROR unicode codepoint changing visible direction of text present in comment
+
+/** ''); */fn foo() {}
+//~^ ERROR unicode codepoint changing visible direction of text present in doc comment
+
+/**
+ *
+ * ''); */fn bar() {}
+//~^^^ ERROR unicode codepoint changing visible direction of text present in doc comment
--- /dev/null
+error: unicode escape in byte string
+ --> $DIR/unicode-control-codepoints.rs:6:26
+ |
+LL | println!("{:?}", b"us\u{202B}e\u{202A}r");
+ | ^^^^^^^^ unicode escape in byte string
+ |
+ = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: unicode escape in byte string
+ --> $DIR/unicode-control-codepoints.rs:6:35
+ |
+LL | println!("{:?}", b"us\u{202B}e\u{202A}r");
+ | ^^^^^^^^ unicode escape in byte string
+ |
+ = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:26
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{202e}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:30
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2066}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:41
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2069}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9 begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:43
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2066}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:29
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{202e}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:33
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2066}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:44
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2069}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:46
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2066}'
+
+error: unicode codepoint changing visible direction of text present in comment
+ --> $DIR/unicode-control-codepoints.rs:2:5
+ |
+LL | // if access_level != "user" { // Check if admin
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | ||
+ | | |'\u{202a}'
+ | | '\u{202b}'
+ | this comment contains invisible unicode text flow control codepoints
+ |
+ = note: `#[deny(text_direction_codepoint_in_comment)]` on by default
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in comment
+ --> $DIR/unicode-control-codepoints.rs:30:1
+ |
+LL | //"/* } if isAdmin begin admins only */"
+ | ^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this comment contains invisible unicode text flow control codepoints
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:11:22
+ |
+LL | println!("{:?}", "/* } if isAdmin begin admins only ");
+ | ^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this literal contains invisible unicode text flow control codepoints
+ |
+ = note: `#[deny(text_direction_codepoint_in_literal)]` on by default
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", "/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only ");
+ | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:14:22
+ |
+LL | println!("{:?}", r##"/* } if isAdmin begin admins only "##);
+ | ^^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this literal contains invisible unicode text flow control codepoints
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", r##"/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only "##);
+ | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:26:22
+ |
+LL | println!("{:?}", '');
+ | ^-
+ | ||
+ | |'\u{202e}'
+ | this literal contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", '\u{202e}');
+ | ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in doc comment
+ --> $DIR/unicode-control-codepoints.rs:33:1
+ |
+LL | /** ''); */fn foo() {}
+ | ^^^^^^^^^^^^ this doc comment contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = note: if their presence wasn't intentional, you can remove them
+ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: unicode codepoint changing visible direction of text present in doc comment
+ --> $DIR/unicode-control-codepoints.rs:36:1
+ |
+LL | / /**
+LL | | *
+LL | | * ''); */fn bar() {}
+ | |___________^ this doc comment contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = note: if their presence wasn't intentional, you can remove them
+ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: aborting due to 17 previous errors
+
// the tuple struct pattern, has 0 fields, but requires 1 field.
//
// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
-// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parentheses be added.
//
// However, we did not account for the expected type being different than the tuple pattern type.
// This caused an issue when the tuple pattern type (`P<T>`) was generic.
--- /dev/null
+// edition:2021
+#![allow(incomplete_features)]
+#![allow(unreachable_code)]
+#![feature(const_async_blocks)]
+#![feature(inline_const)]
+
+fn main() {
+ match loop {} {
+ const { || {} } => {}, //~ ERROR cannot be used in patterns
+ }
+ match loop {} {
+ const { async {} } => {}, //~ ERROR cannot be used in patterns
+ }
+}
--- /dev/null
+error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:9:9
+ |
+LL | const { || {} } => {},
+ | ^^^^^^^^^^^^^^^
+
+error: `impl Future` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:12:9
+ |
+LL | const { async {} } => {},
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
#[rustc_polymorphize_error]
fn foo<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
where
I: Iterator<Item = T>,
{
#[rustc_polymorphize_error]
fn baz<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
where
std::iter::Repeat<I>: Iterator<Item = T>,
{
#[rustc_polymorphize_error]
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
+ //~^ ERROR item has unused generic parameters
}
}
#[rustc_polymorphize_error]
fn quux<A, B, C: Default>() -> usize
+//~^ ERROR item has unused generic parameters
where
A: Baz<B>,
B: Baz<C>,
#[rustc_polymorphize_error]
fn foobar<F, G>() -> usize
+//~^ ERROR item has unused generic parameters
where
(): Foobar<F, G>,
{
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:14:4
+ |
+LL | fn foo<I, T>(_: I)
+ | ^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:23:4
+ |
+LL | fn baz<I, T>(_: I)
+ | ^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:44:19
+ |
+LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+ | - - generic parameter `E` is unused
+ | |
+ | generic parameter `I` is unused
+...
+LL | self.find(|_| true)
+ | ^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:58:4
+ |
+LL | fn quux<A, B, C: Default>() -> usize
+ | ^^^^ - - generic parameter `B` is unused
+ | |
+ | generic parameter `A` is unused
+
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:75:4
+ |
+LL | fn foobar<F, G>() -> usize
+ | ^^^^^^ - generic parameter `F` is unused
+
error: item has unused generic parameters
--> $DIR/predicates.rs:9:4
|
LL | fn bar<I>() {
| ^^^ - generic parameter `I` is unused
-error: aborting due to previous error
+error: aborting due to 6 previous errors
error: requires `sized` lang_item
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0432, E0603.
For more information about an error, try `rustc --explain E0432`.
error: requires `sized` lang_item
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: requires `sized` lang_item
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0432`.
// aux-crate:priv:priv_dep=priv_dep.rs
// aux-build:pub_dep.rs
+// compile-flags: -Zunstable-options
#![deny(exported_private_dependencies)]
// This crate is a private dependency
error: type `OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:20:5
+ --> $DIR/pub-priv1.rs:21:5
|
LL | pub field: OtherType,
| ^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/pub-priv1.rs:3:9
+ --> $DIR/pub-priv1.rs:4:9
|
LL | #![deny(exported_private_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: type `OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:27:5
+ --> $DIR/pub-priv1.rs:28:5
|
LL | pub fn pub_fn(param: OtherType) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:34:5
+ --> $DIR/pub-priv1.rs:35:5
|
LL | type Foo: OtherTrait;
| ^^^^^^^^^^^^^^^^^^^^^
}
use deny as allow;
-#[allow(unused)] //~ ERROR `allow` is ambiguous (built-in attribute vs any other name)
+#[allow(unused)] //~ ERROR `allow` is ambiguous
fn builtin_renamed() {}
LL | NonExistent;
| ^^^^^^^^^^^ not found in this scope
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:9:3
|
LL | #[repr(C)]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:11:19
|
LL | #[cfg_attr(all(), repr(C))]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:20:34
|
LL | fn non_macro_expanded_location<#[repr(C)] T>() {
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:24:11
|
LL | #[repr(C)]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `allow` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:38:3
|
LL | #[allow(unused)]
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `allow` could refer to a built-in attribute
note: `allow` could also refer to the built-in attribute imported here
--> $DIR/ambiguous-builtin-attrs.rs:37:5
| ^^^^^^^^^^^^^
= help: use `crate::allow` to refer to this built-in attribute unambiguously
-error[E0659]: `feature` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `feature` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:3:4
|
LL | #![feature(decl_macro)]
| ^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `feature` could refer to a built-in attribute
note: `feature` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
crate::empty_helper
= note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/derive-helper-shadowing.rs:26:13
|
LL | use empty_helper;
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/derive-helper-shadowing.rs:22:10
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/derive-helper-shadowing.rs:19:3
|
LL | #[empty_helper]
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/derive-helper-shadowing.rs:22:10
|
//~| ERROR cannot find type `OuterAttr` in this scope
struct S;
-#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
- //~| WARN cannot find type `OuterDerive` in this scope
+#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+ //~| ERROR cannot find type `OuterDerive` in this scope
//~| WARN this was previously accepted
//~| WARN this was previously accepted
struct Z;
fn inner_block() {
- #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
- //~| WARN cannot find type `OuterDerive` in this scope
+ #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+ //~| ERROR cannot find type `OuterDerive` in this scope
//~| WARN this was previously accepted
//~| WARN this was previously accepted
struct InnerZ;
OuterAttr
= note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
- = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+ = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0412`.
Future incompatibility report: Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
- = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+ = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
warning: cannot find type `FromOutside` in this scope
-// check-pass
// aux-build:pin-project-internal-0.4.0.rs
// compile-flags: -Z span-debug
}
struct Foo;
- impl_macros!(Foo); //~ WARN using an old version
+ impl_macros!(Foo); //~ ERROR using an old version
//~| WARN this was previously
arrays!(Foo);
other!(Foo);
}
struct Foo;
- impl_macros!(Foo); //~ WARN using an old version
+ impl_macros!(Foo); //~ ERROR using an old version
//~| WARN this was previously
- arrays!(Foo); //~ WARN using an old version
+ arrays!(Foo); //~ ERROR using an old version
//~| WARN this was previously
other!(Foo);
}
include!("actix-web/src/extract.rs");
struct Foo;
- tuple_from_req!(Foo); //~ WARN using an old version
+ tuple_from_req!(Foo); //~ ERROR using an old version
//~| WARN this was previously
}
include!("actix-web-2.0.0/src/extract.rs");
struct Foo;
- tuple_from_req!(Foo); //~ WARN using an old version
+ tuple_from_req!(Foo); //~ ERROR using an old version
//~| WARN this was previously
}
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:27:5
+ ::: $DIR/group-compat-hack.rs:26:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:44:5
+ ::: $DIR/group-compat-hack.rs:43:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
--> $DIR/js-sys-0.3.17/src/lib.rs:5:32
|
LL | #[my_macro] struct Two($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:46:5
+ ::: $DIR/group-compat-hack.rs:45:5
|
LL | arrays!(Foo);
| ------------ in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
- = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:55:5
+ ::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:63:5
+ ::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: 5 warnings emitted
+error: aborting due to 5 previous errors
Future incompatibility report: Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:27:5
+ ::: $DIR/group-compat-hack.rs:26:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:44:5
+ ::: $DIR/group-compat-hack.rs:43:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
--> $DIR/js-sys-0.3.17/src/lib.rs:5:32
|
LL | #[my_macro] struct Two($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:46:5
+ ::: $DIR/group-compat-hack.rs:45:5
|
LL | arrays!(Foo);
| ------------ in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
- = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:55:5
+ ::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:63:5
+ ::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:13: 29:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:30:12: 30:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:18: 44:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:48:12: 48:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:55:21: 55:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:63:21: 63:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:71:21: 71:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:78:21: 78:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:84:13: 84:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:26:18: 26:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:25: 21:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:32: 21:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:38: 21:43 (#14) }], span: $DIR/group-compat-hack.rs:21:37: 21:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:44: 21:45 (#14) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:13: 45:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:83:13: 83:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
|
LL | #[empty_helper]
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/helper-attr-blocked-by-import-ambig.rs:10:10
|
-error[E0659]: `identity_attr` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `identity_attr` is ambiguous
--> $DIR/issue-41211.rs:11:4
|
LL | #![identity_attr]
| ^^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `identity_attr` could refer to the attribute macro imported here
--> $DIR/issue-41211.rs:14:5
|
-// check-pass
// aux-build:test-macros.rs
#[macro_use]
extern crate test_macros;
#[derive(Print)]
-enum ProceduralMasqueradeDummyType { //~ WARN using
+enum ProceduralMasqueradeDummyType { //~ ERROR using
//~| WARN this was previously
Input
}
-warning: using `procedural-masquerade` crate
- --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+ --> $DIR/issue-73933-procedural-masquerade.rs:7:6
|
LL | enum ProceduralMasqueradeDummyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
-warning: 1 warning emitted
+error: aborting due to previous error
Future incompatibility report: Future breakage diagnostic:
-warning: using `procedural-masquerade` crate
- --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+ --> $DIR/issue-73933-procedural-masquerade.rs:7:6
|
LL | enum ProceduralMasqueradeDummyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
- span: #0 bytes(100..104),
+ span: #0 bytes(86..90),
},
Ident {
ident: "ProceduralMasqueradeDummyType",
- span: #0 bytes(105..134),
+ span: #0 bytes(91..120),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "Input",
- span: #0 bytes(186..191),
+ span: #0 bytes(173..178),
},
],
- span: #0 bytes(135..193),
+ span: #0 bytes(121..180),
},
]
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
LL | #[C]
| ^ help: a derive helper attribute with a similar name exists: `B`
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:6:3
|
LL | #[B]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:10:3
|
LL | #[B(D)]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:13:3
|
LL | #[B(E = "foo")]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:16:3
|
LL | #[B(arbitrary tokens)]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type PairCoupledTypes: Trait<
+ //~^ ERROR: bounds on `type`s in this context have no effect
+ //~| ERROR: cannot find trait `Trait` in this scope
+ [u32; {
+ static FOO: usize; //~ ERROR: free static item without body
+ }],
+> = impl Trait<
+ //~^ ERROR: cannot find trait `Trait` in this scope
+ [u32; {
+ static FOO: usize; //~ ERROR: free static item without body
+ }],
+>;
+
+fn main() {}
--- /dev/null
+error: bounds on `type`s in this context have no effect
+ --> $DIR/issue-83479.rs:3:24
+ |
+LL | type PairCoupledTypes: Trait<
+ | ________________________^
+LL | |
+LL | |
+LL | | [u32; {
+LL | | static FOO: usize;
+LL | | }],
+LL | | > = impl Trait<
+ | |_^
+
+error: free static item without body
+ --> $DIR/issue-83479.rs:7:9
+ |
+LL | static FOO: usize;
+ | ^^^^^^^^^^^^^^^^^-
+ | |
+ | help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+ --> $DIR/issue-83479.rs:12:9
+ |
+LL | static FOO: usize;
+ | ^^^^^^^^^^^^^^^^^-
+ | |
+ | help: provide a definition for the static: `= <expr>;`
+
+error[E0405]: cannot find trait `Trait` in this scope
+ --> $DIR/issue-83479.rs:3:24
+ |
+LL | type PairCoupledTypes: Trait<
+ | ^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `Trait` in this scope
+ --> $DIR/issue-83479.rs:9:10
+ |
+LL | > = impl Trait<
+ | ^^^^^ not found in this scope
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
--- /dev/null
+mod list {
+ pub use self::List::Cons;
+
+ pub enum List<T> {
+ Cons(T, Box<List<T>>),
+ }
+}
+
+mod alias {
+ use crate::list::List;
+
+ pub type Foo = List<String>;
+}
+
+fn foo(l: crate::alias::Foo) {
+ match l {
+ Cons(..) => {} //~ ERROR: cannot find tuple struct or tuple variant `Cons` in this scope
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0531]: cannot find tuple struct or tuple variant `Cons` in this scope
+ --> $DIR/issue-90113.rs:17:9
+ |
+LL | Cons(..) => {}
+ | ^^^^ not found in this scope
+ |
+help: consider importing this tuple variant
+ |
+LL | use list::List::Cons;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0531`.
| |
| call expression requires function
|
-help: `Z::Unit` is a unit variant, you need to write it without the parenthesis
+help: `Z::Unit` is a unit variant, you need to write it without the parentheses
|
LL | let _ = Z::Unit;
| ~~~~~~~
| |
| call expression requires function
|
-help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis
+help: `m::E::Unit` is a unit variant, you need to write it without the parentheses
|
LL | let _: E = m::E::Unit;
| ~~~~~~~~~~
| |
| call expression requires function
|
-help: `E::Unit` is a unit variant, you need to write it without the parenthesis
+help: `E::Unit` is a unit variant, you need to write it without the parentheses
|
LL | let _: E = E::Unit;
| ~~~~~~~
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:33:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:34:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:36:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:44:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:48:16
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:49:17
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:50:25
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:51:25
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:54:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:57:15
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:59:11
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:61:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:65:8
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:69:8
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:76:8
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:84:8
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:90:19
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:94:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:97:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:98:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:100:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:108:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:112:19
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:113:20
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:114:28
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:115:28
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:118:15
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:121:18
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:123:14
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:125:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:129:11
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:133:11
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:140:11
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:148:11
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:154:22
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:168:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:170:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:171:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:173:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:181:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:185:13
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:186:14
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:187:22
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:190:9
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:192:12
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:193:8
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:194:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:196:6
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:200:6
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:204:6
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:215:17
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:219:17
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:223:17
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
error: `let` expressions are not supported here
--> $DIR/disallowed-positions.rs:233:17
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if`- and `while`-expressions
- = note: as well as when nested within `&&` and parenthesis in those conditions
+ = note: as well as when nested within `&&` and parentheses in those conditions
warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/disallowed-positions.rs:20:12
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
--> $DIR/const-drop-fail.rs:49:5
|
-LL | const _: () = check($exp);
- | ----- required by a bound introduced by this call
-...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
--> $DIR/const-drop-fail.rs:49:5
|
-LL | const _: () = check($exp);
- | ----- required by a bound introduced by this call
-...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
-note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:10
+note: required by `Foo::c`
+ --> $DIR/trait-where-clause.rs:9:5
|
LL | fn c<T: ~const Bar>();
- | ^ required by this bound in `Foo::c`
+ | ^^^^^^^^^^^^^^^^^^^^^^
help: consider further restricting this bound
|
LL | const fn test1<T: ~const Foo + Bar + Bar>() {
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
-note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:10
+note: required by `Foo::c`
+ --> $DIR/trait-where-clause.rs:9:5
|
LL | fn c<T: ~const Bar>();
- | ^ required by this bound in `Foo::c`
+ | ^^^^^^^^^^^^^^^^^^^^^^
help: consider further restricting this bound
|
LL | fn test3<T: Foo + Bar>() {
println!("{:#?}", output);
let stderr = std::str::from_utf8(&output.stderr);
assert!(stderr.map(|v| {
- v.ends_with("drop of the panic payload panicked")
+ v.ends_with("fatal runtime error: drop of the panic payload panicked\n")
}).unwrap_or(false));
}
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-macros-nested.rs:8:13
|
LL | pub use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-macros.rs:7:5
|
LL | use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-nested.rs:8:13
|
LL | pub use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity.rs:5:5
|
LL | use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
--- /dev/null
+pub trait Trait { fn no_op(&self); }
--- /dev/null
+pub trait Deserialize {
+ fn deserialize();
+}
-error[E0659]: `sub` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `sub` is ambiguous
--> $DIR/block-scoped-shadow-nested.rs:16:13
|
LL | use sub::bar;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `sub` could refer to the module imported here
--> $DIR/block-scoped-shadow-nested.rs:14:9
|
-error[E0659]: `Foo` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `Foo` is ambiguous
--> $DIR/block-scoped-shadow.rs:11:9
|
LL | use Foo::*;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `Foo` could refer to the enum defined here
--> $DIR/block-scoped-shadow.rs:10:5
|
| ^^^^^^^^^^^
= help: use `crate::Foo` to refer to this enum unambiguously
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/block-scoped-shadow.rs:18:9
|
LL | use std as foo;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `std` could refer to the enum defined here
--> $DIR/block-scoped-shadow.rs:17:5
|
| ^^^^^^^^^^^
= help: use `crate::std` to refer to this struct unambiguously
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/block-scoped-shadow.rs:18:9
|
LL | use std as foo;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `std` could refer to the function defined here
--> $DIR/block-scoped-shadow.rs:16:5
|
--- /dev/null
+// run-pass
+// edition:2018
+// aux-crate:issue_55779_extern_trait=issue-55779-extern-trait.rs
+
+use issue_55779_extern_trait::Trait;
+
+struct Local;
+struct Helper;
+
+impl Trait for Local {
+ fn no_op(&self)
+ {
+ // (Unused) extern crate declaration necessary to reproduce bug
+ extern crate issue_55779_extern_trait;
+
+ // This one works
+ // impl Trait for Helper { fn no_op(&self) { } }
+
+ // This one infinite-loops
+ const _IMPL_SERIALIZE_FOR_HELPER: () = {
+ // (extern crate can also appear here to reproduce bug,
+ // as in originating example from serde)
+ impl Trait for Helper { fn no_op(&self) { } }
+ };
+
+ }
+}
+
+fn main() { }
-error[E0659]: `issue_56596` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56596` is ambiguous
--> $DIR/issue-56596.rs:12:5
|
LL | use issue_56596;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56596` could refer to a crate passed with `--extern`
= help: use `::issue_56596` to refer to this crate unambiguously
note: `issue_56596` could also refer to the module imported here
--- /dev/null
+// edition:2018
+// aux-crate:issue_87932_a=issue-87932-a.rs
+
+pub struct A {}
+
+impl issue_87932_a::Deserialize for A {
+ fn deserialize() {
+ extern crate issue_87932_a as _a;
+ }
+}
+
+fn main() {
+ A::deserialize();
+ //~^ ERROR no function or associated item named `deserialize` found for struct `A`
+}
--- /dev/null
+error[E0599]: no function or associated item named `deserialize` found for struct `A` in the current scope
+ --> $DIR/issue-87932.rs:13:8
+ |
+LL | pub struct A {}
+ | ------------ function or associated item `deserialize` not found for this
+...
+LL | A::deserialize();
+ | ^^^^^^^^^^^ function or associated item not found in `A`
+ |
+ = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use <crate::A as issue_87932_a::Deserialize>::deserialize::_a::Deserialize;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
LL | pub use legacy_macro as _;
| ^^^^^^^^^^^^^^^^^
-error[E0659]: `legacy_macro` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `legacy_macro` is ambiguous
--> $DIR/macro-rules.rs:31:13
|
LL | use legacy_macro as _;
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `legacy_macro` could refer to the macro defined here
--> $DIR/macro-rules.rs:28:9
|
}
fn main() {
- io::stdout();
- self::std::io::stdout();
- foo::my_std::io::stdout();
- bar::std::io::stdout();
+ let _ = io::stdout();
+ let _ = self::std::io::stdout();
+ let _ = foo::my_std::io::stdout();
+ let _ = bar::std::io::stdout();
}
| the method is available for `Rc<u8>` here
|
= help: items from traits can only be used if the trait is in scope
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Box::new(3u8).try_into().unwrap();
// check-pass
// edition:2021
-// compile-flags: -Zunstable-options
fn main() {
let _: u16 = 123i32.try_into().unwrap();
// check-pass
// run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
#![warn(rust_2021_prefixes_incompatible_syntax)]
// check-pass
// run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
#![warn(rust_2021_prefixes_incompatible_syntax)]
// run-pass
// This test is just checking that we won't ICE if logging is turned
-// on; don't bother trying to compare that (copious) output. (Note
-// also that this test potentially silly, since we do not build+test
-// debug versions of rustc as part of our continuous integration
-// process...)
+// on; don't bother trying to compare that (copious) output.
//
// dont-check-compiler-stdout
// dont-check-compiler-stderr
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
- |
-LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | - ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
- | |
- | let's call the lifetime of this reference `'1`
- |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
- |
-LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
- | ++++
-
-error: aborting due to previous error
-
impl Foo {
async fn f(self: Pin<&Self>) -> impl Clone { self }
- //~^ ERROR E0759
+ //~^ ERROR: captures lifetime that does not appear in bounds
}
fn main() {
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:37
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here
- | | |
- | | this data with an anonymous lifetime `'_`...
- | ...is captured here...
+ | - ^^^^^^^^^^
+ | |
+ | hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
|
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
- |
-LL | fn f(self: Pin<&Self>) -> impl Clone { self }
- | - ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
- | |
- | let's call the lifetime of this reference `'1`
- |
-help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
- |
-LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
- | ++++
-
-error: aborting due to previous error
-
struct Foo;
impl Foo {
- fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759
+ fn f(self: Pin<&Self>) -> impl Clone { self }
+ //~^ ERROR: captures lifetime that does not appear in bounds
}
fn main() {
-error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
- --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
- |
-LL | fn f(self: Pin<&Self>) -> impl Clone { self }
- | ---------- ^^^^ ...is captured here...
- | |
- | this data with an anonymous lifetime `'_`...
- |
-note: ...and is required to live as long as `'static` here
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
- | ^^^^^^^^^^
-help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound
+ | ----- ^^^^^^^^^^
+ | |
+ | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
+ |
+help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
|
LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ++++
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0759`.
+For more information about this error, try `rustc --explain E0700`.
|
help: consider importing one of these items
|
-LL | use std::num::NonZeroU32;
- |
LL | use core::num::NonZeroU32;
|
+LL | use std::num::NonZeroU32;
+ |
error: aborting due to previous error
-error[E0597]: `val` does not live long enough
+error[E0515]: cannot return reference to function parameter `val`
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
|
-LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
- | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
LL | val.use_self()
- | ^^^^^^^^^^^^^^ borrowed value does not live long enough
-LL | }
- | - `val` dropped here while still borrowed
- |
-help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
- |
-LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
- | ++++
+ | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
error[E0515]: cannot return reference to function parameter `val`
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
impl Bar for i32 {}
fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
- val.use_self() //~ ERROR E0597
+ val.use_self() //~ ERROR cannot return reference to function parameter
}
}
-error[E0597]: `val` does not live long enough
+error[E0515]: cannot return reference to function parameter `val`
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
|
-LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
- | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
LL | val.use_self()
- | ^^^^^^^^^^^^^^ borrowed value does not live long enough
-LL | }
- | - `val` dropped here while still borrowed
- |
-help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
- |
-LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
- | ++++
+ | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function
error[E0515]: cannot return reference to function parameter `val`
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0515, E0597.
-For more information about an error, try `rustc --explain E0515`.
+For more information about this error, try `rustc --explain E0515`.
error[E0277]: the trait bound `&str: From<String>` is not satisfied
- --> $DIR/into-str.rs:4:5
+ --> $DIR/into-str.rs:4:9
|
LL | foo(String::new());
- | ^^^ the trait `From<String>` is not implemented for `&str`
+ | --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`
+ | |
+ | required by a bound introduced by this call
|
= note: to coerce a `String` into a `&str`, use `&*` as a prefix
= note: required because of the requirements on the impl of `Into<&str>` for `String`
|
= help: the trait `Sized` is not implemented for `dyn Fn()`
note: required by a bound in `f_sized`
- --> $DIR/issue-84973-blacklist.rs:9:15
+ --> $DIR/issue-84973-blacklist.rs:9:12
|
LL | fn f_sized<T: Sized>(t: T) {}
- | ^^^^^ required by this bound in `f_sized`
+ | ^ required by this bound in `f_sized`
error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
--> $DIR/issue-84973-blacklist.rs:27:12
--- /dev/null
+// Checks that we do not ICE when comparing `Self` to `Pin`
+// edition:2021
+
+struct S;
+
+impl S {
+ fn foo(_: Box<Option<S>>) {}
+ fn bar() {
+ Self::foo(None) //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-90213-expected-boxfuture-self-ice.rs:9:19
+ |
+LL | Self::foo(None)
+ | ^^^^ expected struct `Box`, found enum `Option`
+ |
+ = note: expected struct `Box<Option<S>>`
+ found enum `Option<_>`
+ = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+help: store this in the heap by calling `Box::new`
+ |
+LL | Self::foo(Box::new(None))
+ | +++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error: lifetime may not live long enough
- --> $DIR/trait-object-nested-in-impl-trait.rs:27:23
+ --> $DIR/trait-object-nested-in-impl-trait.rs:28:9
|
-LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
- | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
- | |
- | let's call the lifetime of this reference `'1`
+LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | - let's call the lifetime of this reference `'1`
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________^ returning this value requires that `'1` must outlive `'static`
|
help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound
|
| |_________^ returning this value requires that `'a` must outlive `'static`
error: lifetime may not live long enough
- --> $DIR/trait-object-nested-in-impl-trait.rs:60:30
+ --> $DIR/trait-object-nested-in-impl-trait.rs:61:9
|
-LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
- | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
- | |
- | lifetime `'a` defined here
+LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
+ | -- lifetime `'a` defined here
+LL | / Iter {
+LL | | current: None,
+LL | | remaining: self.0.iter(),
+LL | | }
+ | |_________^ returning this value requires that `'a` must outlive `'static`
|
help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
|
-error[E0277]: `[i32]` is not an iterator
+error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
LL | for _ in &mut v[1..] {
| ++++
-error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
+error[E0277]: `[i32]` is not an iterator
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
LL | for _ in &mut v[1..] {
| ++++
-error[E0277]: `[K]` is not an iterator
+error[E0277]: the size for values of type `[K]` cannot be known at compilation time
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
LL | for i2 in &mut v2[1..] {
| ++++
-error[E0277]: the size for values of type `[K]` cannot be known at compilation time
+error[E0277]: `[K]` is not an iterator
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
| |
| call expression requires function
|
-help: if you meant to create this closure and immediately call it, surround the closure with parenthesis
+help: if you meant to create this closure and immediately call it, surround the closure with parentheses
|
LL | let _ = (||{})();
| + +
--- /dev/null
+// Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions
+// Edition 2021 change
+// edition:2018
+
+fn test() {
+ let _i: i16 = 0_i32.try_into().unwrap();
+ //~^ ERROR no method named `try_into` found for type `i32` in the current scope
+ //~| NOTE method not found in `i32`
+ //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+
+ let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE not found in this scope
+ //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+
+ let _i: i16 = TryInto::try_into(0_i32).unwrap();
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE not found in this scope
+ //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+
+ let _v: Vec<_> = FromIterator::from_iter(&[1]);
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+}
+
+fn main() {
+ test();
+}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared type `TryFrom`
+ --> $DIR/suggest-tryinto-edition-change.rs:11:19
+ |
+LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+ | ^^^^^^^ not found in this scope
+ |
+ = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+ = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+ |
+LL | use core::convert::TryFrom;
+ |
+LL | use std::convert::TryFrom;
+ |
+
+error[E0433]: failed to resolve: use of undeclared type `TryInto`
+ --> $DIR/suggest-tryinto-edition-change.rs:17:19
+ |
+LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
+ | ^^^^^^^ not found in this scope
+ |
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+ = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+ |
+LL | use core::convert::TryInto;
+ |
+LL | use std::convert::TryInto;
+ |
+
+error[E0433]: failed to resolve: use of undeclared type `FromIterator`
+ --> $DIR/suggest-tryinto-edition-change.rs:23:22
+ |
+LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
+ | ^^^^^^^^^^^^
+ |
+ ::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ |
+LL | pub trait IntoIterator {
+ | ---------------------- similarly named trait `IntoIterator` defined here
+ |
+ = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+ = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+help: a trait with a similar name exists
+ |
+LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]);
+ | ~~~~~~~~~~~~
+help: consider importing one of these items
+ |
+LL | use core::iter::FromIterator;
+ |
+LL | use std::iter::FromIterator;
+ |
+
+error[E0599]: no method named `try_into` found for type `i32` in the current scope
+ --> $DIR/suggest-tryinto-edition-change.rs:6:25
+ |
+LL | let _i: i16 = 0_i32.try_into().unwrap();
+ | ^^^^^^^^ method not found in `i32`
+ |
+ ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ |
+LL | fn try_into(self) -> Result<T, Self::Error>;
+ | -------- the method is available for `i32` here
+ |
+ = help: items from traits can only be used if the trait is in scope
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use std::convert::TryInto;
+ |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0433, E0599.
+For more information about an error, try `rustc --explain E0433`.
--- /dev/null
+// edition:2018
+
+use alloc::rc::Rc; //~ ERROR failed to resolve: use of undeclared crate or module `alloc`
+
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
+ --> $DIR/undeclared-module-alloc.rs:3:5
+ |
+LL | use alloc::rc::Rc;
+ | ^^^^^ use of undeclared crate or module `alloc`
+ |
+ = help: add `extern crate alloc` to use the `alloc` crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
--- /dev/null
+// check-pass
+
+pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+ <&mut () as Clone>::clone(&s);
+}
+
+fn main() {}
fn main() {
test::<A>();
- //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
}
-error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/cache-reached-depth-ice.rs:43:5
|
LL | fn test<X: ?Sized + Send>() {}
| ----- in this derive macro expansion
LL | struct FooHolster {
LL | the_foos: Vec<Foo>,
- | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
+ | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`
|
= note: required because of the requirements on the impl of `Clone` for `Vec<Foo>`
note: required by `clone`
let opt = String::new();
opts.get(opt.as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn main() {
| |
| cannot infer type for type parameter `Q` declared on the associated function `get`
|
- = note: cannot satisfy `String: Borrow<_>`
+ = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+ - impl Borrow<str> for String;
+ - impl<T> Borrow<T> for T
+ where T: ?Sized;
error[E0283]: type annotations needed
- --> $DIR/issue-77982.rs:12:44
+ --> $DIR/issue-77982.rs:8:18
+ |
+LL | opts.get(opt.as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
+ - impl AsRef<OsStr> for String;
+ - impl AsRef<Path> for String;
+ - impl AsRef<[u8]> for String;
+ - impl AsRef<str> for String;
+help: use the fully qualified path for the potential candidates
+ |
+LL | opts.get(<String as AsRef<OsStr>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<Path>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<[u8]>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<str>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-77982.rs:13:44
|
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
| ^^^^^^^^^ ----------- this method call resolves to `T`
| |
| cannot infer type for type parameter `T` declared on the trait `From`
|
- = note: cannot satisfy `u32: From<_>`
+ = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+ - impl From<Ipv4Addr> for u32;
+ - impl From<NonZeroU32> for u32;
+ - impl From<bool> for u32;
+ - impl From<char> for u32;
+ and 3 more
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:35:16
+ --> $DIR/issue-77982.rs:36:16
|
LL | let _ = ().foo();
| - ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
| |
| consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
|
- = note: cannot satisfy `(): Foo<'_, _>`
+note: multiple `impl`s satisfying `(): Foo<'_, _>` found
+ --> $DIR/issue-77982.rs:29:1
+ |
+LL | impl Foo<'static, u32> for () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Foo<'a, i16> for () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:39:19
+ --> $DIR/issue-77982.rs:40:19
|
LL | let _ = (&()).bar();
| - ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
| |
| consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
|
- = note: cannot satisfy `&(): Bar<'_, _>`
+note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
+ --> $DIR/issue-77982.rs:32:1
+ |
+LL | impl<'a> Bar<'static, u32> for &'a () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Bar<'a, i16> for &'a () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0283`.
// Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":
forward();
- //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
- //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
reverse();
- //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
- //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
}
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
LL | Vec<First>: Unpin,
LL | forward();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
LL | Third<'a, Ty>: Unpin,
LL | forward();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
LL | Third<'a, Ty>: Unpin,
LL | reverse();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
LL | Vec<First>: Unpin,
--- /dev/null
+// check-pass
+pub trait Archive {
+ type Archived;
+}
+
+impl<T> Archive for Option<T> {
+ type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
--- /dev/null
+// check-pass
+pub trait Archive {
+ type Archived;
+}
+
+impl<T> Archive for Option<T> {
+ type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
fn a() {
test(22, std::default::Default::default());
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
fn main() {}
LL | test(22, std::default::Default::default());
| ^^^^ cannot infer type for type parameter `U` declared on the function `test`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
+ |
+LL | test(22, std::default::Default::default());
+ | ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+ |
+note: multiple `impl`s satisfying `i32: Convert<_>` found
+ --> $DIR/multidispatch-convert-ambig-dest.rs:8:1
+ |
+LL | impl Convert<i8> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Convert<i16> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `test`
+ --> $DIR/multidispatch-convert-ambig-dest.rs:21:11
+ |
+LL | fn test<T,U>(_: T, _: U)
+ | ---- required by a bound in this
+LL | where T : Convert<U>
+ | ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the type arguments in the function call
+ |
+LL | test::<T, U>(22, std::default::Default::default());
+ | ++++++++
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
| |
| required by a bound introduced by this call
|
- = help: the trait `Send` is not implemented for `dummy1c::TestType`
+ = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
= note: required because it appears within the type `({integer}, dummy1c::TestType)`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
| |
| required by a bound introduced by this call
|
- = help: the trait `Send` is not implemented for `dummy3::TestType`
+ = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
note: required because it appears within the type `Outer2<dummy3::TestType>`
--> $DIR/negated-auto-traits-error.rs:12:8
|
+// check-pass
+
#![feature(negative_impls)]
// aux-build: foreign_trait.rs
trait LocalTrait { }
impl<T: ForeignTrait> LocalTrait for T { }
-impl LocalTrait for String { } //~ ERROR conflicting implementations
+impl LocalTrait for String { }
fn main() { }
+++ /dev/null
-error[E0119]: conflicting implementations of trait `LocalTrait` for type `std::string::String`
- --> $DIR/rely-on-negative-impl-in-coherence.rs:19:1
- |
-LL | impl<T: ForeignTrait> LocalTrait for T { }
- | -------------------------------------- first implementation here
-LL | impl LocalTrait for String { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::string::String`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
--> $DIR/param-without-lifetime-constraint.rs:14:5
|
LL | fn get_relation(&self) -> To;
- | ----------------------------- expected `fn(&Article) -> &ProofReader`
+ | ----------------------------- expected `fn(&'1 Article) -> &'2 ProofReader`
...
LL | fn get_relation(&self) -> &ProofReader {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
|
- = note: expected `fn(&Article) -> &ProofReader`
- found `fn(&Article) -> &ProofReader`
+ = note: expected `fn(&'1 Article) -> &'2 ProofReader`
+ found `fn(&'1 Article) -> &'1 ProofReader`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/param-without-lifetime-constraint.rs:10:31
|
--> $DIR/self-without-lifetime-constraint.rs:45:5
|
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
- | -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+ | -------------------------------------------------------------------- expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
...
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
|
- = note: expected `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
- found `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
+ = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/self-without-lifetime-constraint.rs:41:60
|
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
fn main() {
- 10.dup::<i32>();
+ 10.dup::<i32>(); //~ ERROR type annotations needed
//~^ ERROR this associated function takes 0 generic arguments but 1
- 10.blah::<i32, i32>();
+ 10.blah::<i32, i32>(); //~ ERROR type annotations needed
//~^ ERROR this associated function takes 1 generic argument but 2
(Box::new(10) as Box<dyn bar>).dup();
//~^ ERROR E0038
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
= note: required by cast to type `Box<dyn bar>`
-error: aborting due to 5 previous errors
+error[E0283]: type annotations needed
+ --> $DIR/test-2.rs:9:8
+ |
+LL | 10.dup::<i32>();
+ | ^^^ cannot infer type for type `{integer}`
+ |
+note: multiple `impl`s satisfying `{integer}: bar` found
+ --> $DIR/test-2.rs:5:1
+ |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+ --> $DIR/test-2.rs:11:8
+ |
+LL | 10.blah::<i32, i32>();
+ | ^^^^ cannot infer type for type `{integer}`
+ |
+note: multiple `impl`s satisfying `{integer}: bar` found
+ --> $DIR/test-2.rs:5:1
+ |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0038, E0107.
+Some errors have detailed explanations: E0038, E0107, E0283.
For more information about an error, try `rustc --explain E0038`.
| |
| call expression requires function
|
-help: `Alias::Unit` is a unit variant, you need to write it without the parenthesis
+help: `Alias::Unit` is a unit variant, you need to write it without the parentheses
|
LL | Alias::Unit;
| ~~~~~~~~~~~
error[E0277]: `Rc<u32>` cannot be sent between threads safely
- --> $DIR/auto-trait-leakage2.rs:17:5
+ --> $DIR/auto-trait-leakage2.rs:17:13
|
LL | type Foo = impl std::fmt::Debug;
| -------------------- within this `impl Debug`
...
LL | is_send(m::foo());
- | ^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+ | ------- ^^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `impl Debug`, the trait `Send` is not implemented for `Rc<u32>`
= note: required because it appears within the type `impl Debug`
fn main() {}
type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied
+//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
//~| ERROR `A` doesn't implement `Debug`
//~| ERROR `B` doesn't implement `Debug`
LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+ --> $DIR/generic_duplicate_param_use9.rs:7:18
+ |
+LL | type Two<A, B> = impl Debug;
+ | ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+ |
+ = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
+help: consider restricting type parameter `A`
+ |
+LL | type Two<A: Foo, B> = impl Debug;
+ | +++++
+
error[E0277]: `A` doesn't implement `Debug`
--> $DIR/generic_duplicate_param_use9.rs:7:18
|
LL | type Two<A, B: std::fmt::Debug> = impl Debug;
| +++++++++++++++++
-error[E0277]: the trait bound `A: Foo` is not satisfied
- --> $DIR/generic_duplicate_param_use9.rs:7:18
- |
-LL | type Two<A, B> = impl Debug;
- | ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
- |
- = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
-help: consider restricting type parameter `A`
- |
-LL | type Two<A: Foo, B> = impl Debug;
- | +++++
-
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// edition:2018
+
+#![feature(type_alias_impl_trait)]
+
+use std::future::Future;
+
+type G<'a, T> = impl Future<Output = ()>;
+//~^ ERROR: type mismatch resolving `<impl Future as Future>::Output == ()`
+//~| ERROR: the trait bound `T: Trait` is not satisfied
+
+trait Trait {
+ type F: Future<Output = ()>;
+
+ fn f(&self) -> Self::F;
+
+ fn g<'a>(&'a self) -> G<'a, Self>
+ where
+ Self: Sized,
+ {
+ async move { self.f().await }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+ --> $DIR/issue-89686.rs:7:17
+ |
+LL | type G<'a, T> = impl Future<Output = ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
+...
+LL | async move { self.f().await }
+ | ------------------ the found `async` block
+ |
+ ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+ |
+LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
+ | ------------------------------- the found opaque type
+ |
+ = note: expected unit type `()`
+ found associated type `<impl Future as Future>::Output`
+ = help: consider constraining the associated type `<impl Future as Future>::Output` to `()`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0277]: the trait bound `T: Trait` is not satisfied
+ --> $DIR/issue-89686.rs:7:17
+ |
+LL | type G<'a, T> = impl Future<Output = ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | type G<'a, T: Trait> = impl Future<Output = ()>;
+ | +++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
--- /dev/null
+fn main() {
+ 0u8.as_ref(); //~ ERROR no method named `as_ref` found for type `u8` in the current scope
+}
--- /dev/null
+error[E0599]: no method named `as_ref` found for type `u8` in the current scope
+ --> $DIR/issue-89806.rs:2:9
+ |
+LL | 0u8.as_ref();
+ | ^^^^^^ method not found in `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+// check-pass
+
+trait Foo: Baz {}
+trait Bar {}
+trait Baz: Bar {
+ fn bar(&self);
+}
+
+impl<T: Foo> Bar for T {}
+impl<T: Foo> Baz for T {
+ fn bar(&self) {}
+}
+
+fn accept_foo(x: Box<dyn Foo>) {
+ x.bar();
+}
+
+fn main() {}
--- /dev/null
+use std::path::{Path, PathBuf};
+
+fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+
+fn main() {
+ func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+ //~^ ERROR [E0277]
+}
--- /dev/null
+error[E0277]: the trait bound `PathBuf: From<Cow<'_, str>>` is not satisfied
+ --> $DIR/issue-90101.rs:6:10
+ |
+LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+ | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <PathBuf as From<&T>>
+ <PathBuf as From<Box<Path>>>
+ <PathBuf as From<Cow<'a, Path>>>
+ <PathBuf as From<OsString>>
+ <PathBuf as From<String>>
+ = note: required because of the requirements on the impl of `Into<PathBuf>` for `Cow<'_, str>`
+note: required by a bound in `func`
+ --> $DIR/issue-90101.rs:3:20
+ |
+LL | fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+ | ^^^^^^^^^^^^^ required by this bound in `func`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+fn copy<R: Unpin, W>(_: R, _: W) {}
+
+fn f<T>(r: T) {
+ let w = ();
+ copy(r, w);
+ //~^ ERROR [E0277]
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `T` cannot be unpinned
+ --> $DIR/issue-90164.rs:5:10
+ |
+LL | copy(r, w);
+ | ---- ^ the trait `Unpin` is not implemented for `T`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: consider using `Box::pin`
+note: required by a bound in `copy`
+ --> $DIR/issue-90164.rs:1:12
+ |
+LL | fn copy<R: Unpin, W>(_: R, _: W) {}
+ | ^^^^^ required by this bound in `copy`
+help: consider restricting type parameter `T`
+ |
+LL | fn f<T: std::marker::Unpin>(r: T) {
+ | ++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
| ^^^^ required by this bound in `test`
error[E0277]: `UnsafeCell<NoSync>` cannot be shared between threads safely
- --> $DIR/typeck-unsafe-always-share.rs:27:5
+ --> $DIR/typeck-unsafe-always-share.rs:27:10
|
LL | test(ms);
- | ^^^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+ | ---- ^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`
note: required because it appears within the type `MySync<NoSync>`
| ------ ------ ^ ...but data from `y` flows into `x` here
| |
| these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ~~ ~~
error: aborting due to previous error
fn main() {
foo::Foo(());
- foo::std_io::stdout();
+ let _ = foo::std_io::stdout();
foo::local_io(());
- io::stdout();
- bar::io::stdout();
+ let _ = io::stdout();
+ let _ = bar::io::stdout();
bar::std();
bar::std!();
// scope is allowed, when both resolve to the same definition.
use std::io;
use io::stdout;
- stdout();
+ let _ = stdout();
}
}
fn main() {
Foo(());
- std_io::stdout();
+ let _ = std_io::stdout();
local_io(());
{
// scope is allowed, when both resolve to the same definition.
use ::std::io as std_io;
use std_io::stdout;
- stdout();
+ let _ = stdout();
}
}
fn main() {
foo::Foo(());
- foo::std_io::stdout();
+ let _ = foo::std_io::stdout();
foo::local_io(());
- io::stdout();
- bar::io::stdout();
+ let _ = io::stdout();
+ let _ = bar::io::stdout();
}
fn main() {
Foo(());
- std_io::stdout();
+ let _ = std_io::stdout();
local_io(());
}
| |________________- doesn't satisfy `Box<dyn Foo>: Clone`
|
= note: the following trait bounds were not satisfied:
- `dyn Foo: Clone`
- which is required by `Box<dyn Foo>: Clone`
`dyn Foo: Sized`
which is required by `Box<dyn Foo>: Clone`
+ `dyn Foo: Clone`
+ which is required by `Box<dyn Foo>: Clone`
error: aborting due to previous error
| |
| required by a bound introduced by this call
|
- = help: the trait `Sized` is not implemented for `[u8]`
+ = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`
note: required because it appears within the type `A<[u8]>`
--> $DIR/unsized-exprs.rs:3:8
|
-#![feature(relaxed_struct_unsize)]
// run-pass
// Test that we allow unsizing even if there is an unchanged param in the
// field getting unsized.
| this type parameter needs to be `std::marker::Sized`
|
note: required by a bound in `bar`
- --> $DIR/unsized-bare-typaram.rs:1:11
+ --> $DIR/unsized-bare-typaram.rs:1:8
|
LL | fn bar<T: Sized>() { }
- | ^^^^^ required by this bound in `bar`
+ | ^ required by this bound in `bar`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn foo<T: ?Sized>() { bar::<T>() }
LL | struct Bar<T: ?Sized> { data: T }
| ^^^
note: required by a bound in `is_sized`
- --> $DIR/unsized-struct.rs:1:15
+ --> $DIR/unsized-struct.rs:1:13
|
LL | fn is_sized<T:Sized>() { }
- | ^^^^^ required by this bound in `is_sized`
+ | ^ required by this bound in `is_sized`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
// --extern-location with a raw reference
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar
+// compile-flags:--extern-location bar -Zunstable-options
#![warn(unused_crate_dependencies)]
--- /dev/null
+// Test that the variance computation considers types that
+// appear in const expressions to be invariant.
+
+#![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Trait {
+ const Const: usize;
+}
+
+#[rustc_variance]
+struct Foo<T: Trait> { //~ ERROR [o]
+ field: [u8; <T as Trait>::Const]
+}
+
+fn main() { }
--- /dev/null
+error[E0208]: [o]
+ --> $DIR/variance-associated-consts.rs:13:1
+ |
+LL | / struct Foo<T: Trait> {
+LL | | field: [u8; <T as Trait>::Const]
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
#[derive(Debug, serde::Deserialize)]
struct ManifestTargetPackage {
- available: bool,
url: Option<String>,
hash: Option<String>,
xz_url: Option<String>,
-Subproject commit c7957a74bdcf3b11e7154c1a9401735f23ebd484
+Subproject commit 94ca096afbf25f670e76e07dca754fcfe27134be
+++ /dev/null
-[alias]
-uitest = "test --test compile-test"
-dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
-lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
-collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
-
-[build]
-# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
-rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
-target-dir = "target"
--- /dev/null
+[alias]
+uitest = "test --test compile-test"
+dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
+lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
+collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
+
+[build]
+# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
+rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
+target-dir = "target"
if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
cp -Tr out/master "out/$TAG_NAME"
- ln -sf "$TAG_NAME" out/stable
+ rm -f out/stable
+ ln -s "$TAG_NAME" out/stable
fi
if [[ $BETA = "true" ]]; then
## Unreleased / In Rust Nightly
-[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
+[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
+
+## Rust 1.57
+
+Current beta, release 2021-12-02
+
+[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
+
+### New Lints
+
+* [`negative_feature_names`]
+ [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`redundant_feature_names`]
+ [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`mod_module_files`]
+ [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`self_named_module_files`]
+ [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`manual_split_once`]
+ [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
+* [`derivable_impls`]
+ [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
+* [`needless_option_as_deref`]
+ [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
+* [`iter_not_returning_iterator`]
+ [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
+* [`same_name_method`]
+ [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
+* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
+* [`non_send_fields_in_send_ty`]
+ [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
+* [`equatable_if_let`]
+ [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
+
+### Moves and Deprecations
+
+* Move [`shadow_unrelated`] to `restriction`
+ [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* Move [`option_if_let_else`] to `nursery`
+ [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
+* Move [`branches_sharing_code`] to `nursery`
+ [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
+* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
+ `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
+* Move [`many_single_char_names`] to `pedantic`
+ [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
+* Move [`float_cmp`] to `pedantic`
+ [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
+* Rename `box_vec` to [`box_collection`] and lint on more general cases
+ [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
+* Uplift `invalid_atomic_ordering` to rustc
+ [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
+
+### Enhancements
+
+* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
+ limited to certain patterns
+ [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* The `avoid-breaking-exported-api` configuration now also works for
+ [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
+ [`option_option`], [`linkedlist`], [`rc_mutex`]
+ [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
+* [`unnecessary_unwrap`]: Now also checks for `expect`s
+ [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
+* [`disallowed_method`]: Allow adding a reason that will be displayed with the
+ lint message
+ [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
+* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
+ [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
+* [`approx_constant`]: Add `TAU`
+ [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
+* [`needless_borrow`]: Now also lints on needless mutable borrows
+ [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
+* [`missing_safety_doc`]: Now also lints on unsafe traits
+ [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
+
+### False Positive Fixes
+
+* [`manual_map`]: No longer lints when the option is borrowed in the match and
+ also consumed in the arm
+ [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
+* [`filter_next`]: No longer lints if `filter` method is not the
+ `Iterator::filter` method
+ [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
+* [`manual_flatten`]: No longer lints if expression is used after `if let`
+ [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
+* [`option_if_let_else`]: Multiple fixes
+ [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
+ * `break` and `continue` statements local to the would-be closure are
+ allowed
+ * Don't lint in const contexts
+ * Don't lint when yield expressions are used
+ * Don't lint when the captures made by the would-be closure conflict with
+ the other branch
+ * Don't lint when a field of a local is used when the type could be
+ potentially moved from
+ * In some cases, don't lint when scrutinee expression conflicts with the
+ captures of the would-be closure
+* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
+ wide pointers with thin pointers
+ [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
+* [`bool_assert_comparison`]: No longer lints on types that do not implement the
+ `Not` trait with `Output = bool`
+ [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
+* [`mut_range_bound`]: No longer lints on range bound mutations, that are
+ immediately followed by a `break;`
+ [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
+* [`mutable_key_type`]: Improve accuracy and document remaining false positives
+ and false negatives
+ [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
+* [`redundant_closure`]: Rewrite the lint to fix various false positives and
+ false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
+* [`large_enum_variant`]: No longer wrongly identifies the second largest
+ variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
+* [`needless_return`]: No longer lints on let-else expressions
+ [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
+* [`suspicious_else_formatting`]: No longer lints in proc-macros
+ [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
+* [`excessive_precision`]: No longer lints when in some cases the float was
+ already written in the shortest form
+ [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
+* [`doc_markdown`]: No longer lints on intra-doc links
+ [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
+
+### Suggestion Fixes/Improvements
+
+* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
+ function call in an indexing operation
+ [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
+* [`manual_split_once`]: Produce semantically equivalent suggestion when
+ `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
+* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
+ [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
+* [`manual_assert`]: No better handles complex conditions
+ [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
+* Correctly handle signs in exponents in numeric literals lints
+ [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
+* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
+ [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
+* Drop exponent from suggestion if it is 0 in numeric literals lints
+ [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
+
+### ICE Fixes
+
+* [`implicit_hasher`]
+ [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
+
+### Others
+
+* Clippy now uses the 2021
+ [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
+ [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
## Rust 1.56
-Current beta, release 2021-10-21
+Current stable, released 2021-10-21
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
-### New Lints
-
-* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
-
## Rust 1.55
-Current stable, released 2021-09-09
+Released 2021-09-09
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
+[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
-[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
+[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
+[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
+[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
+[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
+[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
+[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
+[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
+[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
+[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
```bash
- # Make sure to change `your-github-name` to your github name in the following command
+ # Make sure to change `your-github-name` to your github name in the following command. Also be
+ # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
+ # because changes cannot be fast forwarded
git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
```
[package]
name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
[dependencies]
clippy_lints = { version = "0.1", path = "clippy_lints" }
-semver = "0.11"
+semver = "1.0"
rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
tempfile = { version = "3.2", optional = true }
[dev-dependencies]
-cargo_metadata = "0.12"
-compiletest_rs = { version = "0.7", features = ["tmp"] }
+cargo_metadata = "0.14"
+compiletest_rs = { version = "0.7.1", features = ["tmp"] }
tester = "0.9"
regex = "1.5"
# This is used by the `collect-metadata` alias.
[dependencies]
bytecount = "0.6"
clap = "2.33"
+indoc = "1.0"
itertools = "0.10"
opener = "0.5"
regex = "1.5"
matches.value_of("pass"),
matches.value_of("name"),
matches.value_of("category"),
+ matches.is_present("msrv"),
) {
Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {}", e),
"internal_warn",
])
.takes_value(true),
+ )
+ .arg(
+ Arg::with_name("msrv")
+ .long("msrv")
+ .help("Add MSRV config code to the lint"),
),
)
.subcommand(
use crate::clippy_project_root;
+use indoc::indoc;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use std::io::{self, ErrorKind};
/// # Errors
///
/// This function errors out if the files couldn't be created or written to.
-pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> {
+pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> {
let lint = LintData {
pass: pass.expect("`pass` argument is validated by clap"),
name: lint_name.expect("`name` argument is validated by clap"),
project_root: clippy_project_root(),
};
- create_lint(&lint).context("Unable to create lint implementation")?;
- create_test(&lint).context("Unable to create a test for the new lint")
+ create_lint(&lint, msrv).context("Unable to create lint implementation")?;
+ create_test(&lint).context("Unable to create a test for the new lint")?;
+ add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
}
-fn create_lint(lint: &LintData<'_>) -> io::Result<()> {
- let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
- "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
- "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
- _ => {
- unreachable!("`pass_type` should only ever be `early` or `late`!");
- },
- };
-
- let camel_case_name = to_camel_case(lint.name);
- let lint_contents = get_lint_file_contents(
- pass_type,
- pass_lifetimes,
- lint.name,
- &camel_case_name,
- lint.category,
- pass_import,
- context_import,
- );
+fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+ let lint_contents = get_lint_file_contents(lint, enable_msrv);
let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
}
}
+fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+ let path = "clippy_lints/src/lib.rs";
+ let mut lib_rs = fs::read_to_string(path).context("reading")?;
+
+ let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
+
+ let new_lint = if enable_msrv {
+ format!(
+ "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ",
+ lint_pass = lint.pass,
+ module_name = lint.name,
+ camel_name = to_camel_case(lint.name),
+ )
+ } else {
+ format!(
+ "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ",
+ lint_pass = lint.pass,
+ module_name = lint.name,
+ camel_name = to_camel_case(lint.name),
+ )
+ };
+
+ lib_rs.insert_str(comment_start, &new_lint);
+
+ fs::write(path, lib_rs).context("writing")
+}
+
fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
OpenOptions::new()
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
let mut contents = format!(
- "#![warn(clippy::{})]
+ indoc! {"
+ #![warn(clippy::{})]
-fn main() {{
- // test code goes here
-}}
-",
+ fn main() {{
+ // test code goes here
+ }}
+ "},
lint_name
);
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
format!(
- r#"
-# {}
+ indoc! {r#"
+ # {}
-[package]
-name = "{}"
-version = "0.1.0"
-publish = false
+ [package]
+ name = "{}"
+ version = "0.1.0"
+ publish = false
-[workspace]
-"#,
+ [workspace]
+ "#},
hint, lint_name
)
}
-fn get_lint_file_contents(
- pass_type: &str,
- pass_lifetimes: &str,
- lint_name: &str,
- camel_case_name: &str,
- category: &str,
- pass_import: &str,
- context_import: &str,
-) -> String {
- format!(
- "use rustc_lint::{{{type}, {context_import}}};
-use rustc_session::{{declare_lint_pass, declare_tool_lint}};
-{pass_import}
-
-declare_clippy_lint! {{
- /// ### What it does
- ///
- /// ### Why is this bad?
- ///
- /// ### Example
- /// ```rust
- /// // example code where clippy issues a warning
- /// ```
- /// Use instead:
- /// ```rust
- /// // example code which does not raise clippy warning
- /// ```
- pub {name_upper},
- {category},
- \"default lint description\"
-}}
-
-declare_lint_pass!({name_camel} => [{name_upper}]);
-
-impl {type}{lifetimes} for {name_camel} {{}}
-",
- type=pass_type,
- lifetimes=pass_lifetimes,
- name_upper=lint_name.to_uppercase(),
- name_camel=camel_case_name,
- category=category,
- pass_import=pass_import,
- context_import=context_import
- )
+fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
+ let mut result = String::new();
+
+ let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
+ "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
+ "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
+ _ => {
+ unreachable!("`pass_type` should only ever be `early` or `late`!");
+ },
+ };
+
+ let lint_name = lint.name;
+ let category = lint.category;
+ let name_camel = to_camel_case(lint.name);
+ let name_upper = lint_name.to_uppercase();
+
+ result.push_str(&if enable_msrv {
+ format!(
+ indoc! {"
+ use clippy_utils::msrvs;
+ {pass_import}
+ use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
+ use rustc_semver::RustcVersion;
+ use rustc_session::{{declare_tool_lint, impl_lint_pass}};
+
+ "},
+ pass_type = pass_type,
+ pass_import = pass_import,
+ context_import = context_import,
+ )
+ } else {
+ format!(
+ indoc! {"
+ {pass_import}
+ use rustc_lint::{{{context_import}, {pass_type}}};
+ use rustc_session::{{declare_lint_pass, declare_tool_lint}};
+
+ "},
+ pass_import = pass_import,
+ pass_type = pass_type,
+ context_import = context_import
+ )
+ });
+
+ result.push_str(&format!(
+ indoc! {"
+ declare_clippy_lint! {{
+ /// ### What it does
+ ///
+ /// ### Why is this bad?
+ ///
+ /// ### Example
+ /// ```rust
+ /// // example code where clippy issues a warning
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// // example code which does not raise clippy warning
+ /// ```
+ pub {name_upper},
+ {category},
+ \"default lint description\"
+ }}
+ "},
+ name_upper = name_upper,
+ category = category,
+ ));
+
+ result.push_str(&if enable_msrv {
+ format!(
+ indoc! {"
+ pub struct {name_camel} {{
+ msrv: Option<RustcVersion>,
+ }}
+
+ impl {name_camel} {{
+ #[must_use]
+ pub fn new(msrv: Option<RustcVersion>) -> Self {{
+ Self {{ msrv }}
+ }}
+ }}
+
+ impl_lint_pass!({name_camel} => [{name_upper}]);
+
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{
+ extract_msrv_attr!({context_import});
+ }}
+
+ // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
+ // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
+ // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
+ "},
+ pass_type = pass_type,
+ pass_lifetimes = pass_lifetimes,
+ name_upper = name_upper,
+ name_camel = name_camel,
+ context_import = context_import,
+ )
+ } else {
+ format!(
+ indoc! {"
+ declare_lint_pass!({name_camel} => [{name_upper}]);
+
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
+ "},
+ pass_type = pass_type,
+ pass_lifetimes = pass_lifetimes,
+ name_upper = name_upper,
+ name_camel = name_camel,
+ )
+ });
+
+ result
}
#[test]
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
];
let expected = vec![
- format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
- format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
+ format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK),
+ format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK),
];
assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
}
[package]
name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
edition = "2021"
[dependencies]
-cargo_metadata = "0.12"
+cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
if_chain = "1.0"
itertools = "0.10"
toml = "0.5"
unicode-normalization = "0.1"
unicode-script = { version = "0.5", default-features = false }
-semver = "0.11"
+semver = "1.0"
rustc-semver = "1.1"
# NOTE: cargo requires serde feat in its url dep
# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::expr_or_init;
use clippy_utils::ty::is_isize_or_usize;
-use rustc_hir::Expr;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
use super::{utils, CAST_POSSIBLE_TRUNCATION};
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+ if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
+ Some(c)
+ } else {
+ None
+ }
+}
+
+fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
+ constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
+}
+
+fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
+ match expr_or_init(cx, expr).kind {
+ ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
+ ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
+ ExprKind::Binary(op, left, right) => match op.node {
+ BinOpKind::Div => {
+ apply_reductions(cx, nbits, left, signed)
+ - (if signed {
+ 0 // let's be conservative here
+ } else {
+ // by dividing by 1, we remove 0 bits, etc.
+ get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
+ })
+ },
+ BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
+ .unwrap_or(u64::max_value())
+ .min(apply_reductions(cx, nbits, left, signed)),
+ BinOpKind::Shr => {
+ apply_reductions(cx, nbits, left, signed)
+ - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
+ },
+ _ => nbits,
+ },
+ ExprKind::MethodCall(method, _, [left, right], _) => {
+ if signed {
+ return nbits;
+ }
+ let max_bits = if method.ident.as_str() == "min" {
+ get_constant_bits(cx, right)
+ } else {
+ None
+ };
+ apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
+ },
+ ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
+ if method.ident.as_str() == "clamp" {
+ //FIXME: make this a diagnostic item
+ if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
+ return lo_bits.max(hi_bits);
+ }
+ }
+ nbits
+ },
+ ExprKind::MethodCall(method, _, [_value], _) => {
+ if method.ident.name.as_str() == "signum" {
+ 0 // do not lint if cast comes from a `signum` function
+ } else {
+ nbits
+ }
+ },
+ _ => nbits,
+ }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
- let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
+ let from_nbits = apply_reductions(
+ cx,
+ utils::int_ty_to_nbits(cast_from, cx.tcx),
+ cast_expr,
+ cast_from.is_signed(),
+ );
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::FN_TO_NUMERIC_CAST_ANY;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+ // We allow casts from any function type to any function type.
+ match cast_to.kind() {
+ ty::FnDef(..) | ty::FnPtr(..) => return,
+ _ => { /* continue to checks */ },
+ }
+
+ match cast_from.kind() {
+ ty::FnDef(..) | ty::FnPtr(_) => {
+ let mut applicability = Applicability::MaybeIncorrect;
+ let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+ span_lint_and_sugg(
+ cx,
+ FN_TO_NUMERIC_CAST_ANY,
+ expr.span,
+ &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+ "did you mean to invoke the function?",
+ format!("{}() as {}", from_snippet, cast_to),
+ applicability,
+ );
+ },
+ _ => {},
+ }
+}
mod cast_sign_loss;
mod char_lit_as_u8;
mod fn_to_numeric_cast;
+mod fn_to_numeric_cast_any;
mod fn_to_numeric_cast_with_truncation;
mod ptr_as_ptr;
mod unnecessary_cast;
"casting a function pointer to a numeric type not wide enough to store the address"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for casts of a function pointer to any integer type.
+ ///
+ /// ### Why is this bad?
+ /// Casting a function pointer to an integer can have surprising results and can occur
+ /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
+ /// low-level with function pointers then you can opt-out of casting functions to integers in
+ /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+ /// pointer casts in your code.
+ ///
+ /// ### Example
+ /// ```rust
+ /// // Bad: fn1 is cast as `usize`
+ /// fn fn1() -> u16 {
+ /// 1
+ /// };
+ /// let _ = fn1 as usize;
+ ///
+ /// // Good: maybe you intended to call the function?
+ /// fn fn2() -> u16 {
+ /// 1
+ /// };
+ /// let _ = fn2() as usize;
+ ///
+ /// // Good: maybe you intended to cast it to a function type?
+ /// fn fn3() -> u16 {
+ /// 1
+ /// }
+ /// let _ = fn3 as fn() -> u16;
+ /// ```
+ pub FN_TO_NUMERIC_CAST_ANY,
+ restriction,
+ "casting a function pointer to any integer type"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for casts of `&T` to `&mut T` anywhere in the code.
CAST_REF_TO_MUT,
CAST_PTR_ALIGNMENT,
UNNECESSARY_CAST,
+ FN_TO_NUMERIC_CAST_ANY,
FN_TO_NUMERIC_CAST,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
CHAR_LIT_AS_U8,
return;
}
+ fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
- cast_possible_truncation::check(cx, expr, cast_from, cast_to);
+ cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
} else {
sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span)
};
- let moved_end = block
- .expr
- .map_or_else(
- || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
- |expr| expr.span.source_callsite(),
- );
+ let moved_end = block.expr.map_or_else(
+ || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
+ |expr| expr.span.source_callsite(),
+ );
let moved_span = moved_start.to(moved_end);
let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None);
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::ty::{has_drop, is_copy};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
.fields
.iter()
.all(|field| field.vis.is_accessible_from(module_did, cx.tcx));
+ let all_fields_are_copy = variant
+ .fields
+ .iter()
+ .all(|field| {
+ is_copy(cx, cx.tcx.type_of(field.did))
+ });
+ if !has_drop(cx, binding_type) || all_fields_are_copy;
then {
(local, variant, ident.name, binding_type, expr.span)
} else {
+// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
+// tests/ui/deprecated.rs
+
/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
/// enables the simple extraction of the metadata without changing the current deprecation
/// declaration.
target_mut,
},
));
- }
+ },
_ => (),
}
},
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{
def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
+
+use crate::utils::conf;
declare_clippy_lint! {
/// ### What it does
/// An example clippy.toml configuration:
/// ```toml
/// # clippy.toml
- /// disallowed-types = ["std::collections::BTreeMap"]
+ /// disallowed-types = [
+ /// # Can use a string as the path of the disallowed type.
+ /// "std::collections::BTreeMap",
+ /// # Can also use an inline table with a `path` key.
+ /// { path = "std::net::TcpListener" },
+ /// # When using an inline table, can add a `reason` for why the type
+ /// # is disallowed.
+ /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+ /// ]
/// ```
///
/// ```rust,ignore
}
#[derive(Clone, Debug)]
pub struct DisallowedType {
- disallowed: FxHashSet<Vec<Symbol>>,
- def_ids: FxHashSet<DefId>,
- prim_tys: FxHashSet<PrimTy>,
+ conf_disallowed: Vec<conf::DisallowedType>,
+ def_ids: FxHashMap<DefId, Option<String>>,
+ prim_tys: FxHashMap<PrimTy, Option<String>>,
}
impl DisallowedType {
- pub fn new(disallowed: &FxHashSet<String>) -> Self {
+ pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
Self {
- disallowed: disallowed
- .iter()
- .map(|s| s.split("::").map(Symbol::intern).collect::<Vec<_>>())
- .collect(),
- def_ids: FxHashSet::default(),
- prim_tys: FxHashSet::default(),
+ conf_disallowed,
+ def_ids: FxHashMap::default(),
+ prim_tys: FxHashMap::default(),
}
}
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
match res {
Res::Def(_, did) => {
- if self.def_ids.contains(did) {
- emit(cx, &cx.tcx.def_path_str(*did), span);
+ if let Some(reason) = self.def_ids.get(did) {
+ emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
}
},
Res::PrimTy(prim) => {
- if self.prim_tys.contains(prim) {
- emit(cx, prim.name_str(), span);
+ if let Some(reason) = self.prim_tys.get(prim) {
+ emit(cx, prim.name_str(), span, reason.as_deref());
}
},
_ => {},
impl<'tcx> LateLintPass<'tcx> for DisallowedType {
fn check_crate(&mut self, cx: &LateContext<'_>) {
- for path in &self.disallowed {
- let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
- match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>()) {
+ for conf in &self.conf_disallowed {
+ let (path, reason) = match conf {
+ conf::DisallowedType::Simple(path) => (path, None),
+ conf::DisallowedType::WithReason { path, reason } => (
+ path,
+ reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
+ ),
+ };
+ let segs: Vec<_> = path.split("::").collect();
+ match clippy_utils::path_to_res(cx, &segs) {
Res::Def(_, id) => {
- self.def_ids.insert(id);
+ self.def_ids.insert(id, reason);
},
Res::PrimTy(ty) => {
- self.prim_tys.insert(ty);
+ self.prim_tys.insert(ty, reason);
},
_ => {},
}
}
}
-fn emit(cx: &LateContext<'_>, name: &str, span: Span) {
- span_lint(
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
+ span_lint_and_then(
cx,
DISALLOWED_TYPE,
span,
&format!("`{}` is not allowed according to config", name),
+ |diag| {
+ if let Some(reason) = reason {
+ diag.note(reason);
+ }
+ },
);
}
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
-use clippy_utils::source::first_line_of_span;
+use clippy_utils::attrs::is_doc_hidden;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
+use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::Handler;
+use rustc_errors::{Applicability, Handler};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
/// content are not linted.
///
/// In addition, when writing documentation comments, including `[]` brackets
- /// inside a link text would trip the parser. Therfore, documenting link with
+ /// inside a link text would trip the parser. Therefore, documenting link with
/// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
/// would fail.
///
if !cx.access_levels.is_exported(def_id) {
return; // Private functions do not require doc comments
}
+
+ // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
+ if cx
+ .tcx
+ .hir()
+ .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+ .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
+ {
+ return;
+ }
+
if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
span_lint(
cx,
// text "http://example.com" by pulldown-cmark
continue;
}
- headers.safety |= in_heading && text.trim() == "Safety";
- headers.errors |= in_heading && text.trim() == "Errors";
- headers.panics |= in_heading && text.trim() == "Panics";
+ let trimmed_text = text.trim();
+ headers.safety |= in_heading && trimmed_text == "Safety";
+ headers.safety |= in_heading && trimmed_text == "Implementation safety";
+ headers.safety |= in_heading && trimmed_text == "Implementation Safety";
+ headers.errors |= in_heading && trimmed_text == "Errors";
+ headers.panics |= in_heading && trimmed_text == "Panics";
if in_code {
if is_rust {
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
// Trim punctuation as in `some comment (see foo::bar).`
// ^^
- // Or even as in `_foo bar_` which is emphasized.
- let word = word.trim_matches(|c: char| !c.is_alphanumeric());
+ // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
+ let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
- if valid_idents.contains(word) {
+ // Remove leading or trailing single `:` which may be part of a sentence.
+ if word.starts_with(':') && !word.starts_with("::") {
+ word = word.trim_start_matches(':');
+ }
+ if word.ends_with(':') && !word.ends_with("::") {
+ word = word.trim_end_matches(':');
+ }
+
+ if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
continue;
}
}
}
- // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
+ // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
if has_underscore(word) && has_hyphen(word) {
return;
}
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
- span_lint(
+ let mut applicability = Applicability::MachineApplicable;
+
+ span_lint_and_sugg(
cx,
DOC_MARKDOWN,
span,
- &format!("you should put `{}` between ticks in the documentation", word),
+ "item in documentation is missing backticks",
+ "try",
+ format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
+ applicability,
);
}
}
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
- if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
- || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
+ || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{
self.panic_span = Some(expr.span);
}
ExprKind::MethodCall(
_,
_,
- [map, Expr {
- kind: ExprKind::AddrOf(_, _, key),
- span: key_span,
- ..
- }],
+ [
+ map,
+ Expr {
+ kind: ExprKind::AddrOf(_, _, key),
+ span: key_span,
+ ..
+ },
+ ],
_,
) if key_span.ctxt() == expr.span.ctxt() => {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
//! lint on enum variants that are prefixed or suffixed by the same characters
-use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
+use clippy_utils::str_utils::{self, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
MODULE_INCEPTION
]);
-/// Returns the number of chars that match from the start
-#[must_use]
-fn partial_match(pre: &str, name: &str) -> usize {
- let mut name_iter = name.chars();
- let _ = name_iter.next_back(); // make sure the name is never fully matched
- pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
-}
-
-/// Returns the number of chars that match from the end
-#[must_use]
-fn partial_rmatch(post: &str, name: &str) -> usize {
- let mut name_iter = name.chars();
- let _ = name_iter.next(); // make sure the name is never fully matched
- post.chars()
- .rev()
- .zip(name_iter.rev())
- .take_while(|&(l, r)| l == r)
- .count()
-}
-
fn check_variant(
cx: &LateContext<'_>,
threshold: u64,
}
for var in def.variants {
let name = var.ident.name.as_str();
- if partial_match(item_name, &name) == item_name_chars
+ if count_match_start(item_name, &name).char_count == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{
"variant name starts with the enum's name",
);
}
- if partial_rmatch(item_name, &name) == item_name_chars {
+ if count_match_end(item_name, &name).char_count == item_name_chars {
span_lint(
cx,
ENUM_VARIANT_NAMES,
}
}
let first = &def.variants[0].ident.name.as_str();
- let mut pre = &first[..camel_case::until(&*first)];
- let mut post = &first[camel_case::from(&*first)..];
+ let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
+ let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
for var in def.variants {
let name = var.ident.name.as_str();
- let pre_match = partial_match(pre, &name);
+ let pre_match = count_match_start(pre, &name).byte_count;
pre = &pre[..pre_match];
- let pre_camel = camel_case::until(pre);
+ let pre_camel = str_utils::camel_case_until(pre).byte_index;
pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_numeric() {
}
if next.is_lowercase() {
let last = pre.len() - last.len_utf8();
- let last_camel = camel_case::until(&pre[..last]);
- pre = &pre[..last_camel];
+ let last_camel = str_utils::camel_case_until(&pre[..last]);
+ pre = &pre[..last_camel.byte_index];
} else {
break;
}
}
- let post_match = partial_rmatch(post, &name);
- let post_end = post.len() - post_match;
+ let post_match = count_match_end(post, &name);
+ let post_end = post.len() - post_match.byte_count;
post = &post[post_end..];
- let post_camel = camel_case::from(post);
- post = &post[post_camel..];
+ let post_camel = str_utils::camel_case_start(post);
+ post = &post[post_camel.byte_index..];
}
let (what, value) = match (pre.is_empty(), post.is_empty()) {
(true, true) => return,
);
}
}
- if item.vis.node.is_pub() {
- let matching = partial_match(mod_camel, &item_camel);
- let rmatching = partial_rmatch(mod_camel, &item_camel);
+ // The `module_name_repetitions` lint should only trigger if the item has the module in its
+ // name. Having the same name is accepted.
+ if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
+ let matching = count_match_start(mod_camel, &item_camel);
+ let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
- if matching == nchars {
+ if matching.char_count == nchars {
match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => span_lint(
cx,
_ => (),
}
}
- if rmatching == nchars {
+ if rmatching.char_count == nchars {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of};
+use clippy_utils::{
+ ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function,
+};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
if macro_args.len() == 2;
let (lhs, rhs) = (macro_args[0], macro_args[1]);
if eq_expr_value(cx, lhs, rhs);
-
+ if !is_in_test_function(cx.tcx, e.hir_id);
then {
span_lint(
cx,
if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) {
return;
}
- if is_useless_with_eq_exprs(op.node.into()) && eq_expr_value(cx, left, right) {
+ if is_useless_with_eq_exprs(op.node.into())
+ && eq_expr_value(cx, left, right)
+ && !is_in_test_function(cx.tcx, e.hir_id)
+ {
span_lint(
cx,
EQ_OP,
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::implements_trait;
use if_chain::if_chain;
use rustc_errors::Applicability;
let pat_str = match pat.kind {
PatKind::Struct(..) => format!(
"({})",
- snippet_with_applicability(cx, pat.span, "..", &mut applicability),
+ snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
- _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
+ _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
};
span_lint_and_sugg(
cx,
"try",
format!(
"{} == {}",
- snippet_with_applicability(cx, exp.span, "..", &mut applicability),
+ snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
pat_str,
),
applicability,
}
match *cx.typeck_results().expr_adjustments(arg) {
[] => true,
- [Adjustment {
- kind: Adjust::Deref(None),
- ..
- }, Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
- ..
- }] => {
+ [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
+ ..
+ },
+ ] => {
// re-borrow with the same mutability is allowed
let ty = cx.typeck_results().expr_ty(arg);
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::FormatExpn;
-use clippy_utils::last_path_segment;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, QPath};
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
let mut applicability = Applicability::MachineApplicable;
if format_args.value_args.is_empty() {
- if_chain! {
- if let [e] = &*format_args.format_string_parts;
- if let ExprKind::Lit(lit) = &e.kind;
- if let Some(s_src) = snippet_opt(cx, lit.span);
- then {
- // Simulate macro expansion, converting {{ and }} to { and }.
- let s_expand = s_src.replace("{{", "{").replace("}}", "}");
- let sugg = format!("{}.to_string()", s_expand);
- span_useless_format(cx, call_site, sugg, applicability);
+ if format_args.format_string_parts.is_empty() {
+ span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
+ } else {
+ if_chain! {
+ if let [e] = &*format_args.format_string_parts;
+ if let ExprKind::Lit(lit) = &e.kind;
+ if let Some(s_src) = snippet_opt(cx, lit.span);
+ then {
+ // Simulate macro expansion, converting {{ and }} to { and }.
+ let s_expand = s_src.replace("{{", "{").replace("}}", "}");
+ let sugg = format!("{}.to_string()", s_expand);
+ span_useless_format(cx, call_site, sugg, applicability);
+ }
}
}
} else if let [value] = *format_args.value_args {
ty::Str => true,
_ => false,
};
- if format_args.args.iter().all(is_display_arg);
- if format_args.fmt_expr.map_or(true, check_unformatted);
+ if let Some(args) = format_args.args();
+ if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
then {
let is_new_string = match value.kind {
ExprKind::Binary(..) => true,
}
}
-fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
+fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg(
cx,
USELESS_FORMAT,
span,
"useless use of `format!`",
- "consider using `.to_string()`",
+ "consider using `String::new()`",
sugg,
applicability,
);
}
-fn is_display_arg(expr: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::Call(_, [_, fmt]) = expr.kind;
- if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind;
- if let [.., t, _] = path.segments;
- if t.ident.name == sym::Display;
- then { true } else { false }
- }
-}
-
-/// Checks if the expression matches
-/// ```rust,ignore
-/// &[_ {
-/// format: _ {
-/// width: _::Implied,
-/// precision: _::Implied,
-/// ...
-/// },
-/// ...,
-/// }]
-/// ```
-fn check_unformatted(expr: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
- if let ExprKind::Array([expr]) = expr.kind;
- // struct `core::fmt::rt::v1::Argument`
- if let ExprKind::Struct(_, fields, _) = expr.kind;
- if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
- // struct `core::fmt::rt::v1::FormatSpec`
- if let ExprKind::Struct(_, fields, _) = format_field.expr.kind;
- if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
- if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
- if last_path_segment(precision_path).ident.name == sym::Implied;
- if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width);
- if let ExprKind::Path(ref width_qpath) = width_field.expr.kind;
- if last_path_segment(width_qpath).ident.name == sym::Implied;
- then {
- return true;
- }
- }
-
- false
+fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
+ span_lint_and_sugg(
+ cx,
+ USELESS_FORMAT,
+ span,
+ "useless use of `format!`",
+ "consider using `.to_string()`",
+ sugg,
+ applicability,
+ );
}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_diag_trait_item, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::Ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `format!` within the arguments of another macro that does
+ /// formatting such as `format!` itself, `write!` or `println!`. Suggests
+ /// inlining the `format!` call.
+ ///
+ /// ### Why is this bad?
+ /// The recommended code is both shorter and avoids a temporary allocation.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: {}", format!("something failed at {}", Location::caller()));
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller());
+ /// ```
+ pub FORMAT_IN_FORMAT_ARGS,
+ perf,
+ "`format!` used in a macro that does formatting"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+ /// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+ /// in a macro that does formatting.
+ ///
+ /// ### Why is this bad?
+ /// Since the type implements `Display`, the use of `to_string` is
+ /// unnecessary.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller().to_string());
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller());
+ /// ```
+ pub TO_STRING_IN_FORMAT_ARGS,
+ perf,
+ "`to_string` applied to a type that implements `Display` in format args"
+}
+
+declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
+
+const FORMAT_MACRO_PATHS: &[&[&str]] = &[
+ &paths::FORMAT_ARGS_MACRO,
+ &paths::ASSERT_EQ_MACRO,
+ &paths::ASSERT_MACRO,
+ &paths::ASSERT_NE_MACRO,
+ &paths::EPRINT_MACRO,
+ &paths::EPRINTLN_MACRO,
+ &paths::PRINT_MACRO,
+ &paths::PRINTLN_MACRO,
+ &paths::WRITE_MACRO,
+ &paths::WRITELN_MACRO,
+];
+
+const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro];
+
+impl<'tcx> LateLintPass<'tcx> for FormatArgs {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if_chain! {
+ if let Some(format_args) = FormatArgsExpn::parse(expr);
+ let expr_expn_data = expr.span.ctxt().outer_expn_data();
+ let outermost_expn_data = outermost_expn_data(expr_expn_data);
+ if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
+ if FORMAT_MACRO_PATHS
+ .iter()
+ .any(|path| match_def_path(cx, macro_def_id, path))
+ || FORMAT_MACRO_DIAG_ITEMS
+ .iter()
+ .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id));
+ if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
+ if let Some(args) = format_args.args();
+ then {
+ for (i, arg) in args.iter().enumerate() {
+ if !arg.is_display() {
+ continue;
+ }
+ if arg.has_string_formatting() {
+ continue;
+ }
+ if is_aliased(&args, i) {
+ continue;
+ }
+ check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
+ check_to_string_in_format_args(cx, name, arg);
+ }
+ }
+ }
+ }
+}
+
+fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
+ if expn_data.call_site.from_expansion() {
+ outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
+ } else {
+ expn_data
+ }
+}
+
+fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
+ if_chain! {
+ if FormatExpn::parse(arg.value).is_some();
+ if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
+ then {
+ span_lint_and_then(
+ cx,
+ FORMAT_IN_FORMAT_ARGS,
+ trim_semicolon(cx, call_site),
+ &format!("`format!` in `{}!` args", name),
+ |diag| {
+ diag.help(&format!(
+ "combine the `format!(..)` arguments with the outer `{}!(..)` call",
+ name
+ ));
+ diag.help("or consider changing `format!` to `format_args!`");
+ },
+ );
+ }
+ }
+}
+
+fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
+ let value = arg.value;
+ if_chain! {
+ if !value.span.from_expansion();
+ if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
+ if is_diag_trait_item(cx, method_def_id, sym::ToString);
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ let (n_needed_derefs, target) = count_needed_derefs(
+ receiver_ty,
+ cx.typeck_results().expr_adjustments(receiver).iter(),
+ );
+ if implements_trait(cx, target, display_trait_id, &[]) {
+ if n_needed_derefs == 0 {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span.with_lo(receiver.span.hi()),
+ &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+ "remove this",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span,
+ &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+ "use this",
+ format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+}
+
+// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
+fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
+ let value = args[i].value;
+ args.iter()
+ .enumerate()
+ .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+}
+
+fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
+ snippet_opt(cx, span).map_or(span, |snippet| {
+ let snippet = snippet.trim_end_matches(';');
+ span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
+ })
+}
+
+fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
+where
+ I: Iterator<Item = &'tcx Adjustment<'tcx>>,
+{
+ let mut n_total = 0;
+ let mut n_needed = 0;
+ loop {
+ if let Some(Adjustment {
+ kind: Adjust::Deref(overloaded_deref),
+ target,
+ }) = iter.next()
+ {
+ n_total += 1;
+ if overloaded_deref.is_some() {
+ n_needed = n_total;
+ }
+ ty = target;
+ } else {
+ return (n_needed, ty);
+ }
+ }
+}
declare_clippy_lint! {
/// ### What it does
- /// Checks for a [`#[must_use]`] attribute on
+ /// Checks for a `#[must_use]` attribute on
/// unit-returning functions and methods.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// Unit values are useless. The attribute is likely
/// a remnant of a refactoring that removed the return type.
declare_clippy_lint! {
/// ### What it does
- /// Checks for a [`#[must_use]`] attribute without
+ /// Checks for a `#[must_use]` attribute without
/// further information on functions and methods that return a type already
/// marked as `#[must_use]`.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// The attribute isn't needed. Not using the result
/// will already be reported. Alternatively, one can add some text to the
declare_clippy_lint! {
/// ### What it does
/// Checks for public functions that have no
- /// [`#[must_use]`] attribute, but return something not already marked
+ /// `#[must_use]` attribute, but return something not already marked
/// must-use, have no mutable arg and mutate no statics.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// Not bad at all, this lint just shows places where
/// you could add the attribute.
&& constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
}
-#[allow(clippy::cast_possible_wrap)]
fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
let check = match *cx.typeck_results().expr_ty(e).kind() {
//! on the condition
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_middle::lint::in_external_macro;
+use clippy_utils::is_else_clause;
+use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
-impl EarlyLintPass for IfNotElse {
- fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
- if in_external_macro(cx.sess, item.span) {
+impl LateLintPass<'_> for IfNotElse {
+ fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
+ // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
+ // To fix this, return early if this span comes from a macro or desugaring.
+ if item.span.from_expansion() {
return;
}
- if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
+ if let ExprKind::If(cond, _, Some(els)) = item.kind {
if let ExprKind::Block(..) = els.kind {
- match cond.kind {
+ // Disable firing the lint in "else if" expressions.
+ if is_else_clause(cx.tcx, item) {
+ return;
+ }
+
+ match cond.peel_drop_temps().kind {
ExprKind::Unary(UnOp::Not, _) => {
span_lint_and_help(
cx,
+++ /dev/null
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
-use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
- ///
- /// ### Why is this bad?
- /// `assert!` is simpler than `if`-then-`panic!`.
- ///
- /// ### Example
- /// ```rust
- /// let sad_people: Vec<&str> = vec![];
- /// if !sad_people.is_empty() {
- /// panic!("there are sad people: {:?}", sad_people);
- /// }
- /// ```
- /// Use instead:
- /// ```rust
- /// let sad_people: Vec<&str> = vec![];
- /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
- /// ```
- pub IF_THEN_PANIC,
- style,
- "`panic!` and only a `panic!` in `if`-then statement"
-}
-
-declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
-
-impl LateLintPass<'_> for IfThenPanic {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let Expr {
- kind: ExprKind:: If(cond, Expr {
- kind: ExprKind::Block(
- Block {
- stmts: [stmt],
- ..
- },
- _),
- ..
- }, None),
- ..
- } = &expr;
- if is_expn_of(stmt.span, "panic").is_some();
- if !matches!(cond.kind, ExprKind::Let(_, _, _));
- if let StmtKind::Semi(semi) = stmt.kind;
- if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
- then {
- let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
- match *panic_expn.format_args.value_args {
- [] => panic_expn.format_args.format_string_span,
- [.., last] => panic_expn.format_args.format_string_span.to(last.span),
- }
- } else {
- if_chain! {
- if let ExprKind::Block(block, _) = semi.kind;
- if let Some(init) = block.expr;
- if let ExprKind::Call(_, [format_args]) = init.kind;
-
- then {
- format_args.span
- } else {
- return
- }
- }
- };
- let mut applicability = Applicability::MachineApplicable;
- let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
- let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
- if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
- sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
- } else {
- format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par().to_string())
- }
- } else {
- format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string())
- };
-
- span_lint_and_sugg(
- cx,
- IF_THEN_PANIC,
- expr.span,
- "only a `panic!` in `if`-then statement",
- "try",
- format!("assert!({}, {});", cond_sugg, sugg),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
return;
}
if_chain! {
- if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
+ if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr);
// Check if the conditional expression is a binary operation
if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
item.span,
&format!(
"type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`",
- self_type.to_string()
+ self_type
),
None,
- &format!("remove the inherent method from type `{}`", self_type.to_string()),
+ &format!("remove the inherent method from type `{}`", self_type),
);
} else {
span_lint_and_help(
item.span,
&format!(
"implementation of inherent method `to_string(&self) -> String` for type `{}`",
- self_type.to_string()
+ self_type
),
None,
- &format!("implement trait `Display` for type `{}` instead", self_type.to_string()),
+ &format!("implement trait `Display` for type `{}` instead", self_type),
);
}
}
},
_ => None,
}
- }
+ },
// case where `x + 1 <= ...` or `1 + x <= ...`
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
if lhskind.node == BinOpKind::Add =>
},
_ => None,
}
- }
+ },
// case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
-use std::cmp::Ordering;
-
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
+use clippy_utils::comparisons;
use clippy_utils::comparisons::Rel;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
-use clippy_utils::{comparisons, sext};
declare_clippy_lint! {
/// ### What it does
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
-#[derive(Copy, Clone, Debug, Eq)]
-enum FullInt {
- S(i128),
- U(u128),
-}
-
-impl FullInt {
- #[allow(clippy::cast_sign_loss)]
- #[must_use]
- fn cmp_s_u(s: i128, u: u128) -> Ordering {
- if s < 0 {
- Ordering::Less
- } else if u > (i128::MAX as u128) {
- Ordering::Greater
- } else {
- (s as u128).cmp(&u)
- }
- }
-}
-
-impl PartialEq for FullInt {
- #[must_use]
- fn eq(&self, other: &Self) -> bool {
- self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
- }
-}
-
-impl PartialOrd for FullInt {
- #[must_use]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(match (self, other) {
- (&Self::S(s), &Self::S(o)) => s.cmp(&o),
- (&Self::U(s), &Self::U(o)) => s.cmp(&o),
- (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
- (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
- })
- }
-}
-
-impl Ord for FullInt {
- #[must_use]
- fn cmp(&self, other: &Self) -> Ordering {
- self.partial_cmp(other)
- .expect("`partial_cmp` for FullInt can never return `None`")
- }
-}
-
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
}
}
-fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
- let val = constant(cx, cx.typeck_results(), expr)?.0;
- if let Constant::Int(const_int) = val {
- match *cx.typeck_results().expr_ty(expr).kind() {
- ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
- ty::Uint(_) => Some(FullInt::U(const_int)),
- _ => None,
- }
- } else {
- None
- }
-}
-
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
if let ExprKind::Cast(cast_val, _) = expr.kind {
span_lint(
invert: bool,
) {
if let Some((lb, ub)) = lhs_bounds {
- if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
+ if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
declare_clippy_lint! {
/// ### What it does
- /// Checks for `let _ = <expr>`
- /// where expr is #[must_use]
+ /// Checks for `let _ = <expr>` where expr is `#[must_use]`
///
/// ### Why is this bad?
- /// It's better to explicitly
- /// handle the value of a #[must_use] expr
+ /// It's better to explicitly handle the value of a `#[must_use]`
+ /// expr
///
/// ### Example
/// ```rust
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(float_literal::EXCESSIVE_PRECISION),
LintId::of(format::USELESS_FORMAT),
+ LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+ LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
LintId::of(identity_op::IDENTITY_OP),
LintId::of(if_let_mutex::IF_LET_MUTEX),
- LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(match_result_ok::MATCH_RESULT_OK),
+ LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(matches::MATCH_AS_REF),
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+ LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
LintId::of(types::VEC_BOX),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
+ LintId::of(uninit_vec::UNINIT_VEC),
+ LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+ LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(types::BORROWED_BOX),
LintId::of(types::TYPE_COMPLEXITY),
LintId::of(loops::ITER_NEXT_LOOP),
LintId::of(loops::NEVER_LOOP),
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
+ LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
LintId::of(transmuting_null::TRANSMUTING_NULL),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
+ LintId::of(uninit_vec::UNINIT_VEC),
+ LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
casts::CAST_SIGN_LOSS,
casts::CHAR_LIT_AS_U8,
casts::FN_TO_NUMERIC_CAST,
+ casts::FN_TO_NUMERIC_CAST_ANY,
casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
casts::PTR_AS_PTR,
casts::UNNECESSARY_CAST,
floating_point_arithmetic::IMPRECISE_FLOPS,
floating_point_arithmetic::SUBOPTIMAL_FLOPS,
format::USELESS_FORMAT,
+ format_args::FORMAT_IN_FORMAT_ARGS,
+ format_args::TO_STRING_IN_FORMAT_ARGS,
formatting::POSSIBLE_MISSING_COMMA,
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
formatting::SUSPICIOUS_ELSE_FORMATTING,
identity_op::IDENTITY_OP,
if_let_mutex::IF_LET_MUTEX,
if_not_else::IF_NOT_ELSE,
- if_then_panic::IF_THEN_PANIC,
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
implicit_hasher::IMPLICIT_HASHER,
implicit_return::IMPLICIT_RETURN,
loops::WHILE_LET_ON_ITERATOR,
macro_use::MACRO_USE_IMPORTS,
main_recursion::MAIN_RECURSION,
+ manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_map::MANUAL_MAP,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
map_unit_fn::RESULT_MAP_UNIT_FN,
match_on_vec_items::MATCH_ON_VEC_ITEMS,
match_result_ok::MATCH_RESULT_OK,
+ match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
matches::INFALLIBLE_DESTRUCTURING_MATCH,
matches::MATCH_AS_REF,
matches::MATCH_BOOL,
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN,
+ misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX,
neg_multiply::NEG_MULTIPLY,
new_without_default::NEW_WITHOUT_DEFAULT,
no_effect::NO_EFFECT,
+ no_effect::NO_EFFECT_UNDERSCORE_BINDING,
no_effect::UNNECESSARY_OPERATION,
non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES,
strings::STRING_LIT_AS_BYTES,
+ strings::STRING_SLICE,
strings::STRING_TO_STRING,
strings::STR_TO_STRING,
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
temporary_assignment::TEMPORARY_ASSIGNMENT,
to_digit_is_some::TO_DIGIT_IS_SOME,
to_string_in_display::TO_STRING_IN_DISPLAY,
+ trailing_empty_array::TRAILING_EMPTY_ARRAY,
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
transmute::CROSSPOINTER_TRANSMUTE,
transmute::TRANSMUTE_INT_TO_BOOL,
transmute::TRANSMUTE_INT_TO_CHAR,
transmute::TRANSMUTE_INT_TO_FLOAT,
+ transmute::TRANSMUTE_NUM_TO_BYTES,
transmute::TRANSMUTE_PTR_TO_PTR,
transmute::TRANSMUTE_PTR_TO_REF,
transmute::UNSOUND_COLLECTION_TRANSMUTE,
types::REDUNDANT_ALLOCATION,
types::TYPE_COMPLEXITY,
types::VEC_BOX,
+ undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
unicode::INVISIBLE_CHARACTERS,
unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC,
+ uninit_vec::UNINIT_VEC,
+ unit_hash::UNIT_HASH,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG,
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
LintId::of(regex::TRIVIAL_REGEX),
LintId::of(strings::STRING_LIT_AS_BYTES),
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+ LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(use_self::USE_SELF),
])
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS),
+ LintId::of(manual_assert::MANUAL_ASSERT),
LintId::of(manual_ok_or::MANUAL_OK_OR),
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(matches::MATCH_BOOL),
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING),
- LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
LintId::of(needless_continue::NEEDLESS_CONTINUE),
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+ LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
LintId::of(non_expressive_names::SIMILAR_NAMES),
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION),
- LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unicode::UNICODE_NOT_NFC),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
LintId::of(entry::MAP_ENTRY),
LintId::of(escape::BOXED_LOCAL),
+ LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+ LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
LintId::of(loops::MANUAL_MEMCPY),
LintId::of(as_conversions::AS_CONVERSIONS),
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+ LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
LintId::of(create_dir::CREATE_DIR),
LintId::of(dbg_macro::DBG_MACRO),
LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
LintId::of(methods::GET_UNWRAP),
LintId::of(methods::UNWRAP_USED),
LintId::of(misc::FLOAT_CMP_CONST),
+ LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+ LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(shadow::SHADOW_SAME),
LintId::of(shadow::SHADOW_UNRELATED),
LintId::of(strings::STRING_ADD),
+ LintId::of(strings::STRING_SLICE),
LintId::of(strings::STRING_TO_STRING),
LintId::of(strings::STR_TO_STRING),
LintId::of(types::RC_BUFFER),
LintId::of(types::RC_MUTEX),
+ LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
+ LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR),
- LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
])
mod float_literal;
mod floating_point_arithmetic;
mod format;
+mod format_args;
mod formatting;
mod from_over_into;
mod from_str_radix_10;
mod identity_op;
mod if_let_mutex;
mod if_not_else;
-mod if_then_panic;
mod if_then_some_else_none;
mod implicit_hasher;
mod implicit_return;
mod loops;
mod macro_use;
mod main_recursion;
+mod manual_assert;
mod manual_async_fn;
mod manual_map;
mod manual_non_exhaustive;
mod map_unit_fn;
mod match_on_vec_items;
mod match_result_ok;
+mod match_str_case_mismatch;
mod matches;
mod mem_forget;
mod mem_replace;
mod temporary_assignment;
mod to_digit_is_some;
mod to_string_in_display;
+mod trailing_empty_array;
mod trait_bounds;
mod transmute;
mod transmuting_null;
mod try_err;
mod types;
+mod undocumented_unsafe_blocks;
mod undropped_manually_drops;
mod unicode;
+mod uninit_vec;
+mod unit_hash;
mod unit_return_expecting_ord;
mod unit_types;
mod unnamed_address;
store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
store.register_late_pass(|| Box::new(unicode::Unicode));
+ store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
+ store.register_late_pass(|| Box::new(unit_hash::UnitHash));
store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
store.register_late_pass(|| Box::new(strings::StringAdd));
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
- store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
store.register_early_pass(|| Box::new(formatting::Formatting));
store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
+ store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
- let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types)));
+ let disallowed_types = conf.disallowed_types.clone();
+ store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone())));
let import_renames = conf.enforced_import_renames.clone();
store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
let scripts = conf.allowed_scripts.clone();
store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
store.register_late_pass(move || Box::new(feature_name::FeatureName));
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
- store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
+ store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
+ store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
+ store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
+ store.register_late_pass(move || Box::new(format_args::FormatArgs));
+ store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+ // add lints here, do not remove this comment, it's used in `new_lint`
}
#[rustfmt::skip]
///
/// Used in `./src/driver.rs`.
pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
+ // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
match ty.kind {
- TyKind::OpaqueDef(item, _) => {
+ TyKind::OpaqueDef(item, bounds) => {
let map = self.cx.tcx.hir();
let item = map.item(item);
walk_item(self, item);
walk_ty(self, ty);
+ self.lts.extend(bounds.iter().filter_map(|bound| match bound {
+ GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+ _ => None,
+ }));
},
TyKind::BareFn(&BareFnTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx);
sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
meth_name,
)
- }
+ },
_ => format!(
"{}.into_iter()",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::PanicExpn;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_expn_of, sugg};
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
+ ///
+ /// ### Why is this bad?
+ /// `assert!` is simpler than `if`-then-`panic!`.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let sad_people: Vec<&str> = vec![];
+ /// if !sad_people.is_empty() {
+ /// panic!("there are sad people: {:?}", sad_people);
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let sad_people: Vec<&str> = vec![];
+ /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+ /// ```
+ pub MANUAL_ASSERT,
+ pedantic,
+ "`panic!` and only a `panic!` in `if`-then statement"
+}
+
+declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
+
+impl LateLintPass<'_> for ManualAssert {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let Expr {
+ kind: ExprKind:: If(cond, Expr {
+ kind: ExprKind::Block(
+ Block {
+ stmts: [stmt],
+ ..
+ },
+ _),
+ ..
+ }, None),
+ ..
+ } = &expr;
+ if is_expn_of(stmt.span, "panic").is_some();
+ if !matches!(cond.kind, ExprKind::Let(_, _, _));
+ if let StmtKind::Semi(semi) = stmt.kind;
+ if !cx.tcx.sess.source_map().is_multiline(cond.span);
+
+ then {
+ let call = if_chain! {
+ if let ExprKind::Block(block, _) = semi.kind;
+ if let Some(init) = block.expr;
+ then {
+ init
+ } else {
+ semi
+ }
+ };
+ let span = if let Some(panic_expn) = PanicExpn::parse(call) {
+ match *panic_expn.format_args.value_args {
+ [] => panic_expn.format_args.format_string_span,
+ [.., last] => panic_expn.format_args.format_string_span.to(last.span),
+ }
+ } else if let ExprKind::Call(_, [format_args]) = call.kind {
+ format_args.span
+ } else {
+ return
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
+ let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
+ if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
+ sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
+ } else {
+ format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
+ }
+ } else {
+ format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_ASSERT,
+ expr.span,
+ "only a `panic!` in `if`-then statement",
+ "try",
+ format!("assert!({}, {});", cond_sugg, sugg),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+}
reindent_multiline(or_body_snippet.into(), true, Some(indent));
let suggestion = if scrutinee.span.from_expansion() {
- // we don't want parenthesis around macro, e.g. `(some_macro!()).unwrap_or(0)`
+ // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
}
else {
/// }
///
/// if let Ok(value) = iter.next() {
- /// vec.push_value)
+ /// vec.push(value)
/// }
/// ```
pub MATCH_RESULT_OK,
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::SymbolStr;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `match` expressions modifying the case of a string with non-compliant arms
+ ///
+ /// ### Why is this bad?
+ /// The arm is unreachable, which is likely a mistake
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let text = "Foo";
+ ///
+ /// match &*text.to_ascii_lowercase() {
+ /// "foo" => {},
+ /// "Bar" => {},
+ /// _ => {},
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let text = "Foo";
+ ///
+ /// match &*text.to_ascii_lowercase() {
+ /// "foo" => {},
+ /// "bar" => {},
+ /// _ => {},
+ /// }
+ /// ```
+ pub MATCH_STR_CASE_MISMATCH,
+ correctness,
+ "creation of a case altering match expression with non-compliant arms"
+}
+
+declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
+
+#[derive(Debug)]
+enum CaseMethod {
+ LowerCase,
+ AsciiLowerCase,
+ UpperCase,
+ AsciiUppercase,
+}
+
+impl LateLintPass<'_> for MatchStrCaseMismatch {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if_chain! {
+ if !in_external_macro(cx.tcx.sess, expr.span);
+ if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
+ if let ty::Str = ty.kind();
+ then {
+ let mut visitor = MatchExprVisitor {
+ cx,
+ case_method: None,
+ };
+
+ visitor.visit_expr(match_expr);
+
+ if let Some(case_method) = visitor.case_method {
+ if let Some((bad_case_span, bad_case_str)) = verify_case(&case_method, arms) {
+ lint(cx, &case_method, bad_case_span, &bad_case_str);
+ }
+ }
+ }
+ }
+ }
+}
+
+struct MatchExprVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ case_method: Option<CaseMethod>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+ match ex.kind {
+ ExprKind::MethodCall(segment, _, [receiver], _)
+ if self.case_altered(&*segment.ident.as_str(), receiver) => {},
+ _ => walk_expr(self, ex),
+ }
+ }
+}
+
+impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
+ fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
+ if let Some(case_method) = get_case_method(segment_ident) {
+ let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
+
+ if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
+ self.case_method = Some(case_method);
+ return true;
+ }
+ }
+
+ false
+ }
+}
+
+fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
+ match segment_ident_str {
+ "to_lowercase" => Some(CaseMethod::LowerCase),
+ "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
+ "to_uppercase" => Some(CaseMethod::UpperCase),
+ "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
+ _ => None,
+ }
+}
+
+fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
+ let case_check = match case_method {
+ CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
+ CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
+ CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
+ CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
+ };
+
+ for arm in arms {
+ if_chain! {
+ if let PatKind::Lit(Expr {
+ kind: ExprKind::Lit(lit),
+ ..
+ }) = arm.pat.kind;
+ if let LitKind::Str(symbol, _) = lit.node;
+ let input = symbol.as_str();
+ if !case_check(&input);
+ then {
+ return Some((lit.span, input));
+ }
+ }
+ }
+
+ None
+}
+
+fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
+ let (method_str, suggestion) = match case_method {
+ CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
+ CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
+ CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
+ CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MATCH_STR_CASE_MISMATCH,
+ bad_case_span,
+ "this `match` arm has a differing case than its expression",
+ &*format!("consider changing the case of this arm to respect `{}`", method_str),
+ format!("\"{}\"", suggestion),
+ Applicability::MachineApplicable,
+ );
+}
-use clippy_utils::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
};
fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
- let type_ranges = type_ranges(&ranges);
- if !type_ranges.is_empty() {
- if let Some((start, end)) = overlapping(&type_ranges) {
+ if !ranges.is_empty() {
+ if let Some((start, end)) = overlapping(&ranges) {
span_lint_and_note(
cx,
MATCH_OVERLAPPING_ARM,
}
if_chain! {
if matching_wild;
- if let ExprKind::Block(block, _) = arm.body.kind;
- if is_panic_block(block);
+ if is_panic_call(arm.body);
then {
// `Err(_)` or `Err(_e)` arm with `panic!` found
span_lint_and_note(cx,
}
// If the block contains only a `panic!` macro (as expression or statement)
-fn is_panic_block(block: &Block<'_>) -> bool {
- match (&block.expr, block.stmts.len(), block.stmts.first()) {
- (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
- (&None, 1, Some(stmt)) => {
- is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
- },
- _ => false,
- }
+fn is_panic_call(expr: &Expr<'_>) -> bool {
+ // Unwrap any wrapping blocks
+ let span = if let ExprKind::Block(block, _) = expr.kind {
+ match (&block.expr, block.stmts.len(), block.stmts.first()) {
+ (&Some(exp), 0, _) => exp.span,
+ (&None, 1, Some(stmt)) => stmt.span,
+ _ => return false,
+ }
+ } else {
+ expr.span
+ };
+
+ is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
}
fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
'b: 'a,
I: Clone + Iterator<Item = &'a Pat<'b>>,
{
- if !has_only_ref_pats(pats.clone()) {
+ if !has_multiple_ref_pats(pats.clone()) {
return;
}
}
/// Gets all arms that are unbounded `PatRange`s.
-fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
+fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
arms.iter()
.filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
};
- let rhs = match range_end {
- RangeEnd::Included => Bound::Included(rhs),
- RangeEnd::Excluded => Bound::Excluded(rhs),
+
+ let lhs_val = lhs.int_value(cx, ty)?;
+ let rhs_val = rhs.int_value(cx, ty)?;
+
+ let rhs_bound = match range_end {
+ RangeEnd::Included => Bound::Included(rhs_val),
+ RangeEnd::Excluded => Bound::Excluded(rhs_val),
};
return Some(SpannedRange {
span: pat.span,
- node: (lhs, rhs),
+ node: (lhs_val, rhs_bound),
});
}
if let PatKind::Lit(value) = pat.kind {
- let value = constant(cx, cx.typeck_results(), value)?.0;
+ let value = constant_full_int(cx, cx.typeck_results(), value)?;
return Some(SpannedRange {
span: pat.span,
- node: (value.clone(), Bound::Included(value)),
+ node: (value, Bound::Included(value)),
});
}
}
pub node: (T, Bound<T>),
}
-type TypedRanges = Vec<SpannedRange<u128>>;
-
-/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
-/// and other types than
-/// `Uint` and `Int` probably don't make sense.
-fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
- ranges
- .iter()
- .filter_map(|range| match range.node {
- (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Included(end)),
- }),
- (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Excluded(end)),
- }),
- (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Unbounded),
- }),
- _ => None,
- })
- .collect()
-}
-
// Checks if arm has the form `None => None`
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
None
}
-fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
+fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
where
'b: 'a,
I: Iterator<Item = &'a Pat<'b>>,
{
- let mut at_least_one_is_true = false;
+ let mut ref_count = 0;
for opt in pats.map(|pat| match pat.kind {
PatKind::Ref(..) => Some(true), // &-patterns
PatKind::Wild => Some(false), // an "anything" wildcard is also fine
}) {
if let Some(inner) = opt {
if inner {
- at_least_one_is_true = true;
+ ref_count += 1;
}
} else {
return false;
}
}
- at_least_one_is_true
+ ref_count > 1
}
pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{
return;
- }
+ },
ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
) =>
{
return;
- }
+ },
_ => false,
};
}
declare_clippy_lint! {
- /// **What it does:** Checks for usages of `str::splitn(2, _)`
- ///
- /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient.
- ///
- /// **Known problems:** None.
+ /// ### What it does
+ /// Checks for usages of `str::splitn(2, _)`
///
- /// **Example:**
+ /// ### Why is this bad?
+ /// `split_once` is both clearer in intent and slightly more efficient.
///
+ /// ### Example
/// ```rust,ignore
/// // Bad
/// let (key, value) = _.splitn(2, '=').next_tuple()?;
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
}
}
- }
+ },
_ => (),
}
}
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_path_def_path, match_def_path, paths};
+use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
use super::UNINIT_ASSUMED_INIT;
if let hir::ExprKind::Call(callee, args) = recv.kind;
if args.is_empty();
if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT);
- if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
+ if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
then {
span_lint(
cx,
}
}
}
-
-fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component),
- ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
- ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
- _ => false,
- }
-}
-use super::MiscEarlyLints;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext;
use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
- match expr.kind {
- ExprKind::Unary(UnOp::Neg, ref inner) => {
- if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
- span_lint(
- cx,
- DOUBLE_NEG,
- expr.span,
- "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
- );
- }
- },
- ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
- _ => (),
+ if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
+ if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
+ span_lint(
+ cx,
+ DOUBLE_NEG,
+ expr.span,
+ "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
+ );
+ }
}
}
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::Lit;
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+ let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
+ val
+ } else {
+ return; // It's useless so shouldn't lint.
+ };
+ // Do not lint when literal is unsuffixed.
+ if !suffix.is_empty() {
+ if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
+ span_lint_and_sugg(
+ cx,
+ SEPARATED_LITERAL_SUFFIX,
+ lit.span,
+ &format!("{} type suffix should not be separated by an underscore", sugg_type),
+ "remove the underscore",
+ format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ UNSEPARATED_LITERAL_SUFFIX,
+ lit.span,
+ &format!("{} type suffix should be separated by an underscore", sugg_type),
+ "add an underscore",
+ format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
mod builtin_type_shadow;
mod double_neg;
+mod literal_suffix;
mod mixed_case_hex_literals;
mod redundant_pattern;
mod unneeded_field_pattern;
mod unneeded_wildcard_pattern;
-mod unseparated_literal_suffix;
mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass};
/// ### What it does
/// Warns if literal suffixes are not separated by an
/// underscore.
+ /// To enforce unseparated literal suffix style,
+ /// see the `separated_literal_suffix` lint.
///
/// ### Why is this bad?
- /// It is much less readable.
+ /// Suffix style should be consistent.
///
/// ### Example
/// ```rust
/// let y = 123832_i32;
/// ```
pub UNSEPARATED_LITERAL_SUFFIX,
- pedantic,
+ restriction,
"literals whose suffix is not separated by an underscore"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Warns if literal suffixes are separated by an underscore.
+ /// To enforce separated literal suffix style,
+ /// see the `unseparated_literal_suffix` lint.
+ ///
+ /// ### Why is this bad?
+ /// Suffix style should be consistent.
+ ///
+ /// ### Example
+ /// ```rust
+ /// // Bad
+ /// let y = 123832_i32;
+ ///
+ /// // Good
+ /// let y = 123832i32;
+ /// ```
+ pub SEPARATED_LITERAL_SUFFIX,
+ restriction,
+ "literals whose suffix is separated by an underscore"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Warns if an integral constant literal starts with `0`.
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
+ SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN,
if in_external_macro(cx.sess, expr.span) {
return;
}
+
+ if let ExprKind::Lit(ref lit) = expr.kind {
+ MiscEarlyLints::check_lit(cx, lit);
+ }
double_neg::check(cx, expr);
}
}
LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "",
};
- unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+ literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
}
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str();
- unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
+ literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}
+++ /dev/null
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::Lit;
-use rustc_errors::Applicability;
-use rustc_lint::EarlyContext;
-
-use super::UNSEPARATED_LITERAL_SUFFIX;
-
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
- let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
- val
- } else {
- return; // It's useless so shouldn't lint.
- };
- // Do not lint when literal is unsuffixed.
- if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
- span_lint_and_sugg(
- cx,
- UNSEPARATED_LITERAL_SUFFIX,
- lit.span,
- &format!("{} type suffix should be separated by an underscore", sugg_type),
- "add an underscore",
- format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
- Applicability::MachineApplicable,
- );
- }
-}
declare_clippy_lint! {
/// ### What it does
- /// it lints if an exported function, method, trait method with default impl,
+ /// It lints if an exported function, method, trait method with default impl,
/// or trait method impl is not `#[inline]`.
///
/// ### Why is this bad?
}
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
check_self_named_mod_exists(cx, path, file);
- }
+ },
_ => {},
}
}
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
+ if in_external_macro(self.cx.sess(), ty.span) {
+ return;
+ }
+
if let hir::TyKind::Rptr(
_,
hir::MutTy {
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
- if let [Adjustment {
- kind: Adjust::Deref(_), ..
- }, Adjustment {
- kind: Adjust::Deref(_), ..
- }, Adjustment {
- kind: Adjust::Borrow(_),
- ..
- }] = *adj3
+ if let [
+ Adjustment {
+ kind: Adjust::Deref(_), ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(_), ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(_),
+ ..
+ },
+ ] = *adj3
{
let help_msg_ty = if matches!(mutability, Mutability::Not) {
format!("&{}", ty)
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
+use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::ops::Deref;
/// Checks for statements which have no effect.
///
/// ### Why is this bad?
- /// Similar to dead code, these statements are actually
+ /// Unlike dead code, these statements are actually
/// executed. However, as they have no effect, all they do is make the code less
/// readable.
///
"statements with no effect"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for binding to underscore prefixed variable without side-effects.
+ ///
+ /// ### Why is this bad?
+ /// Unlike dead code, these bindings are actually
+ /// executed. However, as they have no effect and shouldn't be used further on, all they
+ /// do is make the code less readable.
+ ///
+ /// ### Known problems
+ /// Further usage of this variable is not checked, which can lead to false positives if it is
+ /// used later in the code.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _i_serve_no_purpose = 1;
+ /// ```
+ pub NO_EFFECT_UNDERSCORE_BINDING,
+ pedantic,
+ "binding to `_` prefixed variable with no side-effect"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for expression statements that can be reduced to a
"outer expressions with no effect"
}
+declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]);
+
+impl<'tcx> LateLintPass<'tcx> for NoEffect {
+ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+ if check_no_effect(cx, stmt) {
+ return;
+ }
+ check_unnecessary_operation(cx, stmt);
+ }
+}
+
+fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool {
+ if let StmtKind::Semi(expr) = stmt.kind {
+ if has_no_effect(cx, expr) {
+ span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
+ return true;
+ }
+ } else if let StmtKind::Local(local) = stmt.kind {
+ if_chain! {
+ if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
+ if let Some(init) = local.init;
+ if !local.pat.span.from_expansion();
+ if has_no_effect(cx, init);
+ if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
+ if ident.name.to_ident_string().starts_with('_');
+ then {
+ span_lint_hir(
+ cx,
+ NO_EFFECT_UNDERSCORE_BINDING,
+ init.hir_id,
+ stmt.span,
+ "binding to `_` prefixed variable with no side-effect"
+ );
+ return true;
+ }
+ }
+ }
+ false
+}
+
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if expr.span.from_expansion() {
return false;
}
}
-declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]);
-
-impl<'tcx> LateLintPass<'tcx> for NoEffect {
- fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
- if let StmtKind::Semi(expr) = stmt.kind {
- if has_no_effect(cx, expr) {
- span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
- } else if let Some(reduced) = reduce_expression(cx, expr) {
- for e in &reduced {
- if e.span.from_expansion() {
- return;
- }
- }
- if let ExprKind::Index(..) = &expr.kind {
- let snippet;
- if_chain! {
- if let Some(arr) = snippet_opt(cx, reduced[0].span);
- if let Some(func) = snippet_opt(cx, reduced[1].span);
- then {
- snippet = format!("assert!({}.len() > {});", &arr, &func);
- } else {
- return;
- }
- }
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be written as",
- snippet,
- Applicability::MaybeIncorrect,
- );
- },
- );
+fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+ if_chain! {
+ if let StmtKind::Semi(expr) = stmt.kind;
+ if let Some(reduced) = reduce_expression(cx, expr);
+ if !&reduced.iter().any(|e| e.span.from_expansion());
+ then {
+ if let ExprKind::Index(..) = &expr.kind {
+ let snippet;
+ if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
+ snippet = format!("assert!({}.len() > {});", &arr, &func);
} else {
- let mut snippet = String::new();
- for e in reduced {
- if let Some(snip) = snippet_opt(cx, e.span) {
- snippet.push_str(&snip);
- snippet.push(';');
- } else {
- return;
- }
+ return;
+ }
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be written as",
+ snippet,
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ } else {
+ let mut snippet = String::new();
+ for e in reduced {
+ if let Some(snip) = snippet_opt(cx, e.span) {
+ snippet.push_str(&snip);
+ snippet.push(';');
+ } else {
+ return;
}
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be reduced to",
- snippet,
- Applicability::MachineApplicable,
- );
- },
- );
}
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be reduced to",
+ snippet,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
/// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
/// or specify correct bounds on generic type parameters (`T: Send`).
pub NON_SEND_FIELDS_IN_SEND_TY,
- nursery,
+ suspicious,
"there is field that does not implement `Send` in a `Send` struct"
}
/// expression).
///
/// ### Why is this bad?
- /// Using the dedicated functions of the Option type is clearer and
+ /// Using the dedicated functions of the `Option` type is clearer and
/// more concise than an `if let` expression.
///
/// ### Known problems
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
+use clippy_utils::ty::walk_ptrs_hir_ty;
use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::{
- BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
- ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
+ BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
+ Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
/// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
/// ```
///
+ /// ```ignore
/// // Good
/// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
/// ```
impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
- check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+ check_fn(cx, sig.decl, Some(body_id));
}
}
return; // ignore trait impls
}
}
- check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+ check_fn(cx, sig.decl, Some(body_id));
}
}
} else {
None
};
- check_fn(cx, sig.decl, item.hir_id(), body_id);
+ check_fn(cx, sig.decl, body_id);
}
}
}
#[allow(clippy::too_many_lines)]
-fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
- let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
- let sig = cx.tcx.fn_sig(fn_def_id);
- let fn_ty = sig.skip_binder();
+fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
- for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
+ for (idx, arg) in decl.inputs.iter().enumerate() {
// Honor the allow attribute on parameters. See issue 5644.
if let Some(body) = &body {
if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
}
}
- if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
- if is_type_diagnostic_item(cx, ty, sym::Vec) {
+ let (item_name, path) = if_chain! {
+ if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
+ if let Res::Def(_, did) = path.res;
+ if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
+ then {
+ (item_name, path)
+ } else {
+ continue
+ }
+ };
+
+ match item_name {
+ sym::Vec => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then(
cx,
},
);
}
- } else if is_type_diagnostic_item(cx, ty, sym::String) {
+ },
+ sym::String => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
span_lint_and_then(
cx,
},
);
}
- } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) {
+ },
+ sym::PathBuf => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
span_lint_and_then(
cx,
},
);
}
- } else if match_type(cx, ty, &paths::COW) {
+ },
+ sym::Cow => {
if_chain! {
- if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
- if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
- if let [ref bx] = *pp.segments;
+ if let [ref bx] = *path.segments;
if let Some(params) = bx.args;
if !params.parenthesized;
if let Some(inner) = params.args.iter().find_map(|arg| match arg {
);
}
}
- }
+ },
+ _ => {},
}
}
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, path_to_local_id};
+use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
/// }
/// ```
///
+ /// ```ignore
+ /// if result.is_err() {
+ /// return result;
+ /// }
+ /// ```
+ ///
/// If it matches, it will suggest to use the question mark operator instead
- fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind;
- if segment.ident.name == sym!(is_none);
- if Self::expression_returns_none(cx, then);
if let Some(subject) = args.get(0);
- if Self::is_option(cx, subject);
-
+ if (Self::option_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_none)) ||
+ (Self::result_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_err));
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
}
}
- fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
= higher::IfLet::hir(cx, expr);
- if Self::is_option(cx, let_expr);
-
if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind;
- if is_lang_ctor(cx, path1, OptionSome);
+ if (Self::option_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, OptionSome)) ||
+ (Self::result_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, ResultOk));
+
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
-
if let ExprKind::Block(block, None) = if_then.kind;
if block.stmts.is_empty();
if let Some(trailing_expr) = &block.expr;
if path_to_local_id(trailing_expr, bind_id);
-
- if Self::expression_returns_none(cx, if_else);
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
- let replacement = format!(
- "{}{}?",
- receiver_str,
- if by_ref { ".as_ref()" } else { "" },
- );
+ let replacement = format!("{}{}?", receiver_str, if by_ref { ".as_ref()" } else { "" },);
span_lint_and_sugg(
cx,
}
}
+ fn result_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+ Self::is_result(cx, expr) && Self::expression_returns_unmodified_err(cx, nested_expr, expr)
+ }
+
+ fn option_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+ Self::is_option(cx, expr) && Self::expression_returns_none(cx, nested_expr)
+ }
+
fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expression);
is_type_diagnostic_item(cx, expr_ty, sym::Option)
}
+ fn is_result(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
+ let expr_ty = cx.typeck_results().expr_ty(expression);
+
+ is_type_diagnostic_item(cx, expr_ty, sym::Result)
+ }
+
fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
match expression.kind {
ExprKind::Block(block, _) => {
}
}
+ fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
+ match expr.kind {
+ ExprKind::Block(block, _) => {
+ if let Some(return_expression) = Self::return_expression(block) {
+ return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
+ }
+
+ false
+ },
+ ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
+ ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
+ _ => false,
+ }
+ }
+
fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
// Check if last expression is a return statement. Then, return the expression
if_chain! {
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- Self::check_is_none_and_early_return_none(cx, expr);
- Self::check_if_let_some_and_early_return_none(cx, expr);
+ Self::check_is_none_or_err_and_early_return(cx, expr);
+ Self::check_if_let_some_or_err_and_early_return(cx, expr);
}
}
use crate::rustc_lint::LintContext;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{in_macro, sugg};
+use clippy_utils::sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Block, ExprKind};
impl LateLintPass<'_> for SemicolonIfNothingReturned {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if_chain! {
- if !in_macro(block.span);
+ if !block.span.from_expansion();
if let Some(expr) = block.expr;
let t_expr = cx.typeck_results().expr_ty(expr);
if t_expr.is_unit();
(SHADOW_SAME, msg)
},
Some(expr) if is_local_used(cx, expr, shadowed) => {
- let msg = format!(
- "`{}` is shadowed by `{}` which reuses the original value",
- snippet(cx, pat.span, "_"),
- snippet(cx, expr.span, "..")
- );
+ let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
(SHADOW_REUSE, msg)
},
_ => {
"calling `as_bytes` on a string literal instead of using a byte string literal"
}
-declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for slice operations on strings
+ ///
+ /// ### Why is this bad?
+ /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
+ /// counts and string indices. This may lead to panics, and should warrant some test cases
+ /// containing wide UTF-8 characters. This lint is most useful in code that should avoid
+ /// panics at all costs.
+ ///
+ /// ### Known problems
+ /// Probably lots of false positives. If an index comes from a known valid position (e.g.
+ /// obtained via `char_indices` over the same string), it is totally OK.
+ ///
+ /// # Example
+ /// ```rust,should_panic
+ /// &"Ölkanne"[1..];
+ /// ```
+ pub STRING_SLICE,
+ restriction,
+ "slicing a string"
+}
+
+declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
impl<'tcx> LateLintPass<'tcx> for StringAdd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), e.span) {
return;
}
-
- if let ExprKind::Binary(
- Spanned {
- node: BinOpKind::Add, ..
- },
- left,
- _,
- ) = e.kind
- {
- if is_string(cx, left) {
- if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
- let parent = get_parent_expr(cx, e);
- if let Some(p) = parent {
- if let ExprKind::Assign(target, _, _) = p.kind {
- // avoid duplicate matches
- if SpanlessEq::new(cx).eq_expr(target, left) {
- return;
+ match e.kind {
+ ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Add, ..
+ },
+ left,
+ _,
+ ) => {
+ if is_string(cx, left) {
+ if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
+ let parent = get_parent_expr(cx, e);
+ if let Some(p) = parent {
+ if let ExprKind::Assign(target, _, _) = p.kind {
+ // avoid duplicate matches
+ if SpanlessEq::new(cx).eq_expr(target, left) {
+ return;
+ }
}
}
}
+ span_lint(
+ cx,
+ STRING_ADD,
+ e.span,
+ "you added something to a string. Consider using `String::push_str()` instead",
+ );
}
- span_lint(
- cx,
- STRING_ADD,
- e.span,
- "you added something to a string. Consider using `String::push_str()` instead",
- );
- }
- } else if let ExprKind::Assign(target, src, _) = e.kind {
- if is_string(cx, target) && is_add(cx, src, target) {
- span_lint(
- cx,
- STRING_ADD_ASSIGN,
- e.span,
- "you assigned the result of adding something to this string. Consider using \
- `String::push_str()` instead",
- );
- }
+ },
+ ExprKind::Assign(target, src, _) => {
+ if is_string(cx, target) && is_add(cx, src, target) {
+ span_lint(
+ cx,
+ STRING_ADD_ASSIGN,
+ e.span,
+ "you assigned the result of adding something to this string. Consider using \
+ `String::push_str()` instead",
+ );
+ }
+ },
+ ExprKind::Index(target, _idx) => {
+ let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
+ if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
+ span_lint(
+ cx,
+ STRING_SLICE,
+ e.span,
+ "indexing into a string may panic if the index is within a UTF-8 character",
+ );
+ }
+ },
+ _ => {},
}
}
}
Some(format!(
"{}{}{}",
snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability),
- new_ident.to_string(),
+ new_ident,
snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability),
))
})
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{HirId, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Const;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+ ///
+ /// ### Why is this bad?
+ /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct RarelyUseful {
+ /// some_field: u32,
+ /// last: [u32; 0],
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// #[repr(C)]
+ /// struct MoreOftenUseful {
+ /// some_field: usize,
+ /// last: [u32; 0],
+ /// }
+ /// ```
+ pub TRAILING_EMPTY_ARRAY,
+ nursery,
+ "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
+}
+declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
+
+impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
+ span_lint_and_help(
+ cx,
+ TRAILING_EMPTY_ARRAY,
+ item.span,
+ "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
+ None,
+ &format!(
+ "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
+ cx.tcx.def_path_str(item.def_id.to_def_id())
+ ),
+ );
+ }
+ }
+}
+
+fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
+ if_chain! {
+ // First check if last field is an array
+ if let ItemKind::Struct(data, _) = &item.kind;
+ if let Some(last_field) = data.fields().last();
+ if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
+
+ // Then check if that that array zero-sized
+ let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
+ let length = Const::from_anon_const(cx.tcx, length_ldid);
+ let length = length.try_eval_usize(cx.tcx, cx.param_env);
+ if let Some(length) = length;
+ then {
+ length == 0
+ } else {
+ false
+ }
+ }
+}
+
+fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+ cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr))
+}
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
+mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
mod transmute_ptr_to_ref;
mod transmute_ref_to_ref;
"transmutes from a float to an integer"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for transmutes from a number to an array of `u8`
+ ///
+ /// ### Why this is bad?
+ /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+ /// is intuitive and safe.
+ ///
+ /// ### Example
+ /// ```rust
+ /// unsafe {
+ /// let x: [u8; 8] = std::mem::transmute(1i64);
+ /// }
+ ///
+ /// // should be
+ /// let x: [u8; 8] = 0i64.to_ne_bytes();
+ /// ```
+ pub TRANSMUTE_NUM_TO_BYTES,
+ complexity,
+ "transmutes from a number to an array of `u8`"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for transmutes from a pointer to a pointer, or
TRANSMUTE_INT_TO_BOOL,
TRANSMUTE_INT_TO_FLOAT,
TRANSMUTE_FLOAT_TO_INT,
+ TRANSMUTE_NUM_TO_BYTES,
UNSOUND_COLLECTION_TRANSMUTE,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
]);
linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
+ linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
if !linted {
diag.span_suggestion(
e.span,
"consider using",
- format!("std::char::from_u32({}).unwrap()", arg.to_string()),
+ format!("std::char::from_u32({}).unwrap()", arg),
Applicability::Unspecified,
);
},
diag.span_suggestion(
e.span,
"consider using",
- format!("{}::from_bits({})", to_ty, arg.to_string()),
+ format!("{}::from_bits({})", to_ty, arg),
Applicability::Unspecified,
);
},
--- /dev/null
+use super::TRANSMUTE_NUM_TO_BYTES;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, UintTy};
+
+/// Checks for `transmute_int_to_float` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ e: &'tcx Expr<'_>,
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+ args: &'tcx [Expr<'_>],
+ const_context: bool,
+) -> bool {
+ match (&from_ty.kind(), &to_ty.kind()) {
+ (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
+ if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
+ return false;
+ }
+ if matches!(from_ty.kind(), ty::Float(_)) && const_context {
+ // TODO: Remove when const_float_bits_conv is stabilized
+ // rust#72447
+ return false;
+ }
+
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_NUM_TO_BYTES,
+ e.span,
+ &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ |diag| {
+ let arg = sugg::Sugg::hir(cx, &args[0], "..");
+ diag.span_suggestion(
+ e.span,
+ "consider using `to_ne_bytes()`",
+ format!("{}.to_ne_bytes()", arg),
+ Applicability::Unspecified,
+ );
+ },
+ );
+ true
+ },
+ _ => false,
+ }
+}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::source::{indent_of, reindent_multiline, snippet};
+use clippy_utils::{in_macro, is_lint_allowed};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
+use rustc_lexer::TokenKind;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{BytePos, Span};
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `unsafe` blocks without a `// Safety: ` comment
+ /// explaining why the unsafe operations performed inside
+ /// the block are safe.
+ ///
+ /// ### Why is this bad?
+ /// Undocumented unsafe blocks can make it difficult to
+ /// read and maintain code, as well as uncover unsoundness
+ /// and bugs.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// let ptr = unsafe { NonNull::new_unchecked(a) };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// // Safety: references are guaranteed to be non-null.
+ /// let ptr = unsafe { NonNull::new_unchecked(a) };
+ /// ```
+ pub UNDOCUMENTED_UNSAFE_BLOCKS,
+ restriction,
+ "creating an unsafe block without explaining why it is safe"
+}
+
+impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
+
+#[derive(Default)]
+pub struct UndocumentedUnsafeBlocks {
+ pub local_level: u32,
+ pub local_span: Option<Span>,
+ // The local was already checked for an overall safety comment
+ // There is no need to continue checking the blocks in the local
+ pub local_checked: bool,
+ // Since we can only check the blocks from expanded macros
+ // We have to omit the suggestion due to the actual definition
+ // Not being available to us
+ pub macro_expansion: bool,
+}
+
+impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
+ fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
+ if_chain! {
+ if !self.local_checked;
+ if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
+ if !in_external_macro(cx.tcx.sess, block.span);
+ if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
+ if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
+ if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
+ then {
+ let mut span = block.span;
+
+ if let Some(local_span) = self.local_span {
+ span = local_span;
+
+ let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
+
+ if result.unwrap_or(true) {
+ self.local_checked = true;
+ return;
+ }
+ }
+
+ self.lint(cx, span);
+ }
+ }
+ }
+
+ fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
+ if_chain! {
+ if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
+ if !in_external_macro(cx.tcx.sess, local.span);
+ if let Some(init) = local.init;
+ then {
+ self.visit_expr(init);
+
+ if self.local_level > 0 {
+ self.local_span = Some(local.span);
+ }
+ }
+ }
+ }
+
+ fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
+ self.local_level = self.local_level.saturating_sub(1);
+
+ if self.local_level == 0 {
+ self.local_checked = false;
+ self.local_span = None;
+ }
+ }
+}
+
+impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
+ type Map = Map<'hir>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, ex: &'v Expr<'v>) {
+ match ex.kind {
+ ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
+ _ => walk_expr(self, ex),
+ }
+ }
+}
+
+impl UndocumentedUnsafeBlocks {
+ fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
+ let map = tcx.hir();
+ let source_map = tcx.sess.source_map();
+
+ let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
+
+ let between_span = if in_macro(block_span) {
+ self.macro_expansion = true;
+ enclosing_scope_span.with_hi(block_span.hi())
+ } else {
+ self.macro_expansion = false;
+ enclosing_scope_span.to(block_span)
+ };
+
+ let file_name = source_map.span_to_filename(between_span);
+ let source_file = source_map.get_source_file(&file_name)?;
+
+ let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
+ let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
+ let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
+
+ let mut pos = 0;
+ let mut comment = false;
+
+ for token in rustc_lexer::tokenize(&src_str) {
+ match token.kind {
+ TokenKind::LineComment { doc_style: None }
+ | TokenKind::BlockComment {
+ doc_style: None,
+ terminated: true,
+ } => {
+ let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
+
+ if comment_str.contains("SAFETY:") {
+ comment = true;
+ }
+ },
+ // We need to add all whitespace to `pos` before checking the comment's line number
+ TokenKind::Whitespace => {},
+ _ => {
+ if comment {
+ // Get the line number of the "comment" (really wherever the trailing whitespace ended)
+ let comment_line_num = source_file
+ .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
+ .0;
+ // Find the block/local's line number
+ let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
+
+ // Check the comment is immediately followed by the block/local
+ if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
+ return Some(true);
+ }
+
+ comment = false;
+ }
+ },
+ }
+
+ pos += token.len;
+ }
+
+ Some(false)
+ }
+
+ fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
+ let source_map = cx.tcx.sess.source_map();
+
+ if source_map.is_multiline(span) {
+ span = source_map.span_until_char(span, '\n');
+ }
+
+ if self.macro_expansion {
+ span_lint_and_help(
+ cx,
+ UNDOCUMENTED_UNSAFE_BLOCKS,
+ span,
+ "unsafe block in macro expansion missing a safety comment",
+ None,
+ "consider adding a safety comment in the macro definition",
+ );
+ } else {
+ let block_indent = indent_of(cx, span);
+ let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
+
+ span_lint_and_sugg(
+ cx,
+ UNDOCUMENTED_UNSAFE_BLOCKS,
+ span,
+ "unsafe block missing a safety comment",
+ "consider adding a safety comment",
+ reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+}
/// let x = String::from("\u{20ac}");
/// ```
pub NON_ASCII_LITERAL,
- pedantic,
+ restriction,
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
+use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
+use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Span};
+
+// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+ /// This is commonly caused by calling `set_len()` right after allocating or
+ /// reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+ ///
+ /// ### Why is this bad?
+ /// It creates a `Vec` with uninitialized data, which leads to
+ /// undefined behavior with most safe operations. Notably, uninitialized
+ /// `Vec<u8>` must not be used with generic `Read`.
+ ///
+ /// Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+ /// creates out-of-bound values that lead to heap memory corruption when used.
+ ///
+ /// ### Known Problems
+ /// This lint only checks directly adjacent statements.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ /// unsafe { vec.set_len(1000); }
+ /// reader.read(&mut vec); // undefined behavior!
+ /// ```
+ ///
+ /// ### How to fix?
+ /// 1. Use an initialized buffer:
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = vec![0; 1000];
+ /// reader.read(&mut vec);
+ /// ```
+ /// 2. Wrap the content in `MaybeUninit`:
+ /// ```rust,ignore
+ /// let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+ /// vec.set_len(1000); // `MaybeUninit` can be uninitialized
+ /// ```
+ /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ /// let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit<u8>]`
+ /// // perform initialization with `remaining`
+ /// vec.set_len(...); // Safe to call `set_len()` on initialized part
+ /// ```
+ pub UNINIT_VEC,
+ correctness,
+ "Vec with uninitialized data"
+}
+
+declare_lint_pass!(UninitVec => [UNINIT_VEC]);
+
+// FIXME: update to a visitor-based implementation.
+// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
+impl<'tcx> LateLintPass<'tcx> for UninitVec {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+ if !in_external_macro(cx.tcx.sess, block.span) {
+ for w in block.stmts.windows(2) {
+ if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
+ handle_uninit_vec_pair(cx, &w[0], expr);
+ }
+ }
+
+ if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
+ handle_uninit_vec_pair(cx, stmt, expr);
+ }
+ }
+ }
+}
+
+fn handle_uninit_vec_pair(
+ cx: &LateContext<'tcx>,
+ maybe_init_or_reserve: &'tcx Stmt<'tcx>,
+ maybe_set_len: &'tcx Expr<'tcx>,
+) {
+ if_chain! {
+ if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
+ if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
+ if vec.location.eq_expr(cx, set_len_self);
+ if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
+ if let ty::Adt(_, substs) = vec_ty.kind();
+ // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
+ if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
+ then {
+ if vec.has_capacity() {
+ // with_capacity / reserve -> set_len
+
+ // Check T of Vec<T>
+ if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
+ // FIXME: #7698, false positive of the internal lints
+ #[allow(clippy::collapsible_span_lint_calls)]
+ span_lint_and_then(
+ cx,
+ UNINIT_VEC,
+ vec![call_span, maybe_init_or_reserve.span],
+ "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
+ |diag| {
+ diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
+ },
+ );
+ }
+ } else {
+ // new / default -> set_len
+ span_lint(
+ cx,
+ UNINIT_VEC,
+ vec![call_span, maybe_init_or_reserve.span],
+ "calling `set_len()` on empty `Vec` creates out-of-bound values",
+ );
+ }
+ }
+ }
+}
+
+/// The target `Vec` that is initialized or reserved
+#[derive(Clone, Copy)]
+struct TargetVec<'tcx> {
+ location: VecLocation<'tcx>,
+ /// `None` if `reserve()`
+ init_kind: Option<VecInitKind>,
+}
+
+impl TargetVec<'_> {
+ pub fn has_capacity(self) -> bool {
+ !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default))
+ }
+}
+
+#[derive(Clone, Copy)]
+enum VecLocation<'tcx> {
+ Local(HirId),
+ Expr(&'tcx Expr<'tcx>),
+}
+
+impl<'tcx> VecLocation<'tcx> {
+ pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ match self {
+ VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
+ VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
+ }
+ }
+}
+
+/// Finds the target location where the result of `Vec` initialization is stored
+/// or `self` expression for `Vec::reserve()`.
+fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
+ match stmt.kind {
+ StmtKind::Local(local) => {
+ if_chain! {
+ if let Some(init_expr) = local.init;
+ if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
+ if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
+ then {
+ return Some(TargetVec {
+ location: VecLocation::Local(hir_id),
+ init_kind: Some(init_kind),
+ })
+ }
+ }
+ },
+ StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
+ ExprKind::Assign(lhs, rhs, _span) => {
+ if let Some(init_kind) = get_vec_init_kind(cx, rhs) {
+ return Some(TargetVec {
+ location: VecLocation::Expr(lhs),
+ init_kind: Some(init_kind),
+ });
+ }
+ },
+ ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+ return Some(TargetVec {
+ location: VecLocation::Expr(self_expr),
+ init_kind: None,
+ });
+ },
+ _ => (),
+ },
+ StmtKind::Item(_) => (),
+ }
+ None
+}
+
+fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
+ is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
+ && path.ident.name.as_str() == "reserve"
+}
+
+/// Returns self if the expression is `Vec::set_len()`
+fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
+ // peel unsafe blocks in `unsafe { vec.set_len() }`
+ let expr = peel_hir_expr_while(expr, |e| {
+ if let ExprKind::Block(block, _) = e.kind {
+ // Extract the first statement/expression
+ match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+ (None, Some(expr)) => Some(expr),
+ (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
+ _ => None,
+ }
+ } else {
+ None
+ }
+ });
+ match expr.kind {
+ ExprKind::MethodCall(path, _, [self_expr, _], _) => {
+ let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
+ if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
+ Some((self_expr, expr.span))
+ } else {
+ None
+ }
+ },
+ _ => None,
+ }
+}
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `().hash(_)`.
+ ///
+ /// ### Why is this bad?
+ /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::hash::Hash;
+ /// # use std::collections::hash_map::DefaultHasher;
+ /// # enum Foo { Empty, WithValue(u8) }
+ /// # use Foo::*;
+ /// # let mut state = DefaultHasher::new();
+ /// # let my_enum = Foo::Empty;
+ /// match my_enum {
+ /// Empty => ().hash(&mut state),
+ /// WithValue(x) => x.hash(&mut state),
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::hash::Hash;
+ /// # use std::collections::hash_map::DefaultHasher;
+ /// # enum Foo { Empty, WithValue(u8) }
+ /// # use Foo::*;
+ /// # let mut state = DefaultHasher::new();
+ /// # let my_enum = Foo::Empty;
+ /// match my_enum {
+ /// Empty => 0_u8.hash(&mut state),
+ /// WithValue(x) => x.hash(&mut state),
+ /// }
+ /// ```
+ pub UNIT_HASH,
+ correctness,
+ "hashing a unit value, which does nothing"
+}
+declare_lint_pass!(UnitHash => [UNIT_HASH]);
+
+impl LateLintPass<'tcx> for UnitHash {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if_chain! {
+ if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
+ if name_ident.ident.name == sym::hash;
+ if let [recv, state_param] = args;
+ if cx.typeck_results().expr_ty(recv).is_unit();
+ then {
+ span_lint_and_then(
+ cx,
+ UNIT_HASH,
+ expr.span,
+ "this call to `hash` on the unit type will do nothing",
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "remove the call to `hash` or consider using",
+ format!(
+ "0_u8.hash({})",
+ snippet(cx, state_param.span, ".."),
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note("the implementation of `Hash` for `()` is a no-op");
+ }
+ );
+ }
+ }
+ }
+}
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
let unstable = name == "sort_unstable_by";
+ if_chain! {
if let ExprKind::Path(QPath::Resolved(_, Path {
segments: [PathSegment { ident: left_name, .. }], ..
- })) = &left_expr.kind {
- if left_name == left_ident {
+ })) = &left_expr.kind;
+ if left_name == left_ident;
+ if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+ implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+ });
+ then {
return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
}
}
declare_clippy_lint! {
/// ### What it does
- /// Checks for functions of type Result that contain `expect()` or `unwrap()`
+ /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
///
/// ### Why is this bad?
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
WithReason { path: String, reason: Option<String> },
}
+/// A single disallowed type, used by the `DISALLOWED_TYPE` lint.
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum DisallowedType {
+ Simple(String),
+ WithReason { path: String, reason: Option<String> },
+}
+
/// Conf with parse errors
#[derive(Default)]
pub struct TryConf {
/// Lint: DISALLOWED_TYPE.
///
/// The list of disallowed types, written as fully qualified paths.
- (disallowed_types: Vec<String> = Vec::new()),
+ (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
/// Lint: UNREADABLE_LITERAL.
///
/// Should the fraction of a decimal be linted to include separators.
///
/// The list of imports to always rename, a fully qualified path followed by the rename.
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
- /// Lint: RESTRICTED_SCRIPTS.
+ /// Lint: DISALLOWED_SCRIPT_IDENTS.
///
/// The list of unicode scripts allowed to be used in the scope.
- (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
+ (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
/// Lint: NON_SEND_FIELDS_IN_SEND_TY.
///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
// Check if the matched type is a diagnostic item
- let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
- if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
+ if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
then {
// TODO: check paths constants from external crates.
let cx_snippet = snippet(cx, context.span, "_");
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
let mut docs = String::from(&*lines.next()?.as_str());
let mut in_code_block = false;
+ let mut is_code_block_rust = false;
for line in lines {
- docs.push('\n');
let line = line.as_str();
let line = &*line;
+
+ // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
+ if is_code_block_rust && line.trim_start().starts_with("# ") {
+ continue;
+ }
+
+ // The line should be represented in the lint list, even if it's just an empty line
+ docs.push('\n');
if let Some(info) = line.trim_start().strip_prefix("```") {
in_code_block = !in_code_block;
+ is_code_block_rust = false;
if in_code_block {
let lang = info
.trim()
.unwrap_or("rust");
docs.push_str("```");
docs.push_str(lang);
+
+ is_code_block_rust = lang == "rust";
continue;
}
}
if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
then {
// report the error around the `vec!` not inside `<std macros>:`
- let span = arg.span
- .ctxt()
- .outer_expn_data()
- .call_site
- .ctxt()
- .outer_expn_data()
- .call_site;
+ let span = arg.span.ctxt().outer_expn_data().call_site;
self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
}
}
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths};
+use clippy_utils::{path_to_local, path_to_local_id};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span};
-use std::convert::TryInto;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
searcher: Option<VecPushSearcher>,
}
-#[derive(Clone, Copy)]
-enum VecInitKind {
- New,
- WithCapacity(u64),
-}
struct VecPushSearcher {
local_id: HirId,
init: VecInitKind,
fn display_err(&self, cx: &LateContext<'_>) {
match self.init {
_ if self.found == 0 => return,
- VecInitKind::WithCapacity(x) if x > self.found => return,
+ VecInitKind::WithLiteralCapacity(x) if x > self.found => return,
+ VecInitKind::WithExprCapacity(_) => return,
_ => (),
};
}
}
}
-
-fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
- if let ExprKind::Call(func, args) = expr.kind {
- match func.kind {
- ExprKind::Path(QPath::TypeRelative(ty, name))
- if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
- {
- if name.ident.name == sym::new {
- return Some(VecInitKind::New);
- } else if name.ident.name.as_str() == "with_capacity" {
- return args.get(0).and_then(|arg| {
- if_chain! {
- if let ExprKind::Lit(lit) = &arg.kind;
- if let LitKind::Int(num, _) = lit.node;
- then {
- Some(VecInitKind::WithCapacity(num.try_into().ok()?))
- } else {
- None
- }
- }
- });
- }
- }
- ExprKind::Path(QPath::Resolved(_, path))
- if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
- && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
- {
- return Some(VecInitKind::New);
- }
- _ => (),
- }
- }
- None
-}
[package]
name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
edition = "2021"
publish = false
+++ /dev/null
-/// Returns the index of the character after the first camel-case component of `s`.
-#[must_use]
-pub fn until(s: &str) -> usize {
- let mut iter = s.char_indices();
- if let Some((_, first)) = iter.next() {
- if !first.is_uppercase() {
- return 0;
- }
- } else {
- return 0;
- }
- let mut up = true;
- let mut last_i = 0;
- for (i, c) in iter {
- if up {
- if c.is_lowercase() {
- up = false;
- } else {
- return last_i;
- }
- } else if c.is_uppercase() {
- up = true;
- last_i = i;
- } else if !c.is_lowercase() {
- return i;
- }
- }
- if up { last_i } else { s.len() }
-}
-
-/// Returns index of the last camel-case component of `s`.
-#[must_use]
-pub fn from(s: &str) -> usize {
- let mut iter = s.char_indices().rev();
- if let Some((_, first)) = iter.next() {
- if !first.is_lowercase() {
- return s.len();
- }
- } else {
- return s.len();
- }
- let mut down = true;
- let mut last_i = s.len();
- for (i, c) in iter {
- if down {
- if c.is_uppercase() {
- down = false;
- last_i = i;
- } else if !c.is_lowercase() {
- return last_i;
- }
- } else if c.is_lowercase() {
- down = true;
- } else if c.is_uppercase() {
- last_i = i;
- } else {
- return last_i;
- }
- }
- last_i
-}
-
-#[cfg(test)]
-mod test {
- use super::{from, until};
-
- #[test]
- fn from_full() {
- assert_eq!(from("AbcDef"), 0);
- assert_eq!(from("Abc"), 0);
- assert_eq!(from("ABcd"), 0);
- assert_eq!(from("ABcdEf"), 0);
- assert_eq!(from("AabABcd"), 0);
- }
-
- #[test]
- fn from_partial() {
- assert_eq!(from("abcDef"), 3);
- assert_eq!(from("aDbc"), 1);
- assert_eq!(from("aabABcd"), 3);
- }
-
- #[test]
- fn from_not() {
- assert_eq!(from("AbcDef_"), 7);
- assert_eq!(from("AbcDD"), 5);
- }
-
- #[test]
- fn from_caps() {
- assert_eq!(from("ABCD"), 4);
- }
-
- #[test]
- fn until_full() {
- assert_eq!(until("AbcDef"), 6);
- assert_eq!(until("Abc"), 3);
- }
-
- #[test]
- fn until_not() {
- assert_eq!(until("abcDef"), 0);
- assert_eq!(until("aDbc"), 0);
- }
-
- #[test]
- fn until_partial() {
- assert_eq!(until("AbcDef_"), 6);
- assert_eq!(until("CallTypeC"), 8);
- assert_eq!(until("AbcDD"), 3);
- }
-
- #[test]
- fn until_caps() {
- assert_eq!(until("ABCD"), 0);
- }
-}
_ => None,
}
}
+
+ /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
+ pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
+ if let Constant::Int(const_int) = *self {
+ match *val_type.kind() {
+ ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+ ty::Uint(_) => Some(FullInt::U(const_int)),
+ _ => None,
+ }
+ } else {
+ None
+ }
+ }
}
/// Parses a `LitKind` to a `Constant`.
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}
+pub fn constant_full_int(
+ lcx: &LateContext<'tcx>,
+ typeck_results: &ty::TypeckResults<'tcx>,
+ e: &Expr<'_>,
+) -> Option<FullInt> {
+ constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
+}
+
+#[derive(Copy, Clone, Debug, Eq)]
+pub enum FullInt {
+ S(i128),
+ U(u128),
+}
+
+impl PartialEq for FullInt {
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl PartialOrd for FullInt {
+ #[must_use]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for FullInt {
+ #[must_use]
+ fn cmp(&self, other: &Self) -> Ordering {
+ use FullInt::{S, U};
+
+ fn cmp_s_u(s: i128, u: u128) -> Ordering {
+ u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
+ }
+
+ match (*self, *other) {
+ (S(s), S(o)) => s.cmp(&o),
+ (U(s), U(o)) => s.cmp(&o),
+ (S(s), U(o)) => cmp_s_u(s, o),
+ (U(s), S(o)) => cmp_s_u(o, s).reverse(),
+ }
+ }
+}
+
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
pub fn constant_context<'a, 'tcx>(
lcx: &'a LateContext<'tcx>,
/// 6 | let other_f64_nan = 0.0f64 / 0.0;
/// | ^^^^^^^^^^^^
/// |
-/// = help: Consider using `f64::NAN` if you would like a constant representing NaN
+/// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T,
-//! This module contains functions that retrieves specifiec elements.
+//! This module contains functions that retrieve specific elements.
#![deny(clippy::missing_docs_in_private_items)]
-use crate::{is_expn_of, match_def_path, paths};
+use crate::ty::is_type_diagnostic_item;
+use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir;
-use rustc_hir::{Arm, Block, BorrowKind, Expr, ExprKind, LoopSource, MatchSource, Node, Pat, StmtKind, UnOp};
+use rustc_hir::{
+ Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
+};
use rustc_lint::LateContext;
-use rustc_span::{sym, ExpnKind, Span, Symbol};
+use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
/// The essential nodes of a desugared for loop as well as the entire span:
/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
pub format_string_parts: &'tcx [Expr<'tcx>],
/// Symbols corresponding to [`Self::format_string_parts`]
pub format_string_symbols: Vec<Symbol>,
+ /// Match arm patterns, the `arg0`, etc. from the next field `args`
+ pub arg_names: &'tcx [Pat<'tcx>],
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
pub args: &'tcx [Expr<'tcx>],
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
_ => None,
})
.collect();
+ if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
if let ExprKind::Array(args) = arm.body.kind;
then {
Some(FormatArgsExpn {
value_args,
format_string_parts,
format_string_symbols,
+ arg_names,
args,
fmt_expr,
})
}
}
}
+
+ /// Returns a vector of `FormatArgsArg`.
+ pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
+ if let Some(expr) = self.fmt_expr {
+ if_chain! {
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
+ if let ExprKind::Array(exprs) = expr.kind;
+ then {
+ exprs.iter().map(|fmt| {
+ if_chain! {
+ // struct `core::fmt::rt::v1::Argument`
+ if let ExprKind::Struct(_, fields, _) = fmt.kind;
+ if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
+ if let ExprKind::Lit(lit) = &position_field.expr.kind;
+ if let LitKind::Int(position, _) = lit.node;
+ if let Ok(i) = usize::try_from(position);
+ let arg = &self.args[i];
+ if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
+ if let Some(j) = self
+ .arg_names
+ .iter()
+ .position(|pat| path_to_local_id(arg_name, pat.hir_id));
+ then {
+ Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
+ } else {
+ None
+ }
+ }
+ }).collect()
+ } else {
+ None
+ }
+ }
+ } else {
+ Some(
+ self.value_args
+ .iter()
+ .zip(self.args.iter())
+ .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None })
+ .collect(),
+ )
+ }
+ }
+}
+
+/// Type representing a `FormatArgsExpn`'s format arguments
+pub struct FormatArgsArg<'tcx> {
+ /// An element of `value_args` according to `position`
+ pub value: &'tcx Expr<'tcx>,
+ /// An element of `args` according to `position`
+ pub arg: &'tcx Expr<'tcx>,
+ /// An element of `fmt_expn`
+ pub fmt: Option<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsArg<'tcx> {
+ /// Returns true if any formatting parameters are used that would have an effect on strings,
+ /// like `{:+2}` instead of just `{}`.
+ pub fn has_string_formatting(&self) -> bool {
+ self.fmt.map_or(false, |fmt| {
+ // `!` because these conditions check that `self` is unformatted.
+ !if_chain! {
+ // struct `core::fmt::rt::v1::Argument`
+ if let ExprKind::Struct(_, fields, _) = fmt.kind;
+ if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
+ // struct `core::fmt::rt::v1::FormatSpec`
+ if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
+ let mut precision_found = false;
+ let mut width_found = false;
+ if subfields.iter().all(|field| {
+ match field.ident.name {
+ sym::precision => {
+ precision_found = true;
+ if let ExprKind::Path(ref precision_path) = field.expr.kind {
+ last_path_segment(precision_path).ident.name == sym::Implied
+ } else {
+ false
+ }
+ }
+ sym::width => {
+ width_found = true;
+ if let ExprKind::Path(ref width_qpath) = field.expr.kind {
+ last_path_segment(width_qpath).ident.name == sym::Implied
+ } else {
+ false
+ }
+ }
+ _ => true,
+ }
+ });
+ if precision_found && width_found;
+ then { true } else { false }
+ }
+ })
+ }
+
+ /// Returns true if the argument is formatted using `Display::fmt`.
+ pub fn is_display(&self) -> bool {
+ if_chain! {
+ if let ExprKind::Call(_, [_, format_field]) = self.arg.kind;
+ if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind;
+ if let [.., t, _] = path.segments;
+ if t.ident.name == sym::Display;
+ then { true } else { false }
+ }
+ }
}
/// Checks if a `let` statement is from a `for` loop desugaring.
/// Parses an expanded `panic!` invocation
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
if_chain! {
- if let ExprKind::Block(block, _) = expr.kind;
- if let Some(init) = block.expr;
- if let ExprKind::Call(_, [format_args]) = init.kind;
+ if let ExprKind::Call(_, [format_args]) = expr.kind;
let expn_data = expr.span.ctxt().outer_expn_data();
- if let ExprKind::AddrOf(_, _, format_args) = format_args.kind;
if let Some(format_args) = FormatArgsExpn::parse(format_args);
then {
Some(PanicExpn {
}
}
}
+
+/// A parsed `Vec` initialization expression
+#[derive(Clone, Copy)]
+pub enum VecInitKind {
+ /// `Vec::new()`
+ New,
+ /// `Vec::default()` or `Default::default()`
+ Default,
+ /// `Vec::with_capacity(123)`
+ WithLiteralCapacity(u64),
+ /// `Vec::with_capacity(slice.len())`
+ WithExprCapacity(HirId),
+}
+
+/// Checks if given expression is an initialization of `Vec` and returns its kind.
+pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
+ if let ExprKind::Call(func, args) = expr.kind {
+ match func.kind {
+ ExprKind::Path(QPath::TypeRelative(ty, name))
+ if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
+ {
+ if name.ident.name == sym::new {
+ return Some(VecInitKind::New);
+ } else if name.ident.name == symbol::kw::Default {
+ return Some(VecInitKind::Default);
+ } else if name.ident.name.as_str() == "with_capacity" {
+ let arg = args.get(0)?;
+ if_chain! {
+ if let ExprKind::Lit(lit) = &arg.kind;
+ if let LitKind::Int(num, _) = lit.node;
+ then {
+ return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?))
+ }
+ }
+ return Some(VecInitKind::WithExprCapacity(arg.hir_id));
+ }
+ },
+ ExprKind::Path(QPath::Resolved(_, path))
+ if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
+ {
+ return Some(VecInitKind::Default);
+ },
+ _ => (),
+ }
+ }
+ None
+}
#[allow(clippy::module_name_repetitions)]
pub mod ast_utils;
pub mod attrs;
-pub mod camel_case;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
pub mod ptr;
pub mod qualify_min_const_fn;
pub mod source;
+pub mod str_utils;
pub mod sugg;
pub mod ty;
pub mod usage;
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
use rustc_hir::{
- def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
- ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat,
- PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
+ def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
+ HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
+ Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+ UnOp,
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::exports::Export;
/// Returns `true` if this `span` was expanded by any macro.
#[must_use]
pub fn in_macro(span: Span) -> bool {
- if span.from_expansion() {
- !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
- } else {
- false
- }
+ span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
}
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
/// Checks if the top level expression can be moved into a closure as is.
/// Currently checks for:
/// * Break/Continue outside the given loop HIR ids.
-/// * Yield/Return statments.
+/// * Yield/Return statements.
/// * Inline assembly.
/// * Usages of a field of a local where the type of the local can be partially moved.
///
let mut capture_expr_ty = e;
for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
- if let [Adjustment {
- kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
- target,
- }, ref adjust @ ..] = *cx
+ if let [
+ Adjustment {
+ kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
+ target,
+ },
+ ref adjust @ ..,
+ ] = *cx
.typeck_results()
.adjustments()
.get(child_id)
for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
match node {
Node::Expr(
- e
- @
- Expr {
+ e @ Expr {
kind: ExprKind::Loop(..) | ExprKind::Closure(..),
..
},
}
let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
- value == v
- } else {
- false
+ return value == v;
}
+ false
}
/// Checks whether the given expression is a constant literal of the given value.
/// Returns the pre-expansion span if is this comes from an expansion of the
/// macro `name`.
-/// See also `is_direct_expn_of`.
+/// See also [`is_direct_expn_of`].
#[must_use]
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
loop {
/// Returns the pre-expansion span if the span directly comes from an expansion
/// of the macro `name`.
-/// The difference with `is_expn_of` is that in
-/// ```rust,ignore
+/// The difference with [`is_expn_of`] is that in
+/// ```rust
+/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
/// foo!(bar!(42));
/// ```
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
-/// `bar!` by
-/// `is_direct_expn_of`.
+/// from `bar!` by `is_direct_expn_of`.
#[must_use]
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
if span.from_expansion() {
}
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
- if_chain! {
- if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
- if let Res::SelfTy(..) = path.res;
- then {
- return true
+ if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
+ if let Res::SelfTy(..) = path.res {
+ return true;
}
}
false
did,
&[
&paths::BEGIN_PANIC,
- &paths::BEGIN_PANIC_FMT,
&paths::PANIC_ANY,
&paths::PANICKING_PANIC,
&paths::PANICKING_PANIC_FMT,
pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(
_,
- &[Expr {
- kind: ExprKind::Closure(_, _, body, _, _),
- ..
- }],
+ &[
+ Expr {
+ kind: ExprKind::Closure(_, _, body, _, _),
+ ..
+ },
+ ],
) = body.value.kind
{
if let ExprKind::Block(
}
pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
- if_chain! {
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
- if let Res::Def(_, def_id) = path.res;
- then {
- cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
- } else {
- false
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+ if let Res::Def(_, def_id) = path.res {
+ return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
}
}
+ false
}
-/// Checks whether item either has `test` attribute applied, or
-/// is a module with `test` in its name.
-pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
- if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) {
- if tcx.has_attr(def_id.to_def_id(), sym::test) {
- return true;
+struct VisitConstTestStruct<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ names: Vec<Symbol>,
+ found: bool,
+}
+impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
+ fn visit_item(&mut self, item: &Item<'_>) {
+ if let ItemKind::Const(ty, _body) = item.kind {
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+ // We could also check for the type name `test::TestDescAndFn`
+ // and the `#[rustc_test_marker]` attribute?
+ if let Res::Def(DefKind::Struct, _) = path.res {
+ let has_test_marker = self
+ .tcx
+ .hir()
+ .attrs(item.hir_id())
+ .iter()
+ .any(|a| a.has_name(sym::rustc_test_marker));
+ if has_test_marker && self.names.contains(&item.ident.name) {
+ self.found = true;
+ }
+ }
+ }
}
}
+ fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
+ fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
+ fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
+}
+
+/// Checks if the function containing the given `HirId` is a `#[test]` function
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+ let names: Vec<_> = tcx
+ .hir()
+ .parent_iter(id)
+ // Since you can nest functions we need to collect all until we leave
+ // function scope
+ .filter_map(|(_id, node)| {
+ if let Node::Item(item) = node {
+ if let ItemKind::Fn(_, _, _) = item.kind {
+ return Some(item.ident.name);
+ }
+ }
+ None
+ })
+ .collect();
+ let parent_mod = tcx.parent_module(id);
+ let mut vis = VisitConstTestStruct {
+ tcx,
+ names,
+ found: false,
+ };
+ tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
+ vis.found
+}
- matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
+/// Checks whether item either has `test` attribute applied, or
+/// is a module with `test` in its name.
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
+ is_in_test_function(tcx, item.hir_id())
+ || matches!(item.kind, ItemKind::Mod(..))
+ && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
}
macro_rules! op_utils {
#[cfg(feature = "metadata-collector-lint")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
-pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
/// Preferably use the diagnostic item `sym::Borrow` where possible
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
#[cfg(feature = "internal-lints")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"];
pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
--- /dev/null
+/// Dealing with sting indices can be hard, this struct ensures that both the
+/// character and byte index are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrIndex {
+ pub char_index: usize,
+ pub byte_index: usize,
+}
+
+impl StrIndex {
+ pub fn new(char_index: usize, byte_index: usize) -> Self {
+ Self { char_index, byte_index }
+ }
+}
+
+/// Returns the index of the character after the first camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+/// ```
+#[must_use]
+pub fn camel_case_until(s: &str) -> StrIndex {
+ let mut iter = s.char_indices().enumerate();
+ if let Some((_char_index, (_, first))) = iter.next() {
+ if !first.is_uppercase() {
+ return StrIndex::new(0, 0);
+ }
+ } else {
+ return StrIndex::new(0, 0);
+ }
+ let mut up = true;
+ let mut last_index = StrIndex::new(0, 0);
+ for (char_index, (byte_index, c)) in iter {
+ if up {
+ if c.is_lowercase() {
+ up = false;
+ } else {
+ return last_index;
+ }
+ } else if c.is_uppercase() {
+ up = true;
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else if !c.is_lowercase() {
+ return StrIndex::new(char_index, byte_index);
+ }
+ }
+
+ if up {
+ last_index
+ } else {
+ StrIndex::new(s.chars().count(), s.len())
+ }
+}
+
+/// Returns index of the last camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
+/// ```
+#[must_use]
+pub fn camel_case_start(s: &str) -> StrIndex {
+ let char_count = s.chars().count();
+ let range = 0..char_count;
+ let mut iter = range.rev().zip(s.char_indices().rev());
+ if let Some((char_index, (_, first))) = iter.next() {
+ if !first.is_lowercase() {
+ return StrIndex::new(char_index, s.len());
+ }
+ } else {
+ return StrIndex::new(char_count, s.len());
+ }
+ let mut down = true;
+ let mut last_index = StrIndex::new(char_count, s.len());
+ for (char_index, (byte_index, c)) in iter {
+ if down {
+ if c.is_uppercase() {
+ down = false;
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else if !c.is_lowercase() {
+ return last_index;
+ }
+ } else if c.is_lowercase() {
+ down = true;
+ } else if c.is_uppercase() {
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else {
+ return last_index;
+ }
+ }
+ last_index
+}
+
+/// Dealing with sting comparison can be complicated, this struct ensures that both the
+/// character and byte count are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrCount {
+ pub char_count: usize,
+ pub byte_count: usize,
+}
+
+impl StrCount {
+ pub fn new(char_count: usize, byte_count: usize) -> Self {
+ Self { char_count, byte_count }
+ }
+}
+
+/// Returns the number of chars that match from the start
+///
+/// ```
+/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
+/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
+/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
+/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
+ // (char_index, char1)
+ let char_count = str1.chars().count();
+ let iter1 = (0..=char_count).zip(str1.chars());
+ // (byte_index, char2)
+ let iter2 = str2.char_indices();
+
+ iter1
+ .zip(iter2)
+ .take_while(|((_, c1), (_, c2))| c1 == c2)
+ .last()
+ .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
+ StrCount::new(char_index + 1, byte_index + character.len_utf8())
+ })
+}
+
+/// Returns the number of chars and bytes that match from the end
+///
+/// ```
+/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
+/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
+/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
+/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
+ let char_count = str1.chars().count();
+ if char_count == 0 {
+ return StrCount::default();
+ }
+
+ // (char_index, char1)
+ let iter1 = (0..char_count).rev().zip(str1.chars().rev());
+ // (byte_index, char2)
+ let byte_count = str2.len();
+ let iter2 = str2.char_indices().rev();
+
+ iter1
+ .zip(iter2)
+ .take_while(|((_, c1), (_, c2))| c1 == c2)
+ .last()
+ .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
+ StrCount::new(char_count - char_index, byte_count - byte_index)
+ })
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn camel_case_start_full() {
+ assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
+ }
+
+ #[test]
+ fn camel_case_start_partial() {
+ assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
+ assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
+ }
+
+ #[test]
+ fn camel_case_start_not() {
+ assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
+ assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
+ assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
+ assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
+ }
+
+ #[test]
+ fn camel_case_start_caps() {
+ assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+ }
+
+ #[test]
+ fn camel_case_until_full() {
+ assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+ assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
+ }
+
+ #[test]
+ fn camel_case_until_not() {
+ assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
+ }
+
+ #[test]
+ fn camel_case_until_partial() {
+ assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
+ assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
+ assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+ }
+
+ #[test]
+ fn until_caps() {
+ assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+ }
+}
use std::fmt::Display;
use std::ops::{Add, Neg, Not, Sub};
-/// A helper type to build suggestion correctly handling parenthesis.
+/// A helper type to build suggestion correctly handling parentheses.
#[derive(Clone, PartialEq)]
pub enum Sugg<'a> {
- /// An expression that never needs parenthesis such as `1337` or `[0; 42]`.
+ /// An expression that never needs parentheses such as `1337` or `[0; 42]`.
NonParen(Cow<'a, str>),
/// An expression that does not fit in other variants.
MaybeParen(Cow<'a, str>),
}
}
- /// Adds parenthesis to any expression that might need them. Suitable to the
+ /// Adds parentheses to any expression that might need them. Suitable to the
/// `self` argument of a method call
/// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
pub fn maybe_par(self) -> Self {
_ => a == b,
}
}
+
+/// Checks if a given type looks safe to be uninitialized.
+pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
+ ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
+ ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
+ _ => false,
+ }
+}
- [Edition 2018 tests](#edition-2018-tests)
- [Testing manually](#testing-manually)
- [Lint declaration](#lint-declaration)
+ - [Lint registration](#lint-registration)
- [Lint passes](#lint-passes)
- [Emitting a lint](#emitting-a-lint)
- [Adding the lint logic](#adding-the-lint-logic)
lint you can run `cargo dev new_lint --name=foo_functions --pass=early
--category=pedantic` (category will default to nursery if not provided). This
command will create two files: `tests/ui/foo_functions.rs` and
-`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
-register the new lint. For cargo lints, two project hierarchies (fail/pass) will
-be created by default under `tests/ui-cargo`.
+`clippy_lints/src/foo_functions.rs`, as well as
+[registering the lint](#lint-registration). For cargo lints, two project
+hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
Next, we'll open up these files and add our lint!
impl EarlyLintPass for FooFunctions {}
```
-Normally after declaring the lint, we have to run `cargo dev update_lints`,
-which updates some files, so Clippy knows about the new lint. Since we used
-`cargo dev new_lint ...` to generate the lint declaration, this was done
-automatically. While `update_lints` automates most of the things, it doesn't
-automate everything. We will have to register our lint pass manually in the
-`register_plugins` function in `clippy_lints/src/lib.rs`:
+[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
+[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+
+## Lint registration
+
+When using `cargo dev new_lint`, the lint is automatically registered and
+nothing more has to be done.
+
+When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
+pass may have to be registered manually in the `register_plugins` function in
+`clippy_lints/src/lib.rs`:
```rust
-store.register_early_pass(|| box foo_functions::FooFunctions);
+store.register_early_pass(|| Box::new(foo_functions::FooFunctions));
```
As one may expect, there is a corresponding `register_late_pass` method
available as well. Without a call to one of `register_early_pass` or
`register_late_pass`, the lint pass in question will not be run.
-One reason that `cargo dev` does not automate this step is that multiple lints
-can use the same lint pass, so registering the lint pass may already be done
-when adding a new lint. Another reason that this step is not automated is that
-the order that the passes are registered determines the order the passes
-actually run, which in turn affects the order that any emitted lints are output
-in.
-
-[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
-[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
-[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+One reason that `cargo dev update_lints` does not automate this step is that
+multiple lints can use the same lint pass, so registering the lint pass may
+already be done when adding a new lint. Another reason that this step is not
+automated is that the order that the passes are registered determines the order
+the passes actually run, which in turn affects the order that any emitted lints
+are output in.
## Lint passes
/// <The configuration field doc comment>
(configuration_ident: Type = DefaultValue),
```
- The doc comment will be automatically added to the lint documentation.
+ The doc comment is automatically added to the documentation of the listed lints. The default
+ value will be formatted using the `Debug` implementation of the type.
2. Adding the configuration value to the lint impl struct:
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
# (experimental) Setup Clippy to work with IntelliJ-Rust
cargo dev setup intellij
```
+More about intellij command usage and reasons [here](../CONTRIBUTING.md#intellij-rust)
## lintcheck
`cargo lintcheck` will build and run clippy on a fixed set of crates and generate a log of the results.
[toolchain]
-channel = "nightly-2021-10-07"
+channel = "nightly-2021-11-04"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
}
fn default_config() -> compiletest::Config {
- let mut config = compiletest::Config::default();
+ let mut config = compiletest::Config {
+ edition: Some("2021".into()),
+ ..compiletest::Config::default()
+ };
if let Ok(filters) = env::var("TESTNAME") {
config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
compiletest::run_tests(cfg);
}
+fn run_ui_test(cfg: &mut compiletest::Config) {
+ cfg.mode = TestMode::Ui;
+ cfg.src_base = Path::new("tests").join("ui_test");
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
+ let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default);
+ let len = rustcflags.len();
+ rustcflags.push_str(" --test");
+ compiletest::run_tests(cfg);
+ if let Some(ref mut flags) = &mut cfg.target_rustcflags {
+ flags.truncate(len);
+ }
+}
+
fn run_internal_tests(cfg: &mut compiletest::Config) {
// only run internal tests with the internal-tests feature
if !RUN_INTERNAL_TESTS {
prepare_env();
let mut config = default_config();
run_ui(&mut config);
+ run_ui_test(&mut config);
run_ui_toml(&mut config);
run_ui_cargo(&mut config);
run_internal_tests(&mut config);
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]
+#![feature(path_file_prefix)]
+use std::cmp::Ordering;
+use std::ffi::OsStr;
use std::fs::{self, DirEntry};
use std::path::Path;
}
}
-/*
-Test for missing files.
-
-Since rs files are alphabetically before stderr/stdout, we can sort by the full name
-and iter in that order. If we've seen the file stem for the first time and it's not
-a rust file, it means the rust file has to be missing.
-*/
+// Test for missing files.
fn explore_directory(dir: &Path) -> Vec<String> {
let mut missing_files: Vec<String> = Vec::new();
let mut current_file = String::new();
let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
- files.sort_by_key(std::fs::DirEntry::path);
+ files.sort_by(|x, y| {
+ match x.path().file_prefix().cmp(&y.path().file_prefix()) {
+ Ordering::Equal => (),
+ ord => return ord,
+ }
+ // Sort rs files before the others if they share the same prefix. So when we see
+ // the file prefix for the first time and it's not a rust file, it means the rust
+ // file has to be missing.
+ match (
+ x.path().extension().and_then(OsStr::to_str),
+ y.path().extension().and_then(OsStr::to_str),
+ ) {
+ (Some("rs"), _) => Ordering::Less,
+ (_, Some("rs")) => Ordering::Greater,
+ _ => Ordering::Equal,
+ }
+ });
for entry in &files {
let path = entry.path();
if path.is_dir() {
missing_files.extend(explore_directory(&path));
} else {
- let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
+ let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
if let Some(ext) = path.extension() {
match ext.to_str().unwrap() {
- "rs" => current_file = file_stem.clone(),
+ "rs" => current_file = file_prefix.clone(),
"stderr" | "stdout" => {
- if file_stem != current_file {
+ if file_prefix != current_file {
missing_files.push(path.to_str().unwrap().to_string());
}
},
Symbol::intern("foo") == rustc_span::sym::clippy;
Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower;
Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper;
- Ident::invalid().name == rustc_span::sym::clippy;
- rustc_span::sym::clippy == Ident::invalid().name;
+ Ident::empty().name == rustc_span::sym::clippy;
+ rustc_span::sym::clippy == Ident::empty().name;
}
Symbol::intern("foo").as_str() == "clippy";
Symbol::intern("foo").to_string() == "self";
Symbol::intern("foo").to_ident_string() != "Self";
- &*Ident::invalid().as_str() == "clippy";
- "clippy" == Ident::invalid().to_string();
+ &*Ident::empty().as_str() == "clippy";
+ "clippy" == Ident::empty().to_string();
}
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:14:5
|
-LL | &*Ident::invalid().as_str() == "clippy";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::invalid().name == rustc_span::sym::clippy`
+LL | &*Ident::empty().as_str() == "clippy";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:15:5
|
-LL | "clippy" == Ident::invalid().to_string();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::invalid().name`
+LL | "clippy" == Ident::empty().to_string();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
error: aborting due to 5 previous errors
-// edition:2018
-
#![warn(clippy::too_many_lines)]
// This function should be considered one line.
error: this function has too many lines (2/1)
- --> $DIR/test.rs:20:1
+ --> $DIR/test.rs:18:1
|
LL | / fn too_many_lines() {
LL | | println!("This is bad.");
= note: `-D clippy::too-many-lines` implied by `-D warnings`
error: this function has too many lines (4/1)
- --> $DIR/test.rs:26:1
+ --> $DIR/test.rs:24:1
|
LL | / async fn async_too_many_lines() {
LL | | println!("This is bad.");
| |_^
error: this function has too many lines (4/1)
- --> $DIR/test.rs:32:1
+ --> $DIR/test.rs:30:1
|
LL | / fn closure_too_many_lines() {
LL | | let _ = {
| |_^
error: this function has too many lines (2/1)
- --> $DIR/test.rs:54:1
+ --> $DIR/test.rs:52:1
|
LL | / fn comment_before_code() {
LL | | let _ = "test";
"std::time::Instant",
"std::io::Read",
"std::primitive::usize",
- "bool"
+ "bool",
+ # can give path and reason with an inline table
+ { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+ # can use an inline table but omit reason
+ { path = "std::net::TcpListener" },
]
static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut());
+fn ip(_: std::net::Ipv4Addr) {}
+
+fn listener(_: std::net::TcpListener) {}
+
#[allow(clippy::diverging_sub_expression)]
fn main() {
let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
LL | struct GenArg<const U: usize>([u8; U]);
| ^^^^^
+error: `std::net::Ipv4Addr` is not allowed according to config
+ --> $DIR/conf_disallowed_type.rs:28:10
+ |
+LL | fn ip(_: std::net::Ipv4Addr) {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: no IPv4 allowed (from clippy.toml)
+
+error: `std::net::TcpListener` is not allowed according to config
+ --> $DIR/conf_disallowed_type.rs:30:16
+ |
+LL | fn listener(_: std::net::TcpListener) {}
+ | ^^^^^^^^^^^^^^^^^^^^^
+
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:30:48
+ --> $DIR/conf_disallowed_type.rs:34:48
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:30:12
+ --> $DIR/conf_disallowed_type.rs:34:12
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:31:13
+ --> $DIR/conf_disallowed_type.rs:35:13
|
LL | let _ = Sneaky::now();
| ^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:32:13
+ --> $DIR/conf_disallowed_type.rs:36:13
|
LL | let _ = foo::atomic::AtomicU32::new(0);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:33:17
+ --> $DIR/conf_disallowed_type.rs:37:17
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:33:48
+ --> $DIR/conf_disallowed_type.rs:37:48
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `syn::TypePath` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:34:43
+ --> $DIR/conf_disallowed_type.rs:38:43
|
LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
| ^^^^^^^^^^^^^
error: `syn::Ident` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:35:13
+ --> $DIR/conf_disallowed_type.rs:39:13
|
LL | let _ = syn::Ident::new("", todo!());
| ^^^^^^^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:37:12
+ --> $DIR/conf_disallowed_type.rs:41:12
|
LL | let _: usize = 64_usize;
| ^^^^^
-error: aborting due to 19 previous errors
+error: aborting due to 21 previous errors
+//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
#![allow(non_fmt_panics)]
macro_rules! assert_const {
debug_assert!($len < 0);
};
}
-
fn main() {
assert!(true);
assert!(false);
assert!(false, "false message");
let msg = "panic message";
- assert!(false, msg.to_uppercase());
+ assert!(false, "{}", msg.to_uppercase());
const B: bool = true;
assert!(B);
= help: remove it
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `assert!(false, "false message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:14:5
|
LL | assert!(false, "false message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: use `panic!("false message")` or `unreachable!("false message")`
- = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `assert!(false, msg.to_uppercase())` should probably be replaced
- --> $DIR/assertions_on_constants.rs:17:5
- |
-LL | assert!(false, msg.to_uppercase());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
+ = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(true)` will be optimized out by the compiler
= help: use `panic!()` or `unreachable!()`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `assert!(false, "C message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:24:5
|
LL | assert!(C, "C message");
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: use `panic!("C message")` or `unreachable!("C message")`
+ = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `debug_assert!(true)` will be optimized out by the compiler
= help: remove it
= note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
// run-rustfix
-// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
// run-rustfix
-// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:40:9
+ --> $DIR/async_yields_async.rs:39:9
|
LL | let _h = async {
| ____________________-
|
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:45:9
+ --> $DIR/async_yields_async.rs:44:9
|
LL | let _i = async {
| ____________________-
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:51:9
+ --> $DIR/async_yields_async.rs:50:9
|
LL | let _j = async || {
| _______________________-
|
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:56:9
+ --> $DIR/async_yields_async.rs:55:9
|
LL | let _k = async || {
| _______________________-
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:58:23
+ --> $DIR/async_yields_async.rs:57:23
|
LL | let _l = async || CustomFutureType;
| ^^^^^^^^^^^^^^^^
| help: consider awaiting this value: `CustomFutureType.await`
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:64:9
+ --> $DIR/async_yields_async.rs:63:9
|
LL | let _m = async || {
| _______________________-
let x = 22;
};
}
+
+#[macro_export]
+macro_rules! mut_mut {
+ () => {
+ let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
+ };
+}
-// edition:2018
#![warn(clippy::await_holding_lock)]
use std::sync::Mutex;
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:7:9
+ --> $DIR/await_holding_lock.rs:6:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:7:5
+ --> $DIR/await_holding_lock.rs:6:5
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:28:9
+ --> $DIR/await_holding_lock.rs:27:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:28:5
+ --> $DIR/await_holding_lock.rs:27:5
|
LL | / let guard = x.lock().unwrap();
LL | |
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:41:13
+ --> $DIR/await_holding_lock.rs:40:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:41:9
+ --> $DIR/await_holding_lock.rs:40:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
| |_____^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:53:13
+ --> $DIR/await_holding_lock.rs:52:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:53:9
+ --> $DIR/await_holding_lock.rs:52:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
-// edition:2018
#![warn(clippy::await_holding_refcell_ref)]
use std::cell::RefCell;
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:7:9
+ --> $DIR/await_holding_refcell_ref.rs:6:9
|
LL | let b = x.borrow();
| ^
|
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:7:5
+ --> $DIR/await_holding_refcell_ref.rs:6:5
|
LL | / let b = x.borrow();
LL | | baz().await
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:12:9
+ --> $DIR/await_holding_refcell_ref.rs:11:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:12:5
+ --> $DIR/await_holding_refcell_ref.rs:11:5
|
LL | / let b = x.borrow_mut();
LL | | baz().await
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:33:9
+ --> $DIR/await_holding_refcell_ref.rs:32:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:33:5
+ --> $DIR/await_holding_refcell_ref.rs:32:5
|
LL | / let b = x.borrow_mut();
LL | |
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:45:9
+ --> $DIR/await_holding_refcell_ref.rs:44:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:45:5
+ --> $DIR/await_holding_refcell_ref.rs:44:5
|
LL | / let b = x.borrow_mut();
LL | |
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:60:13
+ --> $DIR/await_holding_refcell_ref.rs:59:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:60:9
+ --> $DIR/await_holding_refcell_ref.rs:59:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await
| |_____^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:72:13
+ --> $DIR/await_holding_refcell_ref.rs:71:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:72:9
+ --> $DIR/await_holding_refcell_ref.rs:71:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await
(1i64).checked_rem_euclid(-1i64).unwrap() as u64;
(1i64).checked_rem_euclid(-1i64).unwrap() as u128;
(1isize).checked_rem_euclid(-1isize).unwrap() as usize;
+
+ // no lint for `cast_possible_truncation`
+ // with `signum` method call (see issue #5395)
+ let x: i64 = 5;
+ let _ = x.signum() as i32;
+
+ let s = x.signum();
+ let _ = s as i32;
+
+ // Test for signed min
+ (-99999999999i64).min(1) as i8; // should be linted because signed
+
+ // Test for various operations that remove enough bits for the result to fit
+ (999999u64 & 1) as u8;
+ (999999u64 % 15) as u8;
+ (999999u64 / 0x1_0000_0000_0000) as u16;
+ ({ 999999u64 >> 56 }) as u8;
+ ({
+ let x = 999999u64;
+ x.min(1)
+ }) as u8;
+ 999999u64.clamp(0, 255) as u8;
+ 999999u64.clamp(0, 256) as u8; // should still be linted
}
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
-error: aborting due to 22 previous errors
+error: casting `i64` to `i8` may truncate the value
+ --> $DIR/cast.rs:105:5
+ |
+LL | (-99999999999i64).min(1) as i8; // should be linted because signed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `u64` to `u8` may truncate the value
+ --> $DIR/cast.rs:117:5
+ |
+LL | 999999u64.clamp(0, 256) as u8; // should still be linted
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
// run-rustfix
#![feature(stmt_expr_attributes)]
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
// This doesn't get linted, see known problems
// run-rustfix
#![feature(stmt_expr_attributes)]
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
// This doesn't get linted, see known problems
--- /dev/null
+fn zero() {
+ unsafe { 0 };
+}
// in type inference.
#![feature(trivial_bounds)]
#![allow(unused)]
-
trait A {}
impl A for i32 {}
fn unsized_local()
where
- for<'a> Dst<A + 'a>: Sized,
+ for<'a> Dst<dyn A + 'a>: Sized,
{
- let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+ let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
}
fn return_str() -> str
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:25:17
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:20:10
|
-LL | for<'a> Dst<A + 'a>: Sized,
- | ^^^^^^ help: use `dyn`: `dyn A + 'a`
+LL | str: Sized;
+ | ^^^^^
|
- = note: `-D bare-trait-objects` implied by `-D warnings`
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: `-D trivial-bounds` implied by `-D warnings`
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:27:16
+error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:24:30
|
-LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
- | ^ help: use `dyn`: `dyn A`
+LL | for<'a> Dst<dyn A + 'a>: Sized,
+ | ^^^^^
+
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:31:10
|
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL | str: Sized,
+ | ^^^^^
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:27:57
+error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:38:13
|
-LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
- | ^ help: use `dyn`: `dyn A`
+LL | String: ::std::ops::Neg<Output = String>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:45:10
|
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL | i32: Iterator,
+ | ^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
-// edition:2018
-
// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
pub async fn bar<'a, T: 'a>(_: T) {}
// originally from glacier fixed/77919.rs
// encountered errors resolving bounds after type-checking
-
trait TypeVal<T> {
const VAL: T;
}
error[E0412]: cannot find type `PhantomData` in this scope
- --> $DIR/ice-6252.rs:9:9
+ --> $DIR/ice-6252.rs:8:9
|
LL | _n: PhantomData,
| ^^^^^^^^^^^ not found in this scope
|
-help: consider importing this struct
+help: consider importing one of these items
+ |
+LL | use core::marker::PhantomData;
+ |
+LL | use serde::__private::PhantomData;
|
LL | use std::marker::PhantomData;
|
error[E0412]: cannot find type `VAL` in this scope
- --> $DIR/ice-6252.rs:11:63
+ --> $DIR/ice-6252.rs:10:63
|
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| - ^^^ not found in this scope
| help: you might be missing a type parameter: `, VAL`
error[E0046]: not all trait items implemented, missing: `VAL`
- --> $DIR/ice-6252.rs:11:1
+ --> $DIR/ice-6252.rs:10:1
|
LL | const VAL: T;
| ------------- `VAL` from trait
-// edition:2018
#![allow(clippy::never_loop)]
async fn f() {
--- /dev/null
+#![warn(clippy::undocumented_unsafe_blocks)]
+#![allow(clippy::no_effect)]
+
+#[path = "auxiliary/ice-7868-aux.rs"]
+mod zero;
+
+fn main() {}
--- /dev/null
+error: unsafe block missing a safety comment
+ --> $DIR/auxiliary/ice-7868-aux.rs:2:5
+ |
+LL | unsafe { 0 };
+ | ^^^^^^^^^^^^
+ |
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe { 0 };
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+enum Tila {
+ TyöAlkoi,
+ TyöKeskeytyi,
+ TyöValmis,
+}
+
+fn main() {}
--- /dev/null
+error: all variants have the same prefix: `Työ`
+ --> $DIR/ice-7869.rs:1:1
+ |
+LL | / enum Tila {
+LL | | TyöAlkoi,
+LL | | TyöKeskeytyi,
+LL | | TyöValmis,
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+ = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: aborting due to previous error
+
-// edition:2018
-
use serde::Deserialize;
/// Tests that we do not lint for unused underscores in a `MacroAttribute`
-// compile-flags: --edition=2018
#![feature(custom_inner_attributes)]
#![rustfmt::skip]
#![warn(clippy::debug_assert_with_mut_call)]
#![allow(clippy::redundant_closure_call)]
+
struct S;
impl S {
-#[warn(clippy::unstable_as_slice)]
-#[warn(clippy::unstable_as_mut_slice)]
-#[warn(clippy::misaligned_transmute)]
-#[warn(clippy::unused_collect)]
-#[warn(clippy::invalid_ref)]
-#[warn(clippy::into_iter_on_array)]
-#[warn(clippy::unused_label)]
-#[warn(clippy::regex_macro)]
-#[warn(clippy::drop_bounds)]
-#[warn(clippy::temporary_cstring_as_ptr)]
-#[warn(clippy::panic_params)]
-#[warn(clippy::unknown_clippy_lints)]
-#[warn(clippy::find_map)]
-#[warn(clippy::filter_map)]
-#[warn(clippy::pub_enum_variant_names)]
-#[warn(clippy::wrong_pub_self_convention)]
-#[warn(clippy::invalid_atomic_ordering)]
+#![warn(clippy::should_assert_eq)]
+#![warn(clippy::extend_from_slice)]
+#![warn(clippy::range_step_by_zero)]
+#![warn(clippy::unstable_as_slice)]
+#![warn(clippy::unstable_as_mut_slice)]
+#![warn(clippy::misaligned_transmute)]
+#![warn(clippy::assign_ops)]
+#![warn(clippy::if_let_redundant_pattern_matching)]
+#![warn(clippy::unsafe_vector_initialization)]
+#![warn(clippy::unused_collect)]
+#![warn(clippy::replace_consts)]
+#![warn(clippy::regex_macro)]
+#![warn(clippy::find_map)]
+#![warn(clippy::filter_map)]
+#![warn(clippy::pub_enum_variant_names)]
+#![warn(clippy::wrong_pub_self_convention)]
fn main() {}
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
- --> $DIR/deprecated.rs:1:8
+error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
+ --> $DIR/deprecated.rs:1:9
|
-LL | #[warn(clippy::unstable_as_slice)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::should_assert_eq)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
- --> $DIR/deprecated.rs:2:8
+error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
+ --> $DIR/deprecated.rs:2:9
|
-LL | #[warn(clippy::unstable_as_mut_slice)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::extend_from_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
- --> $DIR/deprecated.rs:3:8
+error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
+ --> $DIR/deprecated.rs:3:9
|
-LL | #[warn(clippy::misaligned_transmute)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::range_step_by_zero)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
- --> $DIR/deprecated.rs:4:8
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+ --> $DIR/deprecated.rs:4:9
|
-LL | #[warn(clippy::unused_collect)]
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/deprecated.rs:5:8
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+ --> $DIR/deprecated.rs:5:9
|
-LL | #[warn(clippy::invalid_ref)]
- | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::unstable_as_mut_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/deprecated.rs:6:8
+error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+ --> $DIR/deprecated.rs:6:9
|
-LL | #[warn(clippy::into_iter_on_array)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+LL | #![warn(clippy::misaligned_transmute)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/deprecated.rs:7:8
+error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
+ --> $DIR/deprecated.rs:7:9
|
-LL | #[warn(clippy::unused_label)]
- | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::assign_ops)]
+ | ^^^^^^^^^^^^^^^^^^
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
- --> $DIR/deprecated.rs:8:8
+error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
+ --> $DIR/deprecated.rs:8:9
|
-LL | #[warn(clippy::regex_macro)]
- | ^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/deprecated.rs:9:8
+error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
+ --> $DIR/deprecated.rs:9:9
|
-LL | #[warn(clippy::drop_bounds)]
- | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::unsafe_vector_initialization)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/deprecated.rs:10:8
+error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
+ --> $DIR/deprecated.rs:10:9
|
-LL | #[warn(clippy::temporary_cstring_as_ptr)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+LL | #![warn(clippy::unused_collect)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/deprecated.rs:11:8
+error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
+ --> $DIR/deprecated.rs:11:9
|
-LL | #[warn(clippy::panic_params)]
- | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::replace_consts)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/deprecated.rs:12:8
+error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
+ --> $DIR/deprecated.rs:12:9
|
-LL | #[warn(clippy::unknown_clippy_lints)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+LL | #![warn(clippy::regex_macro)]
+ | ^^^^^^^^^^^^^^^^^^^
error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
- --> $DIR/deprecated.rs:13:8
+ --> $DIR/deprecated.rs:13:9
|
-LL | #[warn(clippy::find_map)]
- | ^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::find_map)]
+ | ^^^^^^^^^^^^^^^^
error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
- --> $DIR/deprecated.rs:14:8
+ --> $DIR/deprecated.rs:14:9
|
-LL | #[warn(clippy::filter_map)]
- | ^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::filter_map)]
+ | ^^^^^^^^^^^^^^^^^^
error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
- --> $DIR/deprecated.rs:15:8
+ --> $DIR/deprecated.rs:15:9
|
-LL | #[warn(clippy::pub_enum_variant_names)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::pub_enum_variant_names)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
- --> $DIR/deprecated.rs:16:8
- |
-LL | #[warn(clippy::wrong_pub_self_convention)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/deprecated.rs:17:8
+ --> $DIR/deprecated.rs:16:9
|
-LL | #[warn(clippy::invalid_atomic_ordering)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+LL | #![warn(clippy::wrong_pub_self_convention)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
#![warn(clippy::diverging_sub_expression)]
#![allow(clippy::match_same_arms, clippy::logic_bug)]
-
#[allow(clippy::empty_loop)]
fn diverge() -> ! {
loop {}
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:20:10
+ --> $DIR/diverging_sub_expression.rs:19:10
|
LL | b || diverge();
| ^^^^^^^^^
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:21:10
+ --> $DIR/diverging_sub_expression.rs:20:10
|
LL | b || A.foo();
| ^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:30:26
+ --> $DIR/diverging_sub_expression.rs:29:26
|
LL | 6 => true || return,
| ^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:31:26
+ --> $DIR/diverging_sub_expression.rs:30:26
|
LL | 7 => true || continue,
| ^^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:34:26
+ --> $DIR/diverging_sub_expression.rs:33:26
|
LL | 3 => true || diverge(),
| ^^^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:39:26
+ --> $DIR/diverging_sub_expression.rs:36:30
+ |
+LL | _ => true || panic!("boo"),
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+ --> $DIR/diverging_sub_expression.rs:38:26
|
LL | _ => true || break,
| ^^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
--- /dev/null
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
+/// which should be reported only once despite being __doubly bad__.
+/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though.
+/// Import an item from `::awesome::global::blob::` (Intended postfix)
+/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~`NotInCodeBlock`~.
+/// `be_sure_we_got_to_the_end_of_it`
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// `be_sure_we_got_to_the_end_of_it`
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_allowed() {
+}
+
+/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [`inline_link2`].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// `be_sure_we_got_to_the_end_of_it`
+fn main() {
+ foo_bar();
+ multiline_codeblock();
+ test_emphasis();
+ test_units();
+}
+
+/// ## `CamelCaseThing`
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # `CamelCaseThing`
+///
+/// Not a title #897 `CamelCaseThing`
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: `PackedNode`
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: PackedNode
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// `be_sure_we_got_to_the_end_of_it`
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+/// let s = "localhost:10000".to_string();
+/// println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over `mycrate::Collection`'s values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ arr: [T; N.checked_next_power_of_two().unwrap()],
+ n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ fn new() -> Self {
+ Self {
+ arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+ n: 0,
+ }
+ }
+}
--- /dev/null
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
+/// which should be reported only once despite being __doubly bad__.
+/// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+/// Import an item from ::awesome::global::blob:: (Intended postfix)
+/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~NotInCodeBlock~.
+/// be_sure_we_got_to_the_end_of_it
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// be_sure_we_got_to_the_end_of_it
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// be_sure_we_got_to_the_end_of_it
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// be_sure_we_got_to_the_end_of_it
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// be_sure_we_got_to_the_end_of_it
+fn test_allowed() {
+}
+
+/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [inline_link2].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// be_sure_we_got_to_the_end_of_it
+fn main() {
+ foo_bar();
+ multiline_codeblock();
+ test_emphasis();
+ test_units();
+}
+
+/// ## CamelCaseThing
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # CamelCaseThing
+///
+/// Not a title #897 CamelCaseThing
+/// be_sure_we_got_to_the_end_of_it
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// be_sure_we_got_to_the_end_of_it
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// be_sure_we_got_to_the_end_of_it
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: `PackedNode`
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: PackedNode
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// be_sure_we_got_to_the_end_of_it
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+/// let s = "localhost:10000".to_string();
+/// println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over mycrate::Collection's values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ arr: [T; N.checked_next_power_of_two().unwrap()],
+ n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ fn new() -> Self {
+ Self {
+ arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+ n: 0,
+ }
+ }
+}
--- /dev/null
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:9:9
+ |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+ | ^^^^^^^ help: try: ``foo_bar``
+ |
+ = note: `-D clippy::doc-markdown` implied by `-D warnings`
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:9:51
+ |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+ | ^^^^^^^^ help: try: ``foo::bar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:10:83
+ |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
+ | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:12:13
+ |
+LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+ | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:12:36
+ |
+LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:13:25
+ |
+LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:14:31
+ |
+LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+ | ^^^^^ help: try: ``::Cat``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:15:22
+ |
+LL | /// That's not code ~NotInCodeBlock~.
+ | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:16:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:30:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:37:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:51:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:74:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:78:22
+ |
+LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:81:21
+ |
+LL | /// It can also be [inline_link2].
+ | ^^^^^^^^^^^^ help: try: ``inline_link2``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:91:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:99:8
+ |
+LL | /// ## CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:102:7
+ |
+LL | /// # CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:104:22
+ |
+LL | /// Not a title #897 CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:105:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:112:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:125:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:136:43
+ |
+LL | /** E.g., serialization of an empty list: FooBar
+ | ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:141:5
+ |
+LL | And BarQuz too.
+ | ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:142:1
+ |
+LL | be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:147:43
+ |
+LL | /** E.g., serialization of an empty list: FooBar
+ | ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:152:5
+ |
+LL | And BarQuz too.
+ | ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:153:1
+ |
+LL | be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:164:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:183:22
+ |
+LL | /// An iterator over mycrate::Collection's values.
+ | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
+
+error: aborting due to 30 previous errors
+
+++ /dev/null
-//! This file tests for the `DOC_MARKDOWN` lint.
-
-#![allow(dead_code, incomplete_features)]
-#![warn(clippy::doc_markdown)]
-#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
-#![rustfmt::skip]
-
-/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
-/// which should be reported only once despite being __doubly bad__.
-/// Here be ::a::global:path.
-/// That's not code ~NotInCodeBlock~.
-/// be_sure_we_got_to_the_end_of_it
-fn foo_bar() {
-}
-
-/// That one tests multiline ticks.
-/// ```rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ```
-///
-/// ~~~rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ~~~
-/// be_sure_we_got_to_the_end_of_it
-fn multiline_codeblock() {
-}
-
-/// This _is a test for
-/// multiline
-/// emphasis_.
-/// be_sure_we_got_to_the_end_of_it
-fn test_emphasis() {
-}
-
-/// This tests units. See also #835.
-/// kiB MiB GiB TiB PiB EiB
-/// kib Mib Gib Tib Pib Eib
-/// kB MB GB TB PB EB
-/// kb Mb Gb Tb Pb Eb
-/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
-/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
-/// 32kB 32MB 32GB 32TB 32PB 32EB
-/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
-/// NaN
-/// be_sure_we_got_to_the_end_of_it
-fn test_units() {
-}
-
-/// This tests allowed identifiers.
-/// KiB MiB GiB TiB PiB EiB
-/// DirectX
-/// ECMAScript
-/// GPLv2 GPLv3
-/// GitHub GitLab
-/// IPv4 IPv6
-/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
-/// NaN NaNs
-/// OAuth GraphQL
-/// OCaml
-/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
-/// WebGL
-/// TensorFlow
-/// TrueType
-/// iOS macOS FreeBSD
-/// TeX LaTeX BibTeX BibLaTeX
-/// MinGW
-/// CamelCase (see also #2395)
-/// be_sure_we_got_to_the_end_of_it
-fn test_allowed() {
-}
-
-/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
-/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [inline_link2].
-///
-/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
-/// [inline_link]: https://foobar
-/// [inline_link2]: https://foobar
-/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
-/// `multiline_ticks` functions.
-///
-/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
-/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
-/// be_sure_we_got_to_the_end_of_it
-fn main() {
- foo_bar();
- multiline_codeblock();
- test_emphasis();
- test_units();
-}
-
-/// ## CamelCaseThing
-/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
-///
-/// # CamelCaseThing
-///
-/// Not a title #897 CamelCaseThing
-/// be_sure_we_got_to_the_end_of_it
-fn issue897() {
-}
-
-/// I am confused by brackets? (`x_y`)
-/// I am confused by brackets? (foo `x_y`)
-/// I am confused by brackets? (`x_y` foo)
-/// be_sure_we_got_to_the_end_of_it
-fn issue900() {
-}
-
-/// Diesel queries also have a similar problem to [Iterator][iterator], where
-/// /// More talking
-/// returning them from a function requires exposing the implementation of that
-/// function. The [`helper_types`][helper_types] module exists to help with this,
-/// but you might want to hide the return type or have it conditionally change.
-/// Boxing can achieve both.
-///
-/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
-/// [helper_types]: ../helper_types/index.html
-/// be_sure_we_got_to_the_end_of_it
-fn issue883() {
-}
-
-/// `foo_bar
-/// baz_quz`
-/// [foo
-/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
-fn multiline() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: `PackedNode`
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: PackedNode
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073_alt() {
-}
-
-/// Tests more than three quotes:
-/// ````
-/// DoNotWarn
-/// ```
-/// StillDont
-/// ````
-/// be_sure_we_got_to_the_end_of_it
-fn four_quotes() {
-}
-
-/// See [NIST SP 800-56A, revision 2].
-///
-/// [NIST SP 800-56A, revision 2]:
-/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
-fn issue_902_comment() {}
-
-#[cfg_attr(feature = "a", doc = " ```")]
-#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
-/// fn main() {
-/// let s = "localhost:10000".to_string();
-/// println!("{}", s);
-/// }
-/// ```
-fn issue_1469() {}
-
-/**
- * This is a doc comment that should not be a list
- *This would also be an error under a strict common mark interpretation
- */
-fn issue_1920() {}
-
-/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
-///
-/// Not ok: http://www.unicode.org
-/// Not ok: https://www.unicode.org
-/// Not ok: http://www.unicode.org/
-/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
-fn issue_1832() {}
-
-/// An iterator over mycrate::Collection's values.
-/// It should not lint a `'static` lifetime in ticks.
-fn issue_2210() {}
-
-/// This should not cause the lint to trigger:
-/// #REQ-data-family.lint_partof_exists
-fn issue_2343() {}
-
-/// This should not cause an ICE:
-/// __|_ _|__||_|
-fn pulldown_cmark_crash() {}
-
-/// This should not lint
-/// (regression test for #7758)
-/// [plain text][path::to::item]
-fn intra_doc_link() {}
-
-// issue #7033 - generic_const_exprs ICE
-struct S<T, const N: usize>
-where [(); N.checked_next_power_of_two().unwrap()]: {
- arr: [T; N.checked_next_power_of_two().unwrap()],
- n: usize,
-}
-
-impl<T: Copy + Default, const N: usize> S<T, N>
-where [(); N.checked_next_power_of_two().unwrap()]: {
- fn new() -> Self {
- Self {
- arr: [T::default(); N.checked_next_power_of_two().unwrap()],
- n: 0,
- }
- }
-}
+++ /dev/null
-error: you should put `foo_bar` between ticks in the documentation
- --> $DIR/doc.rs:8:9
- |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^
- |
- = note: `-D clippy::doc-markdown` implied by `-D warnings`
-
-error: you should put `foo::bar` between ticks in the documentation
- --> $DIR/doc.rs:8:51
- |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^^
-
-error: you should put `Foo::some_fun` between ticks in the documentation
- --> $DIR/doc.rs:9:83
- |
-LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
- | ^^^^^^^^^^^^^
-
-error: you should put `a::global:path` between ticks in the documentation
- --> $DIR/doc.rs:11:15
- |
-LL | /// Here be ::a::global:path.
- | ^^^^^^^^^^^^^^
-
-error: you should put `NotInCodeBlock` between ticks in the documentation
- --> $DIR/doc.rs:12:22
- |
-LL | /// That's not code ~NotInCodeBlock~.
- | ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:13:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:27:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:34:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:48:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:71:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `link_with_underscores` between ticks in the documentation
- --> $DIR/doc.rs:75:22
- |
-LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `inline_link2` between ticks in the documentation
- --> $DIR/doc.rs:78:21
- |
-LL | /// It can also be [inline_link2].
- | ^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:88:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:96:8
- |
-LL | /// ## CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:99:7
- |
-LL | /// # CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:101:22
- |
-LL | /// Not a title #897 CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:102:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:109:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:122:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
- --> $DIR/doc.rs:133:43
- |
-LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
- --> $DIR/doc.rs:138:5
- |
-LL | And BarQuz too.
- | ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:139:1
- |
-LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
- --> $DIR/doc.rs:144:43
- |
-LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
- --> $DIR/doc.rs:149:5
- |
-LL | And BarQuz too.
- | ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:150:1
- |
-LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:161:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:188:13
- |
-LL | /// Not ok: http://www.unicode.org
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:189:13
- |
-LL | /// Not ok: https://www.unicode.org
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:190:13
- |
-LL | /// Not ok: http://www.unicode.org/
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:191:13
- |
-LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `mycrate::Collection` between ticks in the documentation
- --> $DIR/doc.rs:194:22
- |
-LL | /// An iterator over mycrate::Collection's values.
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 31 previous errors
-
--- /dev/null
+/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
+///
+/// Not ok: http://www.unicode.org
+/// Not ok: https://www.unicode.org
+/// Not ok: http://www.unicode.org/
+/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+fn issue_1832() {}
+
+fn main() {}
--- /dev/null
+/// See [NIST SP 800-56A, revision 2].
+///
+/// [NIST SP 800-56A, revision 2]:
+/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
+fn issue_902_comment() {}
+
+fn main() {}
|
= help: a backtick may be missing a pair
-error: you should put `should_be` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:15:32
|
LL | /// This paragraph is fine and should_be linted normally.
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: try: ``should_be``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:17:1
|
= help: a backtick may be missing a pair
-error: you should put `not_fine` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:30:8
|
LL | /// ## not_fine
- | ^^^^^^^^
+ | ^^^^^^^^ help: try: ``not_fine``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:32:1
|
= help: a backtick may be missing a pair
-error: you should put `backticks_here` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:35:23
|
LL | /// - This item needs backticks_here
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: try: ``backticks_here``
error: aborting due to 8 previous errors
-// edition:2018
#![warn(clippy::missing_errors_doc)]
#![allow(clippy::result_unit_err)]
#![allow(clippy::unnecessary_wraps)]
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:8:1
+ --> $DIR/doc_errors.rs:7:1
|
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:12:1
+ --> $DIR/doc_errors.rs:11:1
|
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:17:1
+ --> $DIR/doc_errors.rs:16:1
|
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:22:1
+ --> $DIR/doc_errors.rs:21:1
|
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:52:5
+ --> $DIR/doc_errors.rs:51:5
|
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:57:5
+ --> $DIR/doc_errors.rs:56:5
|
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:86:5
+ --> $DIR/doc_errors.rs:85:5
|
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
drive();
}
}
+
+// do not lint if any parent has `#[doc(hidden)]` attribute
+// see #7347
+#[doc(hidden)]
+pub mod __macro {
+ pub struct T;
+ impl T {
+ pub unsafe fn f() {}
+ }
+}
+
+/// # Implementation safety
+pub unsafe trait DocumentedUnsafeTraitWithImplementationHeader {
+ fn method();
+}
|
= help: remove the prefixes and use full paths to the variants instead of glob imports
-error: all variants have the same prefix: `With`
+error: all variants have the same prefix: `WithOut`
--> $DIR/enum_variants.rs:81:1
|
LL | / enum Seallll {
if g == NotStructuralEq::A {}
if let Some(NotPartialEq::A) = Some(f) {}
if Some(g) == Some(NotStructuralEq::A) {}
+
+ macro_rules! m1 {
+ (x) => {
+ "abc"
+ };
+ }
+ if "abc" == m1!(x) {
+ println!("OK");
+ }
}
if let NotStructuralEq::A = g {}
if let Some(NotPartialEq::A) = Some(f) {}
if let Some(NotStructuralEq::A) = Some(g) {}
+
+ macro_rules! m1 {
+ (x) => {
+ "abc"
+ };
+ }
+ if let m1!(x) = "abc" {
+ println!("OK");
+ }
}
LL | if let Some(NotStructuralEq::A) = Some(g) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
-error: aborting due to 10 previous errors
+error: this pattern matching can be expressed using equality
+ --> $DIR/equatable_if_let.rs:75:8
+ |
+LL | if let m1!(x) = "abc" {
+ | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)`
+
+error: aborting due to 11 previous errors
-// edition:2018
-
#[warn(clippy::eval_order_dependence)]
#[allow(
unused_assignments,
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:16:9
+ --> $DIR/eval_order_dependence.rs:14:9
|
LL | } + x;
| ^
|
= note: `-D clippy::eval-order-dependence` implied by `-D warnings`
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:14:9
+ --> $DIR/eval_order_dependence.rs:12:9
|
LL | x = 1;
| ^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:19:5
+ --> $DIR/eval_order_dependence.rs:17:5
|
LL | x += {
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:20:9
+ --> $DIR/eval_order_dependence.rs:18:9
|
LL | x = 20;
| ^^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:32:12
+ --> $DIR/eval_order_dependence.rs:30:12
|
LL | a: x,
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:34:13
+ --> $DIR/eval_order_dependence.rs:32:13
|
LL | x = 6;
| ^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:41:9
+ --> $DIR/eval_order_dependence.rs:39:9
|
LL | x += {
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:42:13
+ --> $DIR/eval_order_dependence.rs:40:13
|
LL | x = 20;
| ^^^^^^
// run-rustfix
#![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
// run-rustfix
#![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:28:26
+ --> $DIR/expect_fun_call.rs:29:26
|
LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
= note: `-D clippy::expect-fun-call` implied by `-D warnings`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:31:26
+ --> $DIR/expect_fun_call.rs:32:26
|
LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:41:25
+ --> $DIR/expect_fun_call.rs:42:25
|
LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:44:25
+ --> $DIR/expect_fun_call.rs:45:25
|
LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:56:17
+ --> $DIR/expect_fun_call.rs:57:17
|
LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:77:21
+ --> $DIR/expect_fun_call.rs:78:21
|
LL | Some("foo").expect(&get_string());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:78:21
+ --> $DIR/expect_fun_call.rs:79:21
|
LL | Some("foo").expect(get_string().as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:79:21
+ --> $DIR/expect_fun_call.rs:80:21
|
LL | Some("foo").expect(get_string().as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:81:21
+ --> $DIR/expect_fun_call.rs:82:21
|
LL | Some("foo").expect(get_static_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:82:21
+ --> $DIR/expect_fun_call.rs:83:21
|
LL | Some("foo").expect(get_non_static_str(&0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:86:16
+ --> $DIR/expect_fun_call.rs:87:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:92:17
+ --> $DIR/expect_fun_call.rs:93:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
#![deny(clippy::fallible_impl_from)]
-#![allow(clippy::if_then_panic)]
// docs example
struct Foo(i32);
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:6:1
+ --> $DIR/fallible_impl_from.rs:5:1
|
LL | / impl From<String> for Foo {
LL | | fn from(s: String) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:8:13
+ --> $DIR/fallible_impl_from.rs:7:13
|
LL | Foo(s.parse().unwrap())
| ^^^^^^^^^^^^^^^^^^
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:27:1
+ --> $DIR/fallible_impl_from.rs:26:1
|
LL | / impl From<usize> for Invalid {
LL | | fn from(i: usize) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:30:13
+ --> $DIR/fallible_impl_from.rs:29:13
|
LL | panic!();
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:36:1
+ --> $DIR/fallible_impl_from.rs:35:1
|
LL | / impl From<Option<String>> for Invalid {
LL | | fn from(s: Option<String>) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:38:17
+ --> $DIR/fallible_impl_from.rs:37:17
|
LL | let s = s.unwrap();
| ^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | panic!("{:?}", s);
| ^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:54:1
+ --> $DIR/fallible_impl_from.rs:53:1
|
LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
LL | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:56:12
+ --> $DIR/fallible_impl_from.rs:55:12
|
LL | if s.parse::<u32>().ok().unwrap() != 42 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | panic!("{:?}", s);
| ^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors
i: T,
j: U,
}
+
+mod issue6312 {
+ use std::sync::atomic::AtomicBool;
+ use std::sync::Arc;
+
+ // do not lint: type implements `Drop` but not all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropNotAllCopy {
+ name: String,
+ delay_data_sync: Arc<AtomicBool>,
+ }
+
+ impl Drop for ImplDropNotAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropNotAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropNotAllCopy::default();
+ f.name = name.to_owned();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type implements `Drop` and all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl Drop for ImplDropAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type does not implement `Drop` though all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct NoDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl NoDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = NoDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ }
+}
LL | let mut a: WrapperMulti<i32, i64> = Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error: field assignment outside of initializer for an instance created with Default::default()
+ --> $DIR/field_reassign_with_default.rs:229:13
+ |
+LL | f.name = name.len();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+ --> $DIR/field_reassign_with_default.rs:228:13
+ |
+LL | let mut f = ImplDropAllCopy::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+ --> $DIR/field_reassign_with_default.rs:245:13
+ |
+LL | f.name = name.len();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+ --> $DIR/field_reassign_with_default.rs:244:13
+ |
+LL | let mut f = NoDropAllCopy::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
--- /dev/null
+#![warn(clippy::fn_to_numeric_cast_any)]
+#![allow(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> u8 {
+ 0
+}
+
+fn generic_foo<T>(x: T) -> T {
+ x
+}
+
+trait Trait {
+ fn static_method() -> u32 {
+ 2
+ }
+}
+
+struct Struct;
+
+impl Trait for Struct {}
+
+fn fn_pointer_to_integer() {
+ let _ = foo as i8;
+ let _ = foo as i16;
+ let _ = foo as i32;
+ let _ = foo as i64;
+ let _ = foo as i128;
+ let _ = foo as isize;
+
+ let _ = foo as u8;
+ let _ = foo as u16;
+ let _ = foo as u32;
+ let _ = foo as u64;
+ let _ = foo as u128;
+ let _ = foo as usize;
+}
+
+fn static_method_to_integer() {
+ let _ = Struct::static_method as usize;
+}
+
+fn fn_with_fn_arg(f: fn(i32) -> u32) -> usize {
+ f as usize
+}
+
+fn fn_with_generic_static_trait_method<T: Trait>() -> usize {
+ T::static_method as usize
+}
+
+fn closure_to_fn_to_integer() {
+ let clos = |x| x * 2_u32;
+
+ let _ = (clos as fn(u32) -> u32) as usize;
+}
+
+fn fn_to_raw_ptr() {
+ let _ = foo as *const ();
+}
+
+fn cast_fn_to_self() {
+ // Casting to the same function pointer type should be permitted.
+ let _ = foo as fn() -> u8;
+}
+
+fn cast_generic_to_concrete() {
+ // Casting to a more concrete function pointer type should be permitted.
+ let _ = generic_foo as fn(usize) -> usize;
+}
+
+fn cast_closure_to_fn() {
+ // Casting a closure to a function pointer should be permitted.
+ let id = |x| x;
+ let _ = id as fn(usize) -> usize;
+}
+
+fn main() {}
--- /dev/null
+error: casting function pointer `foo` to `i8`
+ --> $DIR/fn_to_numeric_cast_any.rs:23:13
+ |
+LL | let _ = foo as i8;
+ | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+ |
+ = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`
+ --> $DIR/fn_to_numeric_cast_any.rs:24:13
+ |
+LL | let _ = foo as i16;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+
+error: casting function pointer `foo` to `i32`
+ --> $DIR/fn_to_numeric_cast_any.rs:25:13
+ |
+LL | let _ = foo as i32;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+
+error: casting function pointer `foo` to `i64`
+ --> $DIR/fn_to_numeric_cast_any.rs:26:13
+ |
+LL | let _ = foo as i64;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+
+error: casting function pointer `foo` to `i128`
+ --> $DIR/fn_to_numeric_cast_any.rs:27:13
+ |
+LL | let _ = foo as i128;
+ | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+
+error: casting function pointer `foo` to `isize`
+ --> $DIR/fn_to_numeric_cast_any.rs:28:13
+ |
+LL | let _ = foo as isize;
+ | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+
+error: casting function pointer `foo` to `u8`
+ --> $DIR/fn_to_numeric_cast_any.rs:30:13
+ |
+LL | let _ = foo as u8;
+ | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+
+error: casting function pointer `foo` to `u16`
+ --> $DIR/fn_to_numeric_cast_any.rs:31:13
+ |
+LL | let _ = foo as u16;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+
+error: casting function pointer `foo` to `u32`
+ --> $DIR/fn_to_numeric_cast_any.rs:32:13
+ |
+LL | let _ = foo as u32;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+
+error: casting function pointer `foo` to `u64`
+ --> $DIR/fn_to_numeric_cast_any.rs:33:13
+ |
+LL | let _ = foo as u64;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+
+error: casting function pointer `foo` to `u128`
+ --> $DIR/fn_to_numeric_cast_any.rs:34:13
+ |
+LL | let _ = foo as u128;
+ | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+
+error: casting function pointer `foo` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:35:13
+ |
+LL | let _ = foo as usize;
+ | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+
+error: casting function pointer `Struct::static_method` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:39:13
+ |
+LL | let _ = Struct::static_method as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+
+error: casting function pointer `f` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:43:5
+ |
+LL | f as usize
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+
+error: casting function pointer `T::static_method` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:47:5
+ |
+LL | T::static_method as usize
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+
+error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:53:13
+ |
+LL | let _ = (clos as fn(u32) -> u32) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+
+error: casting function pointer `foo` to `*const ()`
+ --> $DIR/fn_to_numeric_cast_any.rs:57:13
+ |
+LL | let _ = foo as *const ();
+ | ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+
+error: aborting due to 17 previous errors
+
// run-rustfix
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
#![warn(clippy::useless_format)]
struct Foo(pub String);
r##"foo {}
" bar"##.to_string();
+ let _ = String::new();
+
"foo".to_string();
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
// run-rustfix
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
#![warn(clippy::useless_format)]
struct Foo(pub String);
" bar"##
);
+ let _ = format!("");
+
format!("{}", "foo");
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
|
error: useless use of `format!`
- --> $DIR/format.rs:21:5
+ --> $DIR/format.rs:21:13
+ |
+LL | let _ = format!("");
+ | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
+
+error: useless use of `format!`
+ --> $DIR/format.rs:23:5
|
LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:25:5
+ --> $DIR/format.rs:27:5
|
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:26:5
+ --> $DIR/format.rs:28:5
|
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:31:5
+ --> $DIR/format.rs:33:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:35:5
+ --> $DIR/format.rs:37:5
|
LL | format!("{:+}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:36:5
+ --> $DIR/format.rs:38:5
|
LL | format!("{:<}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:63:5
+ --> $DIR/format.rs:65:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:65:5
+ --> $DIR/format.rs:67:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:69:18
+ --> $DIR/format.rs:71:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
- --> $DIR/format.rs:73:22
+ --> $DIR/format.rs:75:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
--- /dev/null
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+ fn to_string(&self) -> String {
+ String::from("somewhere")
+ }
+}
+
+struct X(u32);
+
+impl Deref for X {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+ type Target = &'a X;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+impl std::fmt::Display for Z {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Z")
+ }
+}
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: something failed at {}", Location::caller().to_string());
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ Location::caller().to_string()
+ };
+}
+
+fn main() {
+ let x = &X(1);
+ let x_ref = &x;
+
+ let _ = format!("error: something failed at {}", Location::caller());
+ let _ = write!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller()
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller()
+ );
+ print!("error: something failed at {}", Location::caller());
+ println!("error: something failed at {}", Location::caller());
+ eprint!("error: something failed at {}", Location::caller());
+ eprintln!("error: something failed at {}", Location::caller());
+ let _ = format_args!("error: something failed at {}", Location::caller());
+ assert!(true, "error: something failed at {}", Location::caller());
+ assert_eq!(0, 0, "error: something failed at {}", Location::caller());
+ assert_ne!(0, 0, "error: something failed at {}", Location::caller());
+ panic!("error: something failed at {}", Location::caller());
+ println!("{}", *X(1));
+ println!("{}", ***Y(&X(1)));
+ println!("{}", Z(1));
+ println!("{}", **x);
+ println!("{}", ***x_ref);
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{bar}", foo = "foo", bar = "bar");
+ println!("{foo}{bar}", foo = "foo", bar = "bar");
+ println!("{foo}{bar}", bar = "bar", foo = "foo");
+ println!("{foo}{bar}", bar = "bar", foo = "foo");
+
+ // negative tests
+ println!("error: something failed at {}", Somewhere.to_string());
+ // The next two tests are negative because caching the string might be faster than calling `<X as
+ // Display>::fmt` twice.
+ println!("{} and again {0}", x.to_string());
+ println!("{foo}{foo}", foo = "foo".to_string());
+ my_macro!();
+ println!("error: something failed at {}", my_other_macro!());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{foo:?}", foo = "foo".to_string());
+}
--- /dev/null
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+ fn to_string(&self) -> String {
+ String::from("somewhere")
+ }
+}
+
+struct X(u32);
+
+impl Deref for X {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+ type Target = &'a X;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+impl std::fmt::Display for Z {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Z")
+ }
+}
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: something failed at {}", Location::caller().to_string());
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ Location::caller().to_string()
+ };
+}
+
+fn main() {
+ let x = &X(1);
+ let x_ref = &x;
+
+ let _ = format!("error: something failed at {}", Location::caller().to_string());
+ let _ = write!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller().to_string()
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller().to_string()
+ );
+ print!("error: something failed at {}", Location::caller().to_string());
+ println!("error: something failed at {}", Location::caller().to_string());
+ eprint!("error: something failed at {}", Location::caller().to_string());
+ eprintln!("error: something failed at {}", Location::caller().to_string());
+ let _ = format_args!("error: something failed at {}", Location::caller().to_string());
+ assert!(true, "error: something failed at {}", Location::caller().to_string());
+ assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ panic!("error: something failed at {}", Location::caller().to_string());
+ println!("{}", X(1).to_string());
+ println!("{}", Y(&X(1)).to_string());
+ println!("{}", Z(1).to_string());
+ println!("{}", x.to_string());
+ println!("{}", x_ref.to_string());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+ println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+ println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+ println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+
+ // negative tests
+ println!("error: something failed at {}", Somewhere.to_string());
+ // The next two tests are negative because caching the string might be faster than calling `<X as
+ // Display>::fmt` twice.
+ println!("{} and again {0}", x.to_string());
+ println!("{foo}{foo}", foo = "foo".to_string());
+ my_macro!();
+ println!("error: something failed at {}", my_other_macro!());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{foo:?}", foo = "foo".to_string());
+}
--- /dev/null
+error: `to_string` applied to a type that implements `Display` in `format!` args
+ --> $DIR/format_args.rs:76:72
+ |
+LL | let _ = format!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+ |
+ = note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
+
+error: `to_string` applied to a type that implements `Display` in `write!` args
+ --> $DIR/format_args.rs:80:27
+ |
+LL | Location::caller().to_string()
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `writeln!` args
+ --> $DIR/format_args.rs:85:27
+ |
+LL | Location::caller().to_string()
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `print!` args
+ --> $DIR/format_args.rs:87:63
+ |
+LL | print!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:88:65
+ |
+LL | println!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `eprint!` args
+ --> $DIR/format_args.rs:89:64
+ |
+LL | eprint!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `eprintln!` args
+ --> $DIR/format_args.rs:90:66
+ |
+LL | eprintln!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `format_args!` args
+ --> $DIR/format_args.rs:91:77
+ |
+LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert!` args
+ --> $DIR/format_args.rs:92:70
+ |
+LL | assert!(true, "error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
+ --> $DIR/format_args.rs:93:73
+ |
+LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
+ --> $DIR/format_args.rs:94:73
+ |
+LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `panic!` args
+ --> $DIR/format_args.rs:95:63
+ |
+LL | panic!("error: something failed at {}", Location::caller().to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:96:20
+ |
+LL | println!("{}", X(1).to_string());
+ | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:97:20
+ |
+LL | println!("{}", Y(&X(1)).to_string());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:98:24
+ |
+LL | println!("{}", Z(1).to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:99:20
+ |
+LL | println!("{}", x.to_string());
+ | ^^^^^^^^^^^^^ help: use this: `**x`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:100:20
+ |
+LL | println!("{}", x_ref.to_string());
+ | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:102:39
+ |
+LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:103:52
+ |
+LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:104:39
+ |
+LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:105:52
+ |
+LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: aborting due to 21 previous errors
+
--- /dev/null
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![warn(clippy::format_in_format_args)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Error, ErrorKind, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: {}", format!("something failed at {}", Location::caller()));
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ format!("something failed at {}", Location::caller())
+ };
+}
+
+fn main() {
+ let error = Error::new(ErrorKind::Other, "bad thing");
+ let x = 'x';
+
+ println!("error: {}", format!("something failed at {}", Location::caller()));
+ println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+ println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+ println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+ println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+ println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+ println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+ let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+ let _ = write!(
+ stdout(),
+ "error: {}",
+ format!("something failed at {}", Location::caller())
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: {}",
+ format!("something failed at {}", Location::caller())
+ );
+ print!("error: {}", format!("something failed at {}", Location::caller()));
+ eprint!("error: {}", format!("something failed at {}", Location::caller()));
+ eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+ let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+ assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+ assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ panic!("error: {}", format!("something failed at {}", Location::caller()));
+
+ // negative tests
+ println!("error: {}", format_args!("something failed at {}", Location::caller()));
+ println!("error: {:>70}", format!("something failed at {}", Location::caller()));
+ println!("error: {} {0}", format!("something failed at {}", Location::caller()));
+ println!("{} and again {0}", format!("hi {}", x));
+ my_macro!();
+ println!("error: {}", my_other_macro!());
+}
--- /dev/null
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:27:5
+ |
+LL | println!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::format-in-format-args` implied by `-D warnings`
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:28:5
+ |
+LL | println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:29:5
+ |
+LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:30:5
+ |
+LL | println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:31:5
+ |
+LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:32:5
+ |
+LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:33:5
+ |
+LL | println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format!` args
+ --> $DIR/format_args_unfixable.rs:34:13
+ |
+LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `format!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `write!` args
+ --> $DIR/format_args_unfixable.rs:35:13
+ |
+LL | let _ = write!(
+ | _____________^
+LL | | stdout(),
+LL | | "error: {}",
+LL | | format!("something failed at {}", Location::caller())
+LL | | );
+ | |_____^
+ |
+ = help: combine the `format!(..)` arguments with the outer `write!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `writeln!` args
+ --> $DIR/format_args_unfixable.rs:40:13
+ |
+LL | let _ = writeln!(
+ | _____________^
+LL | | stdout(),
+LL | | "error: {}",
+LL | | format!("something failed at {}", Location::caller())
+LL | | );
+ | |_____^
+ |
+ = help: combine the `format!(..)` arguments with the outer `writeln!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `print!` args
+ --> $DIR/format_args_unfixable.rs:45:5
+ |
+LL | print!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `print!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprint!` args
+ --> $DIR/format_args_unfixable.rs:46:5
+ |
+LL | eprint!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `eprint!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprintln!` args
+ --> $DIR/format_args_unfixable.rs:47:5
+ |
+LL | eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `eprintln!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format_args!` args
+ --> $DIR/format_args_unfixable.rs:48:13
+ |
+LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `format_args!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert!` args
+ --> $DIR/format_args_unfixable.rs:49:5
+ |
+LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_eq!` args
+ --> $DIR/format_args_unfixable.rs:50:5
+ |
+LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert_eq!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_ne!` args
+ --> $DIR/format_args_unfixable.rs:51:5
+ |
+LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert_ne!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `panic!` args
+ --> $DIR/format_args_unfixable.rs:52:5
+ |
+LL | panic!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `panic!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: aborting due to 18 previous errors
+
-// edition:2018
#![warn(clippy::future_not_send)]
use std::cell::Cell;
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:8:62
+ --> $DIR/future_not_send.rs:7:62
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ future returned by `private_future` is not `Send`
|
= note: `-D clippy::future-not-send` implied by `-D warnings`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:9:5
+ --> $DIR/future_not_send.rs:8:5
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:9:5
+ --> $DIR/future_not_send.rs:8:5
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ---- has type `&std::cell::Cell<usize>` which is not `Send`
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:12:42
+ --> $DIR/future_not_send.rs:11:42
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:13:5
+ --> $DIR/future_not_send.rs:12:5
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:20:63
+ --> $DIR/future_not_send.rs:19:63
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ future returned by `private_future2` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:20:26
+ --> $DIR/future_not_send.rs:19:26
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
- --> $DIR/future_not_send.rs:20:40
+ --> $DIR/future_not_send.rs:19:40
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:24:43
+ --> $DIR/future_not_send.rs:23:43
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
| ^ future returned by `public_future2` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:24:29
+ --> $DIR/future_not_send.rs:23:29
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
| ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:35:39
+ --> $DIR/future_not_send.rs:34:39
|
LL | async fn private_future(&self) -> usize {
| ^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:36:9
+ --> $DIR/future_not_send.rs:35:9
|
LL | async fn private_future(&self) -> usize {
| ----- has type `&Dummy` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:40:39
+ --> $DIR/future_not_send.rs:39:39
|
LL | pub async fn public_future(&self) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:41:9
+ --> $DIR/future_not_send.rs:40:9
|
LL | pub async fn public_future(&self) {
| ----- has type `&Dummy` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:50:37
+ --> $DIR/future_not_send.rs:49:37
|
LL | async fn generic_future<T>(t: T) -> T
| ^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:55:5
+ --> $DIR/future_not_send.rs:54:5
|
LL | let rt = &t;
| -- has type `&T` which is not `Send`
= note: `T` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:66:34
+ --> $DIR/future_not_send.rs:65:34
|
LL | async fn unclear_future<T>(t: T) {}
| ^ future returned by `unclear_future` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:66:28
+ --> $DIR/future_not_send.rs:65:28
|
LL | async fn unclear_future<T>(t: T) {}
| ^ has type `T` which is not `Send`
#![warn(clippy::all)]
#![warn(clippy::if_not_else)]
+fn foo() -> bool {
+ unimplemented!()
+}
fn bla() -> bool {
unimplemented!()
}
} else {
println!("Bunny");
}
+ if !foo() {
+ println!("Foo");
+ } else if !bla() {
+ println!("Bugs");
+ } else {
+ println!("Bunny");
+ }
}
error: unnecessary boolean `not` operation
- --> $DIR/if_not_else.rs:9:5
+ --> $DIR/if_not_else.rs:12:5
|
LL | / if !bla() {
LL | | println!("Bugs");
= help: remove the `!` and swap the blocks of the `if`/`else`
error: unnecessary `!=` operation
- --> $DIR/if_not_else.rs:14:5
+ --> $DIR/if_not_else.rs:17:5
|
LL | / if 4 != 5 {
LL | | println!("Bugs");
+++ /dev/null
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
- let a = vec![1, 2, 3];
- let c = Some(2);
- if !a.is_empty()
- && a.len() == 3
- && c != None
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- {
- panic!("qaqaq{:?}", a);
- }
- assert!(a.is_empty(), "qaqaq{:?}", a);
- assert!(a.is_empty(), "qwqwq");
- if a.len() == 3 {
- println!("qwq");
- println!("qwq");
- println!("qwq");
- }
- if let Some(b) = c {
- panic!("orz {}", b);
- }
- if a.len() == 3 {
- panic!("qaqaq");
- } else {
- println!("qwq");
- }
- let b = vec![1, 2, 3];
- assert!(!b.is_empty(), "panic1");
- assert!(!(b.is_empty() && a.is_empty()), "panic2");
- assert!(!(a.is_empty() && !b.is_empty()), "panic3");
- assert!(!(b.is_empty() || a.is_empty()), "panic4");
- assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-}
+++ /dev/null
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
- let a = vec![1, 2, 3];
- let c = Some(2);
- if !a.is_empty()
- && a.len() == 3
- && c != None
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- {
- panic!("qaqaq{:?}", a);
- }
- if !a.is_empty() {
- panic!("qaqaq{:?}", a);
- }
- if !a.is_empty() {
- panic!("qwqwq");
- }
- if a.len() == 3 {
- println!("qwq");
- println!("qwq");
- println!("qwq");
- }
- if let Some(b) = c {
- panic!("orz {}", b);
- }
- if a.len() == 3 {
- panic!("qaqaq");
- } else {
- println!("qwq");
- }
- let b = vec![1, 2, 3];
- if b.is_empty() {
- panic!("panic1");
- }
- if b.is_empty() && a.is_empty() {
- panic!("panic2");
- }
- if a.is_empty() && !b.is_empty() {
- panic!("panic3");
- }
- if b.is_empty() || a.is_empty() {
- panic!("panic4");
- }
- if a.is_empty() || !b.is_empty() {
- panic!("panic5");
- }
-}
+++ /dev/null
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:19:5
- |
-LL | / if !a.is_empty() {
-LL | | panic!("qaqaq{:?}", a);
-LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
- |
- = note: `-D clippy::if-then-panic` implied by `-D warnings`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:22:5
- |
-LL | / if !a.is_empty() {
-LL | | panic!("qwqwq");
-LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:39:5
- |
-LL | / if b.is_empty() {
-LL | | panic!("panic1");
-LL | | }
- | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:42:5
- |
-LL | / if b.is_empty() && a.is_empty() {
-LL | | panic!("panic2");
-LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:45:5
- |
-LL | / if a.is_empty() && !b.is_empty() {
-LL | | panic!("panic3");
-LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:48:5
- |
-LL | / if b.is_empty() || a.is_empty() {
-LL | | panic!("panic4");
-LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:51:5
- |
-LL | / if a.is_empty() || !b.is_empty() {
-LL | | panic!("panic5");
-LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
-
-error: aborting due to 7 previous errors
-
-// edition:2018
// aux-build:implicit_hasher_macros.rs
#![deny(clippy::implicit_hasher)]
#![allow(unused)]
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:17:35
+ --> $DIR/implicit_hasher.rs:16:35
|
LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
| ^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/implicit_hasher.rs:3:9
+ --> $DIR/implicit_hasher.rs:2:9
|
LL | #![deny(clippy::implicit_hasher)]
| ^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:26:36
+ --> $DIR/implicit_hasher.rs:25:36
|
LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
| ^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:31:19
+ --> $DIR/implicit_hasher.rs:30:19
|
LL | impl Foo<i16> for HashMap<String, String> {
| ^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:48:32
+ --> $DIR/implicit_hasher.rs:47:32
|
LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
| ^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:53:19
+ --> $DIR/implicit_hasher.rs:52:19
|
LL | impl Foo<i16> for HashSet<String> {
| ^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:70:23
+ --> $DIR/implicit_hasher.rs:69:23
|
LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:70:53
+ --> $DIR/implicit_hasher.rs:69:53
|
LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:74:43
+ --> $DIR/implicit_hasher.rs:73:43
|
LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
| ^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:82:33
+ --> $DIR/implicit_hasher.rs:81:33
|
LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:82:63
+ --> $DIR/implicit_hasher.rs:81:63
|
LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:101:35
+ --> $DIR/implicit_hasher.rs:100:35
|
LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
| ^^^^^^^^^^^^^^^^^
-// edition:2018
// run-rustfix
#![warn(clippy::implicit_return)]
-// edition:2018
// run-rustfix
#![warn(clippy::implicit_return)]
error: missing `return` statement
- --> $DIR/implicit_return.rs:13:5
+ --> $DIR/implicit_return.rs:12:5
|
LL | true
| ^^^^ help: add `return` as shown: `return true`
= note: `-D clippy::implicit-return` implied by `-D warnings`
error: missing `return` statement
- --> $DIR/implicit_return.rs:17:15
+ --> $DIR/implicit_return.rs:16:15
|
LL | if true { true } else { false }
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:17:29
+ --> $DIR/implicit_return.rs:16:29
|
LL | if true { true } else { false }
| ^^^^^ help: add `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:23:17
+ --> $DIR/implicit_return.rs:22:17
|
LL | true => false,
| ^^^^^ help: add `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:24:20
+ --> $DIR/implicit_return.rs:23:20
|
LL | false => { true },
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:37:9
+ --> $DIR/implicit_return.rs:36:9
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:44:13
+ --> $DIR/implicit_return.rs:43:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:52:13
+ --> $DIR/implicit_return.rs:51:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:70:18
+ --> $DIR/implicit_return.rs:69:18
|
LL | let _ = || { true };
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:71:16
+ --> $DIR/implicit_return.rs:70:16
|
LL | let _ = || true;
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:79:5
+ --> $DIR/implicit_return.rs:78:5
|
LL | format!("test {}", "test")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
error: missing `return` statement
- --> $DIR/implicit_return.rs:88:5
+ --> $DIR/implicit_return.rs:87:5
|
LL | m!(true, false)
| ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
error: missing `return` statement
- --> $DIR/implicit_return.rs:94:13
+ --> $DIR/implicit_return.rs:93:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:99:17
+ --> $DIR/implicit_return.rs:98:17
|
LL | break 'outer false;
| ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:114:5
+ --> $DIR/implicit_return.rs:113:5
|
LL | / loop {
LL | | m!(true);
|
error: missing `return` statement
- --> $DIR/implicit_return.rs:128:5
+ --> $DIR/implicit_return.rs:127:5
|
LL | true
| ^^^^ help: add `return` as shown: `return true`
if i_64 != 0 {
i_64 -= 1;
}
+
+ // issue #7831
+ // No Lint
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("side effect");
+ }
}
if i_64 != 0 {
i_64 -= 1;
}
+
+ // issue #7831
+ // No Lint
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("side effect");
+ }
}
// run-rustfix
-// edition:2018
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
// run-rustfix
-// edition:2018
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
error: struct constructor field order is inconsistent with struct definition field order
- --> $DIR/inconsistent_struct_constructor.rs:34:9
+ --> $DIR/inconsistent_struct_constructor.rs:33:9
|
LL | Foo { y, x, z };
| ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
= note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
error: struct constructor field order is inconsistent with struct definition field order
- --> $DIR/inconsistent_struct_constructor.rs:56:9
+ --> $DIR/inconsistent_struct_constructor.rs:55:9
|
LL | / Foo {
LL | | z,
--- /dev/null
+error: sub-expression diverges
+ --> $DIR/issue-7447.rs:23:15
+ |
+LL | byte_view(panic!());
+ | ^^^^^^^^
+ |
+ = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+ --> $DIR/issue-7447.rs:24:19
+ |
+LL | group_entries(panic!());
+ | ^^^^^^^^
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
-// edition:2018
#![allow(dead_code)]
async fn sink1<'a>(_: &'a str) {} // lint
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/issue_4266.rs:4:1
+ --> $DIR/issue_4266.rs:3:1
|
LL | async fn sink1<'a>(_: &'a str) {} // lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/issue_4266.rs:8:1
+ --> $DIR/issue_4266.rs:7:1
|
LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
+#[allow(unused_must_use)]
fn main() {
let mut vec = vec![0, 1, 2, 3];
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
linked_list.push_back(1);
binary_heap.push(1);
- let _ = &vec[..].len();
+ &vec[..].len();
vec.len();
boxed_slice.len();
vec_deque.len();
binary_heap.len();
vec.len();
- let _ = &vec[..].len();
+ &vec[..].len();
vec_deque.len();
hash_map.len();
b_tree_map.len();
linked_list.len();
- let _ = &vec[..].len();
+ &vec[..].len();
vec.len();
vec_deque.len();
hash_set.len();
}
}
+#[allow(unused_must_use)]
fn main() {
let mut vec = vec![0, 1, 2, 3];
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
linked_list.push_back(1);
binary_heap.push(1);
- let _ = &vec[..].iter().count();
+ &vec[..].iter().count();
vec.iter().count();
boxed_slice.iter().count();
vec_deque.iter().count();
binary_heap.iter().count();
vec.iter_mut().count();
- let _ = &vec[..].iter_mut().count();
+ &vec[..].iter_mut().count();
vec_deque.iter_mut().count();
hash_map.iter_mut().count();
b_tree_map.iter_mut().count();
linked_list.iter_mut().count();
- let _ = &vec[..].into_iter().count();
+ &vec[..].into_iter().count();
vec.into_iter().count();
vec_deque.into_iter().count();
hash_set.into_iter().count();
error: called `.iter().count()` on a `slice`
- --> $DIR/iter_count.rs:53:14
+ --> $DIR/iter_count.rs:54:6
|
-LL | let _ = &vec[..].iter().count();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].iter().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
|
= note: `-D clippy::iter-count` implied by `-D warnings`
error: called `.iter().count()` on a `Vec`
- --> $DIR/iter_count.rs:54:5
+ --> $DIR/iter_count.rs:55:5
|
LL | vec.iter().count();
| ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.iter().count()` on a `slice`
- --> $DIR/iter_count.rs:55:5
+ --> $DIR/iter_count.rs:56:5
|
LL | boxed_slice.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()`
error: called `.iter().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:56:5
+ --> $DIR/iter_count.rs:57:5
|
LL | vec_deque.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.iter().count()` on a `HashSet`
- --> $DIR/iter_count.rs:57:5
+ --> $DIR/iter_count.rs:58:5
|
LL | hash_set.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
error: called `.iter().count()` on a `HashMap`
- --> $DIR/iter_count.rs:58:5
+ --> $DIR/iter_count.rs:59:5
|
LL | hash_map.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.iter().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:59:5
+ --> $DIR/iter_count.rs:60:5
|
LL | b_tree_map.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.iter().count()` on a `BTreeSet`
- --> $DIR/iter_count.rs:60:5
+ --> $DIR/iter_count.rs:61:5
|
LL | b_tree_set.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
error: called `.iter().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:61:5
+ --> $DIR/iter_count.rs:62:5
|
LL | linked_list.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.iter().count()` on a `BinaryHeap`
- --> $DIR/iter_count.rs:62:5
+ --> $DIR/iter_count.rs:63:5
|
LL | binary_heap.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
error: called `.iter_mut().count()` on a `Vec`
- --> $DIR/iter_count.rs:64:5
+ --> $DIR/iter_count.rs:65:5
|
LL | vec.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.iter_mut().count()` on a `slice`
- --> $DIR/iter_count.rs:65:14
+ --> $DIR/iter_count.rs:66:6
|
-LL | let _ = &vec[..].iter_mut().count();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].iter_mut().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
error: called `.iter_mut().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:66:5
+ --> $DIR/iter_count.rs:67:5
|
LL | vec_deque.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.iter_mut().count()` on a `HashMap`
- --> $DIR/iter_count.rs:67:5
+ --> $DIR/iter_count.rs:68:5
|
LL | hash_map.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.iter_mut().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:68:5
+ --> $DIR/iter_count.rs:69:5
|
LL | b_tree_map.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.iter_mut().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:69:5
+ --> $DIR/iter_count.rs:70:5
|
LL | linked_list.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.into_iter().count()` on a `slice`
- --> $DIR/iter_count.rs:71:14
+ --> $DIR/iter_count.rs:72:6
|
-LL | let _ = &vec[..].into_iter().count();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].into_iter().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
error: called `.into_iter().count()` on a `Vec`
- --> $DIR/iter_count.rs:72:5
+ --> $DIR/iter_count.rs:73:5
|
LL | vec.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.into_iter().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:73:5
+ --> $DIR/iter_count.rs:74:5
|
LL | vec_deque.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.into_iter().count()` on a `HashSet`
- --> $DIR/iter_count.rs:74:5
+ --> $DIR/iter_count.rs:75:5
|
LL | hash_set.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
error: called `.into_iter().count()` on a `HashMap`
- --> $DIR/iter_count.rs:75:5
+ --> $DIR/iter_count.rs:76:5
|
LL | hash_map.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.into_iter().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:76:5
+ --> $DIR/iter_count.rs:77:5
|
LL | b_tree_map.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.into_iter().count()` on a `BTreeSet`
- --> $DIR/iter_count.rs:77:5
+ --> $DIR/iter_count.rs:78:5
|
LL | b_tree_set.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
error: called `.into_iter().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:78:5
+ --> $DIR/iter_count.rs:79:5
|
LL | linked_list.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.into_iter().count()` on a `BinaryHeap`
- --> $DIR/iter_count.rs:79:5
+ --> $DIR/iter_count.rs:80:5
|
LL | binary_heap.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
-// edition:2018
-
#![warn(clippy::len_without_is_empty)]
#![allow(dead_code, unused)]
error: struct `PubOne` has a public `len` method, but no `is_empty` method
- --> $DIR/len_without_is_empty.rs:9:5
+ --> $DIR/len_without_is_empty.rs:7:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::len-without-is-empty` implied by `-D warnings`
error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
- --> $DIR/len_without_is_empty.rs:57:1
+ --> $DIR/len_without_is_empty.rs:55:1
|
LL | / pub trait PubTraitsToo {
LL | | fn len(&self) -> isize;
| |_^
error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method
- --> $DIR/len_without_is_empty.rs:70:5
+ --> $DIR/len_without_is_empty.rs:68:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:74:5
+ --> $DIR/len_without_is_empty.rs:72:5
|
LL | fn is_empty(&self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:82:5
+ --> $DIR/len_without_is_empty.rs:80:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:86:5
+ --> $DIR/len_without_is_empty.rs:84:5
|
LL | pub fn is_empty(&self, x: u32) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool`
error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:94:5
+ --> $DIR/len_without_is_empty.rs:92:5
|
LL | pub fn len(self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:98:5
+ --> $DIR/len_without_is_empty.rs:96:5
|
LL | pub fn is_empty(&self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(self) -> bool`
error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
- --> $DIR/len_without_is_empty.rs:173:1
+ --> $DIR/len_without_is_empty.rs:171:1
|
LL | / pub trait DependsOnFoo: Foo {
LL | | fn len(&mut self) -> usize;
| |_^
error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:218:5
+ --> $DIR/len_without_is_empty.rs:216:5
|
LL | pub fn len(&self) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:223:5
+ --> $DIR/len_without_is_empty.rs:221:5
|
LL | pub fn is_empty(&self) -> Option<bool> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool`
error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:230:5
+ --> $DIR/len_without_is_empty.rs:228:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:235:5
+ --> $DIR/len_without_is_empty.rs:233:5
|
LL | pub fn is_empty(&self) -> Option<bool> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool>
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:230:5
+ --> $DIR/len_without_is_empty.rs:228:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:242:5
+ --> $DIR/len_without_is_empty.rs:240:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:246:5
+ --> $DIR/len_without_is_empty.rs:244:5
|
LL | pub fn is_empty(&self) -> Result<bool, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:253:5
+ --> $DIR/len_without_is_empty.rs:251:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::mixed_case_hex_literals)]
#![warn(clippy::zero_prefixed_literal)]
-#![allow(clippy::unseparated_literal_suffix)]
+#![warn(clippy::unseparated_literal_suffix)]
+#![warn(clippy::separated_literal_suffix)]
#![allow(dead_code)]
fn main() {
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:12:15
+ |
+LL | let ok4 = 0xab_cd_i32;
+ | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32`
+ |
+ = note: `-D clippy::separated-literal-suffix` implied by `-D warnings`
+
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:13:15
+ |
+LL | let ok5 = 0xAB_CD_u32;
+ | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32`
+
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:14:15
+ |
+LL | let ok5 = 0xAB_CD_isize;
+ | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:14:17
+ --> $DIR/literals.rs:15:17
|
LL | let fail1 = 0xabCD;
| ^^^^^^
|
= note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:16:17
+ |
+LL | let fail2 = 0xabCD_u32;
+ | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:15:17
+ --> $DIR/literals.rs:16:17
|
LL | let fail2 = 0xabCD_u32;
| ^^^^^^^^^^
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:17:17
+ |
+LL | let fail2 = 0xabCD_isize;
+ | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:16:17
+ --> $DIR/literals.rs:17:17
|
LL | let fail2 = 0xabCD_isize;
| ^^^^^^^^^^^^
+error: integer type suffix should be separated by an underscore
+ --> $DIR/literals.rs:18:27
+ |
+LL | let fail_multi_zero = 000_123usize;
+ | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize`
+ |
+ = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
+
error: this is a decimal constant
- --> $DIR/literals.rs:17:27
+ --> $DIR/literals.rs:18:27
|
LL | let fail_multi_zero = 000_123usize;
| ^^^^^^^^^^^^
LL | let fail_multi_zero = 0o123usize;
| ~~~~~~~~~~
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:21:16
+ |
+LL | let ok10 = 0_i64;
+ | ^^^^^ help: remove the underscore: `0i64`
+
error: this is a decimal constant
- --> $DIR/literals.rs:21:17
+ --> $DIR/literals.rs:22:17
|
LL | let fail8 = 0123;
| ^^^^
LL | let fail8 = 0o123;
| ~~~~~
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:31:16
+ |
+LL | let ok17 = 0x123_4567_8901_usize;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize`
+
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:33:18
+ --> $DIR/literals.rs:34:18
|
LL | let fail19 = 12_3456_21;
| ^^^^^^^^^^ help: consider: `12_345_621`
= note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:34:18
+ --> $DIR/literals.rs:35:18
|
LL | let fail22 = 3__4___23;
| ^^^^^^^^^ help: consider: `3_423`
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:35:18
+ --> $DIR/literals.rs:36:18
|
LL | let fail23 = 3__16___23;
| ^^^^^^^^^^ help: consider: `31_623`
error: digits of hex or binary literal not grouped by four
- --> $DIR/literals.rs:37:18
+ --> $DIR/literals.rs:38:18
|
LL | let fail24 = 0xAB_ABC_AB;
| ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB`
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
error: digits of hex or binary literal not grouped by four
- --> $DIR/literals.rs:38:18
+ --> $DIR/literals.rs:39:18
|
LL | let fail25 = 0b01_100_101;
| ^^^^^^^^^^^^ help: consider: `0b0110_0101`
-error: aborting due to 10 previous errors
+error: aborting due to 18 previous errors
-// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
// aux-build:proc_macro_derive.rs
-// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
// aux-build:proc_macro_derive.rs
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:19:5
+ --> $DIR/macro_use_imports.rs:18:5
|
LL | #[macro_use]
| ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
= note: `-D clippy::macro-use-imports` implied by `-D warnings`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:25:5
+ --> $DIR/macro_use_imports.rs:20:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:21:5
+ --> $DIR/macro_use_imports.rs:22:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:23:5
+ --> $DIR/macro_use_imports.rs:24:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
error: aborting due to 4 previous errors
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:22:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qaqaq{:?}", a);
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ |
+ = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:25:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qwqwq");
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:42:5
+ |
+LL | / if b.is_empty() {
+LL | | panic!("panic1");
+LL | | }
+ | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:45:5
+ |
+LL | / if b.is_empty() && a.is_empty() {
+LL | | panic!("panic2");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:48:5
+ |
+LL | / if a.is_empty() && !b.is_empty() {
+LL | | panic!("panic3");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:51:5
+ |
+LL | / if b.is_empty() || a.is_empty() {
+LL | | panic!("panic4");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:54:5
+ |
+LL | / if a.is_empty() || !b.is_empty() {
+LL | | panic!("panic5");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:22:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qaqaq{:?}", a);
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ |
+ = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:25:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qwqwq");
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:42:5
+ |
+LL | / if b.is_empty() {
+LL | | panic!("panic1");
+LL | | }
+ | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:45:5
+ |
+LL | / if b.is_empty() && a.is_empty() {
+LL | | panic!("panic2");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:48:5
+ |
+LL | / if a.is_empty() && !b.is_empty() {
+LL | | panic!("panic3");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:51:5
+ |
+LL | / if b.is_empty() || a.is_empty() {
+LL | | panic!("panic4");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:54:5
+ |
+LL | / if a.is_empty() || !b.is_empty() {
+LL | | panic!("panic5");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ if !a.is_empty() {
+ panic!("qaqaq{:?}", a);
+ }
+ if !a.is_empty() {
+ panic!("qwqwq");
+ }
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ if b.is_empty() {
+ panic!("panic1");
+ }
+ if b.is_empty() && a.is_empty() {
+ panic!("panic2");
+ }
+ if a.is_empty() && !b.is_empty() {
+ panic!("panic3");
+ }
+ if b.is_empty() || a.is_empty() {
+ panic!("panic4");
+ }
+ if a.is_empty() || !b.is_empty() {
+ panic!("panic5");
+ }
+}
// run-rustfix
-// edition:2018
#![warn(clippy::manual_async_fn)]
#![allow(unused)]
// run-rustfix
-// edition:2018
#![warn(clippy::manual_async_fn)]
#![allow(unused)]
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:8:1
+ --> $DIR/manual_async_fn.rs:7:1
|
LL | fn fut() -> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:13:1
+ --> $DIR/manual_async_fn.rs:12:1
|
LL | fn fut2() ->impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:18:1
+ --> $DIR/manual_async_fn.rs:17:1
|
LL | fn fut3()-> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:22:1
+ --> $DIR/manual_async_fn.rs:21:1
|
LL | fn empty_fut() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:27:1
+ --> $DIR/manual_async_fn.rs:26:1
|
LL | fn empty_fut2() ->impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:32:1
+ --> $DIR/manual_async_fn.rs:31:1
|
LL | fn empty_fut3()-> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:36:1
+ --> $DIR/manual_async_fn.rs:35:1
|
LL | fn core_fut() -> impl core::future::Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:58:5
+ --> $DIR/manual_async_fn.rs:57:5
|
LL | fn inh_fut() -> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:93:1
+ --> $DIR/manual_async_fn.rs:92:1
|
LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:102:1
+ --> $DIR/manual_async_fn.rs:101:1
|
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// edition:2018
// run-rustfix
#![warn(clippy::manual_map)]
-// edition:2018
// run-rustfix
#![warn(clippy::manual_map)]
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:15:5
+ --> $DIR/manual_map_option.rs:14:5
|
LL | / match Some(0) {
LL | | Some(_) => Some(2),
= note: `-D clippy::manual-map` implied by `-D warnings`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:20:5
+ --> $DIR/manual_map_option.rs:19:5
|
LL | / match Some(0) {
LL | | Some(x) => Some(x + 1),
| |_____^ help: try this: `Some(0).map(|x| x + 1)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:25:5
+ --> $DIR/manual_map_option.rs:24:5
|
LL | / match Some("") {
LL | | Some(x) => Some(x.is_empty()),
| |_____^ help: try this: `Some("").map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:30:5
+ --> $DIR/manual_map_option.rs:29:5
|
LL | / if let Some(x) = Some(0) {
LL | | Some(!x)
| |_____^ help: try this: `Some(0).map(|x| !x)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:37:5
+ --> $DIR/manual_map_option.rs:36:5
|
LL | / match Some(0) {
LL | | Some(x) => { Some(std::convert::identity(x)) }
| |_____^ help: try this: `Some(0).map(std::convert::identity)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:42:5
+ --> $DIR/manual_map_option.rs:41:5
|
LL | / match Some(&String::new()) {
LL | | Some(x) => Some(str::len(x)),
| |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:52:5
+ --> $DIR/manual_map_option.rs:51:5
|
LL | / match &Some([0, 1]) {
LL | | Some(x) => Some(x[0]),
| |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:57:5
+ --> $DIR/manual_map_option.rs:56:5
|
LL | / match &Some(0) {
LL | | &Some(x) => Some(x * 2),
| |_____^ help: try this: `Some(0).map(|x| x * 2)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:62:5
+ --> $DIR/manual_map_option.rs:61:5
|
LL | / match Some(String::new()) {
LL | | Some(ref x) => Some(x.is_empty()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:67:5
+ --> $DIR/manual_map_option.rs:66:5
|
LL | / match &&Some(String::new()) {
LL | | Some(x) => Some(x.len()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:72:5
+ --> $DIR/manual_map_option.rs:71:5
|
LL | / match &&Some(0) {
LL | | &&Some(x) => Some(x + x),
| |_____^ help: try this: `Some(0).map(|x| x + x)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:85:9
+ --> $DIR/manual_map_option.rs:84:9
|
LL | / match &mut Some(String::new()) {
LL | | Some(x) => Some(x.push_str("")),
| |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:91:5
+ --> $DIR/manual_map_option.rs:90:5
|
LL | / match &mut Some(String::new()) {
LL | | Some(ref x) => Some(x.len()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:96:5
+ --> $DIR/manual_map_option.rs:95:5
|
LL | / match &mut &Some(String::new()) {
LL | | Some(x) => Some(x.is_empty()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:101:5
+ --> $DIR/manual_map_option.rs:100:5
|
LL | / match Some((0, 1, 2)) {
LL | | Some((x, y, z)) => Some(x + y + z),
| |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:106:5
+ --> $DIR/manual_map_option.rs:105:5
|
LL | / match Some([1, 2, 3]) {
LL | | Some([first, ..]) => Some(first),
| |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:111:5
+ --> $DIR/manual_map_option.rs:110:5
|
LL | / match &Some((String::new(), "test")) {
LL | | Some((x, y)) => Some((y, x)),
| |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:169:5
+ --> $DIR/manual_map_option.rs:168:5
|
LL | / match Some(0) {
LL | | Some(x) => Some(vec![x]),
| |_____^ help: try this: `Some(0).map(|x| vec![x])`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:174:5
+ --> $DIR/manual_map_option.rs:173:5
|
LL | / match option_env!("") {
LL | | Some(x) => Some(String::from(x)),
| |_____^ help: try this: `option_env!("").map(String::from)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:194:12
+ --> $DIR/manual_map_option.rs:193:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
| |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:202:12
+ --> $DIR/manual_map_option.rs:201:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
let a = Ok::<i32, &str>(1);
a.unwrap_or(42);
- // int case, suggestion must surround Result expr with parenthesis
+ // int case, suggestion must surround Result expr with parentheses
(Ok(1) as Result<i32, &str>).unwrap_or(42);
- // method call case, suggestion must not surround Result expr `s.method()` with parenthesis
+ // method call case, suggestion must not surround Result expr `s.method()` with parentheses
struct S {}
impl S {
fn method(self) -> Option<i32> {
Err(_) => 42,
};
- // int case, suggestion must surround Result expr with parenthesis
+ // int case, suggestion must surround Result expr with parentheses
match Ok(1) as Result<i32, &str> {
Ok(i) => i,
Err(_) => 42,
};
- // method call case, suggestion must not surround Result expr `s.method()` with parenthesis
+ // method call case, suggestion must not surround Result expr `s.method()` with parentheses
struct S {}
impl S {
fn method(self) -> Option<i32> {
LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_expr_like_matches_macro.rs:166:20
- |
-LL | let _res = match &val {
- | ____________________^
-LL | | &Some(ref _a) => true,
-LL | | _ => false,
-LL | | };
- | |_________^
- |
- = note: `-D clippy::match-ref-pats` implied by `-D warnings`
-help: try
- |
-LL ~ let _res = match val {
-LL ~ Some(ref _a) => true,
- |
-
error: match expression looks like `matches!` macro
--> $DIR/match_expr_like_matches_macro.rs:178:20
|
LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_expr_like_matches_macro.rs:178:20
- |
-LL | let _res = match &val {
- | ____________________^
-LL | | &Some(ref _a) => true,
-LL | | _ => false,
-LL | | };
- | |_________^
- |
-help: try
- |
-LL ~ let _res = match val {
-LL ~ Some(ref _a) => true,
- |
-
-error: aborting due to 14 previous errors
+error: aborting due to 12 previous errors
const FOO: u64 = 2;
match 42 {
- 0..=10 => println!("0 ... 10"),
- 0..=11 => println!("0 ... 11"),
+ 0..=10 => println!("0..=10"),
+ 0..=11 => println!("0..=11"),
_ => (),
}
match 42 {
- 0..=5 => println!("0 ... 5"),
- 6..=7 => println!("6 ... 7"),
- FOO..=11 => println!("0 ... 11"),
+ 0..=5 => println!("0..=5"),
+ 6..=7 => println!("6..=7"),
+ FOO..=11 => println!("FOO..=11"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..=5 => println!("0 ... 5"),
+ 0..=5 => println!("0..=5"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..=2 => println!("0 ... 2"),
+ 0..=2 => println!("0..=2"),
_ => (),
}
match 42 {
- 0..=10 => println!("0 ... 10"),
- 11..=50 => println!("11 ... 50"),
+ 0..=10 => println!("0..=10"),
+ 11..=50 => println!("11..=50"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..2 => println!("0 .. 2"),
+ 0..2 => println!("0..2"),
_ => (),
}
match 42 {
- 0..10 => println!("0 .. 10"),
- 10..50 => println!("10 .. 50"),
+ 0..10 => println!("0..10"),
+ 10..50 => println!("10..50"),
_ => (),
}
match 42 {
- 0..11 => println!("0 .. 11"),
- 0..=11 => println!("0 ... 11"),
+ 0..11 => println!("0..11"),
+ 0..=11 => println!("0..=11"),
_ => (),
}
match 42 {
- 5..7 => println!("5 .. 7"),
- 0..10 => println!("0 .. 10"),
+ 5..7 => println!("5..7"),
+ 0..10 => println!("0..10"),
_ => (),
}
match 42 {
- 5..10 => println!("5 .. 10"),
- 0..=10 => println!("0 ... 10"),
+ 5..10 => println!("5..10"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
match 42 {
- 0..14 => println!("0 .. 14"),
- 5..10 => println!("5 .. 10"),
+ 0..14 => println!("0..14"),
+ 5..10 => println!("5..10"),
_ => (),
}
match 42 {
- 5..14 => println!("5 .. 14"),
- 0..=10 => println!("0 ... 10"),
+ 5..14 => println!("5..14"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
match 42 {
- 0..7 => println!("0 .. 7"),
- 0..=10 => println!("0 ... 10"),
+ 0..7 => println!("0..7"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
- /*
- // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
match 42 {
- 0.. => println!("0 .. 42"),
- 3.. => println!("3 .. 42"),
+ 3.. => println!("3.."),
+ 0.. => println!("0.."),
_ => (),
}
match 42 {
- ..=23 => println!("0 ... 23"),
- ..26 => println!("0 .. 26"),
+ ..=23 => println!("..=23"),
+ ..26 => println!("..26"),
+ _ => (),
+ }
+
+ // Issue #7829
+ match 0 {
+ -1..=1 => (),
+ -2..=2 => (),
_ => (),
}
- */
if let None = Some(42) {
// nothing
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:13:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
= note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:14:9
|
-LL | 0..=11 => println!("0 ... 11"),
+LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:19:9
|
-LL | 0..=5 => println!("0 ... 5"),
+LL | 0..=5 => println!("0..=5"),
| ^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:21:9
|
-LL | FOO..=11 => println!("0 ... 11"),
+LL | FOO..=11 => println!("FOO..=11"),
| ^^^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:56:9
|
-LL | 0..11 => println!("0 .. 11"),
+LL | 0..11 => println!("0..11"),
| ^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:57:9
|
-LL | 0..=11 => println!("0 ... 11"),
+LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:81:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:80:9
|
-LL | 5..14 => println!("5 .. 14"),
+LL | 5..14 => println!("5..14"),
| ^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:86:9
|
-LL | 0..7 => println!("0 .. 7"),
+LL | 0..7 => println!("0..7"),
| ^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:87:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
-error: aborting due to 5 previous errors
+error: some ranges overlap
+ --> $DIR/match_overlapping_arm.rs:98:9
+ |
+LL | ..=23 => println!("..=23"),
+ | ^^^^^
+ |
+note: overlaps with this
+ --> $DIR/match_overlapping_arm.rs:99:9
+ |
+LL | ..26 => println!("..26"),
+ | ^^^^
+
+error: aborting due to 6 previous errors
#![warn(clippy::match_ref_pats)]
-#![allow(clippy::equatable_if_let)]
+#![allow(clippy::equatable_if_let, clippy::enum_variant_names)]
fn ref_pats() {
{
}
}
+mod issue_7740 {
+ macro_rules! foobar_variant(
+ ($idx:expr) => (FooBar::get($idx).unwrap())
+ );
+
+ enum FooBar {
+ Foo,
+ Bar,
+ FooBar,
+ BarFoo,
+ }
+
+ impl FooBar {
+ fn get(idx: u8) -> Option<&'static Self> {
+ match idx {
+ 0 => Some(&FooBar::Foo),
+ 1 => Some(&FooBar::Bar),
+ 2 => Some(&FooBar::FooBar),
+ 3 => Some(&FooBar::BarFoo),
+ _ => None,
+ }
+ }
+ }
+
+ fn issue_7740() {
+ // Issue #7740
+ match foobar_variant!(0) {
+ &FooBar::Foo => println!("Foo"),
+ &FooBar::Bar => println!("Bar"),
+ &FooBar::FooBar => println!("FooBar"),
+ _ => println!("Wild"),
+ }
+
+ // This shouldn't trigger
+ if let &FooBar::BarFoo = foobar_variant!(3) {
+ println!("BarFoo");
+ } else {
+ println!("Wild");
+ }
+ }
+}
+
fn main() {}
LL ~ None => println!("none"),
|
-error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:18:5
- |
-LL | / match tup {
-LL | | &(v, 1) => println!("{}", v),
-LL | | _ => println!("none"),
-LL | | }
- | |_____^
- |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
- |
-LL ~ match *tup {
-LL ~ (v, 1) => println!("{}", v),
- |
-
error: you don't need to add `&` to both the expression and the patterns
--> $DIR/match_ref_pats.rs:24:5
|
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
-error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:36:5
- |
-LL | / if let &None = a {
-LL | | println!("none");
-LL | | }
- | |_____^
- |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
- |
-LL | if let None = *a {
- | ~~~~ ~~
-
error: redundant pattern matching, consider using `is_none()`
--> $DIR/match_ref_pats.rs:41:12
|
LL | if let &None = &b {
| -------^^^^^----- help: try this: `if b.is_none()`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_ref_pats.rs:41:5
- |
-LL | / if let &None = &b {
-LL | | println!("none");
-LL | | }
- | |_____^
- |
-help: try
- |
-LL | if let None = b {
- | ~~~~ ~
-
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:68:9
+ --> $DIR/match_ref_pats.rs:101:9
|
-LL | / match foo_variant!(0) {
-LL | | &Foo::A => println!("A"),
+LL | / match foobar_variant!(0) {
+LL | | &FooBar::Foo => println!("Foo"),
+LL | | &FooBar::Bar => println!("Bar"),
+LL | | &FooBar::FooBar => println!("FooBar"),
LL | | _ => println!("Wild"),
LL | | }
| |_________^
|
help: instead of prefixing all patterns with `&`, you can dereference the expression
|
-LL ~ match *foo_variant!(0) {
-LL ~ Foo::A => println!("A"),
+LL ~ match *foobar_variant!(0) {
+LL ~ FooBar::Foo => println!("Foo"),
+LL ~ FooBar::Bar => println!("Bar"),
+LL ~ FooBar::FooBar => println!("FooBar"),
|
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
--- /dev/null
+#![warn(clippy::match_str_case_mismatch)]
+
+// Valid
+
+fn as_str_match() {
+ let var = "BAR";
+
+ match var.to_ascii_lowercase().as_str() {
+ "foo" => {},
+ "bar" => {},
+ _ => {},
+ }
+}
+
+fn non_alphabetic() {
+ let var = "~!@#$%^&*()-_=+FOO";
+
+ match var.to_ascii_lowercase().as_str() {
+ "1234567890" => {},
+ "~!@#$%^&*()-_=+foo" => {},
+ "\n\r\t\x7F" => {},
+ _ => {},
+ }
+}
+
+fn unicode_cased() {
+ let var = "ВОДЫ";
+
+ match var.to_lowercase().as_str() {
+ "水" => {},
+ "νερό" => {},
+ "воды" => {},
+ "물" => {},
+ _ => {},
+ }
+}
+
+fn titlecase() {
+ let var = "BarDz";
+
+ match var.to_lowercase().as_str() {
+ "foolj" => {},
+ "bardz" => {},
+ _ => {},
+ }
+}
+
+fn no_case_equivalent() {
+ let var = "barʁ";
+
+ match var.to_uppercase().as_str() {
+ "FOOɕ" => {},
+ "BARʁ" => {},
+ _ => {},
+ }
+}
+
+fn addrof_unary_match() {
+ let var = "BAR";
+
+ match &*var.to_ascii_lowercase() {
+ "foo" => {},
+ "bar" => {},
+ _ => {},
+ }
+}
+
+fn alternating_chain() {
+ let var = "BAR";
+
+ match &*var
+ .to_ascii_lowercase()
+ .to_uppercase()
+ .to_lowercase()
+ .to_ascii_uppercase()
+ {
+ "FOO" => {},
+ "BAR" => {},
+ _ => {},
+ }
+}
+
+fn unrelated_method() {
+ struct Item {
+ a: String,
+ }
+
+ impl Item {
+ #[allow(clippy::wrong_self_convention)]
+ fn to_lowercase(self) -> String {
+ self.a
+ }
+ }
+
+ let item = Item { a: String::from("BAR") };
+
+ match &*item.to_lowercase() {
+ "FOO" => {},
+ "BAR" => {},
+ _ => {},
+ }
+}
+
+// Invalid
+
+fn as_str_match_mismatch() {
+ let var = "BAR";
+
+ match var.to_ascii_lowercase().as_str() {
+ "foo" => {},
+ "Bar" => {},
+ _ => {},
+ }
+}
+
+fn non_alphabetic_mismatch() {
+ let var = "~!@#$%^&*()-_=+FOO";
+
+ match var.to_ascii_lowercase().as_str() {
+ "1234567890" => {},
+ "~!@#$%^&*()-_=+Foo" => {},
+ "\n\r\t\x7F" => {},
+ _ => {},
+ }
+}
+
+fn unicode_cased_mismatch() {
+ let var = "ВОДЫ";
+
+ match var.to_lowercase().as_str() {
+ "水" => {},
+ "νερό" => {},
+ "Воды" => {},
+ "물" => {},
+ _ => {},
+ }
+}
+
+fn titlecase_mismatch() {
+ let var = "BarDz";
+
+ match var.to_lowercase().as_str() {
+ "foolj" => {},
+ "barDz" => {},
+ _ => {},
+ }
+}
+
+fn no_case_equivalent_mismatch() {
+ let var = "barʁ";
+
+ match var.to_uppercase().as_str() {
+ "FOOɕ" => {},
+ "bARʁ" => {},
+ _ => {},
+ }
+}
+
+fn addrof_unary_match_mismatch() {
+ let var = "BAR";
+
+ match &*var.to_ascii_lowercase() {
+ "foo" => {},
+ "Bar" => {},
+ _ => {},
+ }
+}
+
+fn alternating_chain_mismatch() {
+ let var = "BAR";
+
+ match &*var
+ .to_ascii_lowercase()
+ .to_uppercase()
+ .to_lowercase()
+ .to_ascii_uppercase()
+ {
+ "FOO" => {},
+ "bAR" => {},
+ _ => {},
+ }
+}
+
+fn main() {}
--- /dev/null
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:111:9
+ |
+LL | "Bar" => {},
+ | ^^^^^
+ |
+ = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings`
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "bar" => {},
+ | ~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:121:9
+ |
+LL | "~!@#$%^&*()-_=+Foo" => {},
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "~!@#$%^&*()-_=+foo" => {},
+ | ~~~~~~~~~~~~~~~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:133:9
+ |
+LL | "Воды" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_lowercase`
+ |
+LL | "воды" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:144:9
+ |
+LL | "barDz" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_lowercase`
+ |
+LL | "bardz" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:154:9
+ |
+LL | "bARʁ" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_uppercase`
+ |
+LL | "BARʁ" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:164:9
+ |
+LL | "Bar" => {},
+ | ^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "bar" => {},
+ | ~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:179:9
+ |
+LL | "bAR" => {},
+ | ^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_uppercase`
+ |
+LL | "BAR" => {},
+ | ~~~~~
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:14:9
+ |
+LL | Err(_) => panic!("err"),
+ | ^^^^^^
+ |
+ = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:20:9
+ |
+LL | Err(_) => panic!(),
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:26:9
+ |
+LL | Err(_) => {
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:34:9
+ |
+LL | Err(_e) => panic!(),
+ | ^^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:14:9
+ |
+LL | Err(_) => panic!("err"),
+ | ^^^^^^
+ |
+ = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:20:9
+ |
+LL | Err(_) => panic!(),
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:26:9
+ |
+LL | Err(_) => {
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:34:9
+ |
+LL | Err(_e) => panic!(),
+ | ^^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
#![feature(exclusive_range_pattern)]
#![allow(clippy::match_same_arms)]
#![warn(clippy::match_wild_err_arm)]
+++ /dev/null
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:11:9
- |
-LL | Err(_) => panic!("err"),
- | ^^^^^^
- |
- = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:17:9
- |
-LL | Err(_) => panic!(),
- | ^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:23:9
- |
-LL | Err(_) => {
- | ^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_e)` matches all errors
- --> $DIR/match_wild_err_arm.rs:31:9
- |
-LL | Err(_e) => panic!(),
- | ^^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: aborting due to 4 previous errors
-
// aux-build:option_helpers.rs
-// edition:2018
#![warn(clippy::all, clippy::pedantic)]
#![allow(
error: methods called `new` usually return `Self`
- --> $DIR/methods.rs:105:5
+ --> $DIR/methods.rs:104:5
|
LL | / fn new() -> i32 {
LL | | 0
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
- --> $DIR/methods.rs:126:13
+ --> $DIR/methods.rs:125:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
// injected intrinsics by the compiler.
#![allow(dead_code)]
#![feature(global_asm)]
-
//! Some garbage docs for the crate here
#![doc = "More garbage"]
}
/// dox
pub mod public_interface {
- pub use internal_impl::documented as foo;
- pub use internal_impl::globbed::*;
- pub use internal_impl::undocumented1 as bar;
- pub use internal_impl::{documented, undocumented2};
+ pub use crate::internal_impl::documented as foo;
+ pub use crate::internal_impl::globbed::*;
+ pub use crate::internal_impl::undocumented1 as bar;
+ pub use crate::internal_impl::{documented, undocumented2};
}
fn main() {}
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:10:1
+ --> $DIR/missing-doc.rs:9:1
|
LL | type Typedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:11:1
+ --> $DIR/missing-doc.rs:10:1
|
LL | pub type PubTypedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:13:1
+ --> $DIR/missing-doc.rs:12:1
|
LL | mod module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:14:1
+ --> $DIR/missing-doc.rs:13:1
|
LL | pub mod pub_module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:18:1
+ --> $DIR/missing-doc.rs:17:1
|
LL | pub fn foo2() {}
| ^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:19:1
+ --> $DIR/missing-doc.rs:18:1
|
LL | fn foo3() {}
| ^^^^^^^^^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:33:1
+ --> $DIR/missing-doc.rs:32:1
|
LL | / enum Baz {
LL | | BazA { a: isize, b: isize },
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:34:5
+ --> $DIR/missing-doc.rs:33:5
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:12
+ --> $DIR/missing-doc.rs:33:12
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:22
+ --> $DIR/missing-doc.rs:33:22
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:35:5
+ --> $DIR/missing-doc.rs:34:5
|
LL | BarB,
| ^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:38:1
+ --> $DIR/missing-doc.rs:37:1
|
LL | / pub enum PubBaz {
LL | | PubBazA { a: isize },
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:39:5
+ --> $DIR/missing-doc.rs:38:5
|
LL | PubBazA { a: isize },
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:39:15
+ --> $DIR/missing-doc.rs:38:15
|
LL | PubBazA { a: isize },
| ^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:59:1
+ --> $DIR/missing-doc.rs:58:1
|
LL | const FOO: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:66:1
+ --> $DIR/missing-doc.rs:65:1
|
LL | pub const FOO4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:68:1
+ --> $DIR/missing-doc.rs:67:1
|
LL | static BAR: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:75:1
+ --> $DIR/missing-doc.rs:74:1
|
LL | pub static BAR4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:77:1
+ --> $DIR/missing-doc.rs:76:1
|
LL | / mod internal_impl {
LL | | /// dox
| |_^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:80:5
+ --> $DIR/missing-doc.rs:79:5
|
LL | pub fn undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:81:5
+ --> $DIR/missing-doc.rs:80:5
|
LL | pub fn undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:82:5
+ --> $DIR/missing-doc.rs:81:5
|
LL | fn undocumented3() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:87:9
+ --> $DIR/missing-doc.rs:86:9
|
LL | pub fn also_undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:88:9
+ --> $DIR/missing-doc.rs:87:9
|
LL | fn also_undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::missing_panics_doc)]
#![allow(clippy::option_map_unit_fn)]
-
fn main() {}
/// This needs to be documented
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:7:1
+ --> $DIR/missing_panics_doc.rs:6:1
|
LL | / pub fn unwrap() {
LL | | let result = Err("Hi");
|
= note: `-D clippy::missing-panics-doc` implied by `-D warnings`
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:9:5
+ --> $DIR/missing_panics_doc.rs:8:5
|
LL | result.unwrap()
| ^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:13:1
+ --> $DIR/missing_panics_doc.rs:12:1
|
LL | / pub fn panic() {
LL | | panic!("This function panics")
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:14:5
+ --> $DIR/missing_panics_doc.rs:13:5
|
LL | panic!("This function panics")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:18:1
+ --> $DIR/missing_panics_doc.rs:17:1
|
LL | / pub fn todo() {
LL | | todo!()
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:19:5
+ --> $DIR/missing_panics_doc.rs:18:5
|
LL | todo!()
| ^^^^^^^
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:23:1
+ --> $DIR/missing_panics_doc.rs:22:1
|
LL | / pub fn inner_body(opt: Option<u32>) {
LL | | opt.map(|x| {
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:26:13
+ --> $DIR/missing_panics_doc.rs:25:13
|
LL | panic!()
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:32:1
+ --> $DIR/missing_panics_doc.rs:31:1
|
LL | / pub fn unreachable_and_panic() {
LL | | if true { unreachable!() } else { panic!() }
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:33:39
+ --> $DIR/missing_panics_doc.rs:32:39
|
LL | if true { unreachable!() } else { panic!() }
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:37:1
+ --> $DIR/missing_panics_doc.rs:36:1
|
LL | / pub fn assert_eq() {
LL | | let x = 0;
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:39:5
+ --> $DIR/missing_panics_doc.rs:38:5
|
LL | assert_eq!(x, 0);
| ^^^^^^^^^^^^^^^^
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:43:1
+ --> $DIR/missing_panics_doc.rs:42:1
|
LL | / pub fn assert_ne() {
LL | | let x = 0;
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:45:5
+ --> $DIR/missing_panics_doc.rs:44:5
|
LL | assert_ne!(x, 0);
| ^^^^^^^^^^^^^^^^
+// aux-build:macro_rules.rs
+
#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::mut_mut)]
+#[macro_use]
+extern crate macro_rules;
+
fn fun(x: &mut &mut u32) -> bool {
**x > 0
}
println!(":{}", arg);
}
}
+
+fn issue6922() {
+ // do not lint from an external macro
+ mut_mut!();
+}
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:4:11
+ --> $DIR/mut_mut.rs:9:11
|
LL | fn fun(x: &mut &mut u32) -> bool {
| ^^^^^^^^^^^^^
= note: `-D clippy::mut-mut` implied by `-D warnings`
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:20:17
+ --> $DIR/mut_mut.rs:25:17
|
LL | let mut x = &mut &mut 1u32;
| ^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:14:9
+ --> $DIR/mut_mut.rs:19:9
|
LL | &mut $p
| ^^^^^^^
= note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this expression mutably borrows a mutable reference. Consider reborrowing
- --> $DIR/mut_mut.rs:22:21
+ --> $DIR/mut_mut.rs:27:21
|
LL | let mut y = &mut x;
| ^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:26:32
+ --> $DIR/mut_mut.rs:31:32
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:26:16
+ --> $DIR/mut_mut.rs:31:16
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:37
+ --> $DIR/mut_mut.rs:36:37
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:16
+ --> $DIR/mut_mut.rs:36:16
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:21
+ --> $DIR/mut_mut.rs:36:21
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^
-// edition:2018
// FIXME: run-rustfix waiting on multi-span suggestions
#![warn(clippy::needless_borrow)]
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:60:14
+ --> $DIR/needless_borrow_pat.rs:59:14
|
LL | Some(ref x) => x,
| ^^^^^ help: try this: `x`
= note: `-D clippy::needless-borrow` implied by `-D warnings`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:66:14
+ --> $DIR/needless_borrow_pat.rs:65:14
|
LL | Some(ref x) => *x,
| ^^^^^
| ~ ~
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:72:14
+ --> $DIR/needless_borrow_pat.rs:71:14
|
LL | Some(ref x) => {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:82:14
+ --> $DIR/needless_borrow_pat.rs:81:14
|
LL | Some(ref x) => m1!(x),
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:87:15
+ --> $DIR/needless_borrow_pat.rs:86:15
|
LL | let _ = |&ref x: &&String| {
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:92:10
+ --> $DIR/needless_borrow_pat.rs:91:10
|
LL | let (ref y,) = (&x,);
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:102:14
+ --> $DIR/needless_borrow_pat.rs:101:14
|
LL | Some(ref x) => x.0,
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:112:14
+ --> $DIR/needless_borrow_pat.rs:111:14
|
LL | E::A(ref x) | E::B(ref x) => *x,
| ^^^^^ ^^^^^
| ~ ~ ~
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:118:21
+ --> $DIR/needless_borrow_pat.rs:117:21
|
LL | if let Some(ref x) = Some(&String::new());
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:126:12
+ --> $DIR/needless_borrow_pat.rs:125:12
|
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:133:11
+ --> $DIR/needless_borrow_pat.rs:132:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:141:11
+ --> $DIR/needless_borrow_pat.rs:140:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
x
}
+// No error; multiple input refs
+async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
+ args.get(0).cloned()
+}
+
// No error; static involved.
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
x
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:45:1
+ --> $DIR/needless_lifetimes.rs:50:1
|
LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:50:1
+ --> $DIR/needless_lifetimes.rs:55:1
|
LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:62:1
+ --> $DIR/needless_lifetimes.rs:67:1
|
LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:86:1
+ --> $DIR/needless_lifetimes.rs:91:1
|
LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:116:5
+ --> $DIR/needless_lifetimes.rs:121:5
|
LL | fn self_and_out<'s>(&'s self) -> &'s u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:125:5
+ --> $DIR/needless_lifetimes.rs:130:5
|
LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:144:1
+ --> $DIR/needless_lifetimes.rs:149:1
|
LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:174:1
+ --> $DIR/needless_lifetimes.rs:179:1
|
LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:180:1
+ --> $DIR/needless_lifetimes.rs:185:1
|
LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:199:1
+ --> $DIR/needless_lifetimes.rs:204:1
|
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:207:1
+ --> $DIR/needless_lifetimes.rs:212:1
|
LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:243:1
+ --> $DIR/needless_lifetimes.rs:248:1
|
LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:250:9
+ --> $DIR/needless_lifetimes.rs:255:9
|
LL | fn needless_lt<'a>(x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:254:9
+ --> $DIR/needless_lifetimes.rs:259:9
|
LL | fn needless_lt<'a>(_x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:267:9
+ --> $DIR/needless_lifetimes.rs:272:9
|
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:296:5
+ --> $DIR/needless_lifetimes.rs:301:5
|
LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:299:5
+ --> $DIR/needless_lifetimes.rs:304:5
|
LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:308:5
+ --> $DIR/needless_lifetimes.rs:313:5
|
LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:320:5
+ --> $DIR/needless_lifetimes.rs:325:5
|
LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:335:5
+ --> $DIR/needless_lifetimes.rs:340:5
|
LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:348:5
+ --> $DIR/needless_lifetimes.rs:353:5
|
LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:351:5
+ --> $DIR/needless_lifetimes.rs:356:5
|
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// run-rustfix
-// edition:2018
#![feature(let_else)]
#![allow(unused)]
// run-rustfix
-// edition:2018
#![feature(let_else)]
#![allow(unused)]
error: unneeded `return` statement
- --> $DIR/needless_return.rs:25:5
+ --> $DIR/needless_return.rs:24:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
= note: `-D clippy::needless-return` implied by `-D warnings`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:29:5
+ --> $DIR/needless_return.rs:28:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:34:9
+ --> $DIR/needless_return.rs:33:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:36:9
+ --> $DIR/needless_return.rs:35:9
|
LL | return false;
| ^^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:42:17
+ --> $DIR/needless_return.rs:41:17
|
LL | true => return false,
| ^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:44:13
+ --> $DIR/needless_return.rs:43:13
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:51:9
+ --> $DIR/needless_return.rs:50:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:53:16
+ --> $DIR/needless_return.rs:52:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:61:5
+ --> $DIR/needless_return.rs:60:5
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:66:9
+ --> $DIR/needless_return.rs:65:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:68:9
+ --> $DIR/needless_return.rs:67:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:75:14
+ --> $DIR/needless_return.rs:74:14
|
LL | _ => return,
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:90:9
+ --> $DIR/needless_return.rs:89:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:92:9
+ --> $DIR/needless_return.rs:91:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:113:32
+ --> $DIR/needless_return.rs:112:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:118:13
+ --> $DIR/needless_return.rs:117:13
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:120:20
+ --> $DIR/needless_return.rs:119:20
|
LL | let _ = || return;
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:126:32
+ --> $DIR/needless_return.rs:125:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^ help: remove `return`: `Foo`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:135:5
+ --> $DIR/needless_return.rs:134:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:139:5
+ --> $DIR/needless_return.rs:138:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:144:9
+ --> $DIR/needless_return.rs:143:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:146:9
+ --> $DIR/needless_return.rs:145:9
|
LL | return false;
| ^^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:152:17
+ --> $DIR/needless_return.rs:151:17
|
LL | true => return false,
| ^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:154:13
+ --> $DIR/needless_return.rs:153:13
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:161:9
+ --> $DIR/needless_return.rs:160:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:163:16
+ --> $DIR/needless_return.rs:162:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:171:5
+ --> $DIR/needless_return.rs:170:5
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:176:9
+ --> $DIR/needless_return.rs:175:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:178:9
+ --> $DIR/needless_return.rs:177:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:185:14
+ --> $DIR/needless_return.rs:184:14
|
LL | _ => return,
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:200:9
+ --> $DIR/needless_return.rs:199:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:202:9
+ --> $DIR/needless_return.rs:201:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
#![feature(box_syntax)]
-#![warn(clippy::no_effect)]
+#![warn(clippy::no_effect_underscore_binding)]
#![allow(dead_code)]
#![allow(path_statements)]
#![allow(clippy::deref_addrof)]
|| x += 5;
let s: String = "foo".into();
FooString { s: s };
+ let _unused = 1;
+ let _penguin = || println!("Some helpful closure");
+ let _duck = Struct { field: 0 };
+ let _cat = [2, 4, 6, 8][2];
#[allow(clippy::no_effect)]
0;
// Do not warn
get_number();
unsafe { unsafe_fn() };
+ let _used = get_struct();
+ let _x = vec![1];
DropUnit;
DropStruct { field: 0 };
DropTuple(0);
LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 26 previous errors
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:93:5
+ |
+LL | let _unused = 1;
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:94:5
+ |
+LL | let _penguin = || println!("Some helpful closure");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:95:5
+ |
+LL | let _duck = Struct { field: 0 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:96:5
+ |
+LL | let _cat = [2, 4, 6, 8][2];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 30 previous errors
impl MaybeInst {
fn fill(&mut self) {
let filled = match *self {
- MaybeInst::Split1(goto1) => panic!(1),
- MaybeInst::Split2(goto2) => panic!(2),
+ MaybeInst::Split1(goto1) => panic!("1"),
+ MaybeInst::Split2(goto2) => panic!("2"),
_ => unimplemented!(),
};
unimplemented!()
|
help: try
|
-LL | let _ = a == b && c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b || c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b && c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:28:13
|
help: try
|
-LL | let _ = a == b || c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b && c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b || c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:29:13
|
help: try
|
-LL | let _ = a == b && c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b || c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b && c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:30:13
|
help: try
|
-LL | let _ = a != b || c != d;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a == b && c == d);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a != b || c != d;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:31:13
|
help: try
|
-LL | let _ = a != b && c != d;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a == b || c == d);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a != b && c != d;
+ | ~~~~~~~~~~~~~~~~
error: aborting due to 12 previous errors
-// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
fn bad1(string: Option<&str>) -> (bool, &str) {
string.map_or((false, "hello"), |x| (true, x))
-// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
fn bad1(string: Option<&str>) -> (bool, &str) {
if let Some(x) = string {
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:8:5
+ --> $DIR/option_if_let_else.rs:6:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:26:13
+ --> $DIR/option_if_let_else.rs:24:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:27:13
+ --> $DIR/option_if_let_else.rs:25:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:28:13
+ --> $DIR/option_if_let_else.rs:26:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:34:13
+ --> $DIR/option_if_let_else.rs:32:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:35:13
+ --> $DIR/option_if_let_else.rs:33:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:41:13
+ --> $DIR/option_if_let_else.rs:39:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:50:5
+ --> $DIR/option_if_let_else.rs:48:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:63:13
+ --> $DIR/option_if_let_else.rs:61:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
| |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:72:13
+ --> $DIR/option_if_let_else.rs:70:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:101:13
+ --> $DIR/option_if_let_else.rs:99:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:110:13
+ --> $DIR/option_if_let_else.rs:108:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:138:13
+ --> $DIR/option_if_let_else.rs:136:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:142:13
+ --> $DIR/option_if_let_else.rs:140:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
#![warn(clippy::panic_in_result_fn)]
#![allow(clippy::unnecessary_wraps)]
-
struct A;
impl A {
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:7:5
+ --> $DIR/panic_in_result_fn.rs:6:5
|
LL | / fn result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
= note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:9:9
+ --> $DIR/panic_in_result_fn.rs:8:9
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:12:5
+ --> $DIR/panic_in_result_fn.rs:11:5
|
LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:14:9
+ --> $DIR/panic_in_result_fn.rs:13:9
|
LL | unimplemented!();
| ^^^^^^^^^^^^^^^^
= note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:17:5
+ --> $DIR/panic_in_result_fn.rs:16:5
|
LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:19:9
+ --> $DIR/panic_in_result_fn.rs:18:9
|
LL | unreachable!();
| ^^^^^^^^^^^^^^
= note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:22:5
+ --> $DIR/panic_in_result_fn.rs:21:5
|
LL | / fn result_with_todo() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:24:9
+ --> $DIR/panic_in_result_fn.rs:23:9
|
LL | todo!("Finish this");
| ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:53:1
+ --> $DIR/panic_in_result_fn.rs:52:1
|
LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:55:5
+ --> $DIR/panic_in_result_fn.rs:54:5
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:68:1
+ --> $DIR/panic_in_result_fn.rs:67:1
|
LL | / fn main() -> Result<(), String> {
LL | | todo!("finish main method");
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:69:5
+ --> $DIR/panic_in_result_fn.rs:68:5
|
LL | todo!("finish main method");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#![allow(
- unused,
- clippy::many_single_char_names,
- clippy::redundant_clone,
- clippy::if_then_panic
-)]
+#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
#![warn(clippy::ptr_arg)]
use std::borrow::Cow;
let _ = str.clone().clone();
}
}
+
+// No error for types behind an alias (#7699)
+type A = Vec<u8>;
+fn aliased(a: &A) {}
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:12:14
+ --> $DIR/ptr_arg.rs:7:14
|
LL | fn do_vec(x: &Vec<i64>) {
| ^^^^^^^^^ help: change this to: `&[i64]`
= note: `-D clippy::ptr-arg` implied by `-D warnings`
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:21:14
+ --> $DIR/ptr_arg.rs:16:14
|
LL | fn do_str(x: &String) {
| ^^^^^^^ help: change this to: `&str`
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:30:15
+ --> $DIR/ptr_arg.rs:25:15
|
LL | fn do_path(x: &PathBuf) {
| ^^^^^^^^ help: change this to: `&Path`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:43:18
+ --> $DIR/ptr_arg.rs:38:18
|
LL | fn do_vec(x: &Vec<i64>);
| ^^^^^^^^^ help: change this to: `&[i64]`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:56:14
+ --> $DIR/ptr_arg.rs:51:14
|
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
| ^^^^^^^^
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:65:18
+ --> $DIR/ptr_arg.rs:60:18
|
LL | fn str_cloned(x: &String) -> String {
| ^^^^^^^
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:73:19
+ --> $DIR/ptr_arg.rs:68:19
|
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
| ^^^^^^^^
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:81:44
+ --> $DIR/ptr_arg.rs:76:44
|
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
| ^^^^^^^
| ~
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:95:25
+ --> $DIR/ptr_arg.rs:90:25
|
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
| ^^^^^^^^^^^ help: change this to: `&[i32]`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:148:21
+ --> $DIR/ptr_arg.rs:143:21
|
LL | fn foo_vec(vec: &Vec<u8>) {
| ^^^^^^^^
| ~~~~~~~~~~~~~~
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:153:23
+ --> $DIR/ptr_arg.rs:148:23
|
LL | fn foo_path(path: &PathBuf) {
| ^^^^^^^^
| ~~~~~~~~~~~~~~~~~~
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:158:21
+ --> $DIR/ptr_arg.rs:153:21
|
LL | fn foo_str(str: &PathBuf) {
| ^^^^^^^^
Some(0)
}
+fn func_returning_result() -> Result<i32, i32> {
+ Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
+ let _ = x?;
+
+ x?;
+
+ // No warning
+ let y = if let Ok(x) = x {
+ x
+ } else {
+ return Err(0);
+ };
+
+ // issue #7859
+ // no warning
+ let _ = if let Ok(x) = func_returning_result() {
+ x
+ } else {
+ return Err(0);
+ };
+
+ // no warning
+ if func_returning_result().is_err() {
+ return func_returning_result();
+ }
+
+ Ok(y)
+}
+
fn main() {
some_func(Some(42));
some_func(None);
returns_something_similar_to_option(so);
func();
+
+ let _ = result_func(Ok(42));
}
Some(0)
}
+fn func_returning_result() -> Result<i32, i32> {
+ Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
+ let _ = if let Ok(x) = x { x } else { return x };
+
+ if x.is_err() {
+ return x;
+ }
+
+ // No warning
+ let y = if let Ok(x) = x {
+ x
+ } else {
+ return Err(0);
+ };
+
+ // issue #7859
+ // no warning
+ let _ = if let Ok(x) = func_returning_result() {
+ x
+ } else {
+ return Err(0);
+ };
+
+ // no warning
+ if func_returning_result().is_err() {
+ return func_returning_result();
+ }
+
+ Ok(y)
+}
+
fn main() {
some_func(Some(42));
some_func(None);
returns_something_similar_to_option(so);
func();
+
+ let _ = result_func(Ok(42));
}
LL | | }
| |_____^ help: replace it with: `f()?;`
-error: aborting due to 11 previous errors
+error: this if-let-else may be rewritten with the `?` operator
+ --> $DIR/question_mark.rs:142:13
+ |
+LL | let _ = if let Ok(x) = x { x } else { return x };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
+
+error: this block may be rewritten with the `?` operator
+ --> $DIR/question_mark.rs:144:5
+ |
+LL | / if x.is_err() {
+LL | | return x;
+LL | | }
+ | |_____^ help: replace it with: `x?;`
+
+error: aborting due to 13 previous errors
fn foo<F: Fn()>(_: &Alpha, _: F) {}
let x = Alpha;
// ok, data is moved while the clone is in use.
- foo(&x.clone(), move || {
+ foo(&x, move || {
let _ = x;
});
LL | let y = x.clone().join("matthias");
| ^^^^^^^^^
-error: aborting due to 14 previous errors
+error: redundant clone
+ --> $DIR/redundant_clone.rs:199:11
+ |
+LL | foo(&x.clone(), move || {
+ | ^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/redundant_clone.rs:199:10
+ |
+LL | foo(&x.clone(), move || {
+ | ^
+
+error: aborting due to 15 previous errors
-// edition:2018
// FIXME: run-rustfix waiting on multi-span suggestions
#![warn(clippy::ref_binding_to_reference)]
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:31:14
+ --> $DIR/ref_binding_to_reference.rs:30:14
|
LL | Some(ref x) => x,
| ^^^^^
| ~ ~~
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:37:14
+ --> $DIR/ref_binding_to_reference.rs:36:14
|
LL | Some(ref x) => {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:47:14
+ --> $DIR/ref_binding_to_reference.rs:46:14
|
LL | Some(ref x) => m2!(x),
| ^^^^^
| ~ ~~
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:52:15
+ --> $DIR/ref_binding_to_reference.rs:51:15
|
LL | let _ = |&ref x: &&String| {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:58:12
+ --> $DIR/ref_binding_to_reference.rs:57:12
|
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:65:11
+ --> $DIR/ref_binding_to_reference.rs:64:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:73:11
+ --> $DIR/ref_binding_to_reference.rs:72:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::module_name_repetitions)]
+#![warn(clippy::new_without_default)]
+#![warn(clippy::redundant_static_lifetimes)]
#![warn(clippy::cognitive_complexity)]
+#![warn(clippy::bind_instead_of_map)]
+#![warn(clippy::box_collection)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::useless_conversion)]
+#![warn(clippy::invisible_characters)]
+#![warn(clippy::single_char_add_str)]
+#![warn(clippy::match_result_ok)]
+// uplifted lints
+#![warn(invalid_value)]
+#![warn(array_into_iter)]
+#![warn(unused_labels)]
+#![warn(drop_bounds)]
+#![warn(temporary_cstring_as_ptr)]
+#![warn(non_fmt_panics)]
+#![warn(unknown_lints)]
+#![warn(invalid_atomic_ordering)]
#![warn(enum_intrinsics_non_enums)]
-#[warn(clippy::module_name_repetitions)]
fn main() {}
-
-#[warn(clippy::new_without_default)]
-struct Foo;
-
-#[warn(clippy::redundant_static_lifetimes)]
-fn foo() {}
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::stutter)]
+#![warn(clippy::new_without_default_derive)]
+#![warn(clippy::const_static_lifetime)]
#![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::option_and_then_some)]
+#![warn(clippy::box_vec)]
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![warn(clippy::option_map_unwrap_or)]
+#![warn(clippy::option_map_unwrap_or_else)]
+#![warn(clippy::result_map_unwrap_or_else)]
+#![warn(clippy::option_unwrap_used)]
+#![warn(clippy::result_unwrap_used)]
+#![warn(clippy::option_expect_used)]
+#![warn(clippy::result_expect_used)]
+#![warn(clippy::for_loop_over_option)]
+#![warn(clippy::for_loop_over_result)]
+#![warn(clippy::identity_conversion)]
+#![warn(clippy::zero_width_space)]
+#![warn(clippy::single_char_push_str)]
+#![warn(clippy::if_let_some_result)]
+// uplifted lints
+#![warn(clippy::invalid_ref)]
+#![warn(clippy::into_iter_on_array)]
+#![warn(clippy::unused_label)]
+#![warn(clippy::drop_bounds)]
+#![warn(clippy::temporary_cstring_as_ptr)]
+#![warn(clippy::panic_params)]
+#![warn(clippy::unknown_clippy_lints)]
+#![warn(clippy::invalid_atomic_ordering)]
#![warn(clippy::mem_discriminant_non_enum)]
-#[warn(clippy::stutter)]
fn main() {}
-
-#[warn(clippy::new_without_default_derive)]
-struct Foo;
-
-#[warn(clippy::const_static_lifetime)]
-fn foo() {}
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+ --> $DIR/rename.rs:31:9
+ |
+LL | #![warn(clippy::stutter)]
+ | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+ |
+ = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+ --> $DIR/rename.rs:32:9
+ |
+LL | #![warn(clippy::new_without_default_derive)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+ --> $DIR/rename.rs:33:9
+ |
+LL | #![warn(clippy::const_static_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> $DIR/rename.rs:10:9
+ --> $DIR/rename.rs:34:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
+ --> $DIR/rename.rs:35:9
|
- = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+LL | #![warn(clippy::option_and_then_some)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:11:9
+error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
+ --> $DIR/rename.rs:36:9
|
-LL | #![warn(clippy::mem_discriminant_non_enum)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::box_vec)]
+ | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:13:8
+error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
+ --> $DIR/rename.rs:37:9
|
-LL | #[warn(clippy::stutter)]
- | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::block_in_if_condition_expr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:16:8
+error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
+ --> $DIR/rename.rs:38:9
|
-LL | #[warn(clippy::new_without_default_derive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::block_in_if_condition_stmt)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:19:8
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:39:9
+ |
+LL | #![warn(clippy::option_map_unwrap_or)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:40:9
+ |
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:41:9
+ |
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+ --> $DIR/rename.rs:42:9
+ |
+LL | #![warn(clippy::option_unwrap_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+ --> $DIR/rename.rs:43:9
+ |
+LL | #![warn(clippy::result_unwrap_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
+ --> $DIR/rename.rs:44:9
+ |
+LL | #![warn(clippy::option_expect_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+ --> $DIR/rename.rs:45:9
+ |
+LL | #![warn(clippy::result_expect_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
+ --> $DIR/rename.rs:46:9
+ |
+LL | #![warn(clippy::for_loop_over_option)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
+ --> $DIR/rename.rs:47:9
+ |
+LL | #![warn(clippy::for_loop_over_result)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+ --> $DIR/rename.rs:48:9
+ |
+LL | #![warn(clippy::identity_conversion)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+ --> $DIR/rename.rs:49:9
+ |
+LL | #![warn(clippy::zero_width_space)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+ --> $DIR/rename.rs:50:9
+ |
+LL | #![warn(clippy::single_char_push_str)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+ --> $DIR/rename.rs:51:9
+ |
+LL | #![warn(clippy::if_let_some_result)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
+ --> $DIR/rename.rs:53:9
+ |
+LL | #![warn(clippy::invalid_ref)]
+ | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+ --> $DIR/rename.rs:54:9
+ |
+LL | #![warn(clippy::into_iter_on_array)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
+ --> $DIR/rename.rs:55:9
+ |
+LL | #![warn(clippy::unused_label)]
+ | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+ --> $DIR/rename.rs:56:9
+ |
+LL | #![warn(clippy::drop_bounds)]
+ | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+ --> $DIR/rename.rs:57:9
+ |
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+ --> $DIR/rename.rs:58:9
+ |
+LL | #![warn(clippy::panic_params)]
+ | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+
+error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
+ --> $DIR/rename.rs:59:9
+ |
+LL | #![warn(clippy::unknown_clippy_lints)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+ --> $DIR/rename.rs:60:9
+ |
+LL | #![warn(clippy::invalid_atomic_ordering)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+ --> $DIR/rename.rs:61:9
|
-LL | #[warn(clippy::const_static_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
-error: aborting due to 5 previous errors
+error: aborting due to 30 previous errors
let mut s = MaybeUninit::<String>::uninit();
let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
}
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+ macro_rules! repro {
+ () => {
+ while false {
+ }
+ };
+ }
+ repro!();
+}
let x = foo(x);
let x = || x;
let x = Some(1).map(|_| x)?;
+ let y = 1;
+ let y = match y {
+ 1 => 2,
+ _ => 3,
+ };
None
}
LL | let x = &mut x;
| ^
-error: `x` is shadowed by `x.0` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:13:9
|
LL | let x = x.0;
LL | let x = ([[0]], ());
| ^
-error: `x` is shadowed by `x[0]` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:14:9
|
LL | let x = x[0];
LL | let x = x.0;
| ^
-error: `x` is shadowed by `x` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:15:10
|
LL | let [x] = x;
LL | let x = x[0];
| ^
-error: `x` is shadowed by `Some(x)` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:16:9
|
LL | let x = Some(x);
LL | let [x] = x;
| ^
-error: `x` is shadowed by `foo(x)` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:17:9
|
LL | let x = foo(x);
LL | let x = Some(x);
| ^
-error: `x` is shadowed by `|| x` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:18:9
|
LL | let x = || x;
LL | let x = foo(x);
| ^
-error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:19:9
|
LL | let x = Some(1).map(|_| x)?;
LL | let x = || x;
| ^
+error: `y` is shadowed
+ --> $DIR/shadow.rs:21:9
+ |
+LL | let y = match y {
+ | ^
+ |
+note: previous binding is here
+ --> $DIR/shadow.rs:20:9
+ |
+LL | let y = 1;
+ | ^
+
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:25:9
+ --> $DIR/shadow.rs:30:9
|
LL | let x = 2;
| ^
|
= note: `-D clippy::shadow-unrelated` implied by `-D warnings`
note: previous binding is here
- --> $DIR/shadow.rs:24:9
+ --> $DIR/shadow.rs:29:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:30:13
+ --> $DIR/shadow.rs:35:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:29:10
+ --> $DIR/shadow.rs:34:10
|
LL | fn f(x: u32) {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:35:14
+ --> $DIR/shadow.rs:40:14
|
LL | Some(x) => {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:36:17
+ --> $DIR/shadow.rs:41:17
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:35:14
+ --> $DIR/shadow.rs:40:14
|
LL | Some(x) => {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:40:17
+ --> $DIR/shadow.rs:45:17
|
LL | if let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:41:20
+ --> $DIR/shadow.rs:46:20
|
LL | while let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:42:15
+ --> $DIR/shadow.rs:47:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:43:13
+ --> $DIR/shadow.rs:48:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:42:15
+ --> $DIR/shadow.rs:47:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
-error: aborting due to 19 previous errors
+error: aborting due to 20 previous errors
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
- --> $DIR/method_list_1.rs:26:5
+ --> $DIR/method_list_1.rs:24:5
|
LL | / pub fn add(self, other: T) -> T {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
- --> $DIR/method_list_1.rs:30:5
+ --> $DIR/method_list_1.rs:28:5
|
LL | / pub fn as_mut(&mut self) -> &mut T {
LL | | unimplemented!()
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
- --> $DIR/method_list_1.rs:34:5
+ --> $DIR/method_list_1.rs:32:5
|
LL | / pub fn as_ref(&self) -> &T {
LL | | unimplemented!()
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
- --> $DIR/method_list_1.rs:38:5
+ --> $DIR/method_list_1.rs:36:5
|
LL | / pub fn bitand(self, rhs: T) -> T {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
- --> $DIR/method_list_1.rs:42:5
+ --> $DIR/method_list_1.rs:40:5
|
LL | / pub fn bitor(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
- --> $DIR/method_list_1.rs:46:5
+ --> $DIR/method_list_1.rs:44:5
|
LL | / pub fn bitxor(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
- --> $DIR/method_list_1.rs:50:5
+ --> $DIR/method_list_1.rs:48:5
|
LL | / pub fn borrow(&self) -> &str {
LL | | unimplemented!()
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
- --> $DIR/method_list_1.rs:54:5
+ --> $DIR/method_list_1.rs:52:5
|
LL | / pub fn borrow_mut(&mut self) -> &mut str {
LL | | unimplemented!()
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
- --> $DIR/method_list_1.rs:58:5
+ --> $DIR/method_list_1.rs:56:5
|
LL | / pub fn clone(&self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
- --> $DIR/method_list_1.rs:62:5
+ --> $DIR/method_list_1.rs:60:5
|
LL | / pub fn cmp(&self, other: &Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
- --> $DIR/method_list_1.rs:70:5
+ --> $DIR/method_list_1.rs:68:5
|
LL | / pub fn deref(&self) -> &Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
- --> $DIR/method_list_1.rs:74:5
+ --> $DIR/method_list_1.rs:72:5
|
LL | / pub fn deref_mut(&mut self) -> &mut Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
- --> $DIR/method_list_1.rs:78:5
+ --> $DIR/method_list_1.rs:76:5
|
LL | / pub fn div(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
- --> $DIR/method_list_1.rs:82:5
+ --> $DIR/method_list_1.rs:80:5
|
LL | / pub fn drop(&mut self) {
LL | | unimplemented!()
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
- --> $DIR/method_list_2.rs:27:5
+ --> $DIR/method_list_2.rs:25:5
|
LL | / pub fn eq(&self, other: &Self) -> bool {
LL | | unimplemented!()
= help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
- --> $DIR/method_list_2.rs:31:5
+ --> $DIR/method_list_2.rs:29:5
|
LL | / pub fn from_iter<T>(iter: T) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
- --> $DIR/method_list_2.rs:35:5
+ --> $DIR/method_list_2.rs:33:5
|
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
LL | | unimplemented!()
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
- --> $DIR/method_list_2.rs:39:5
+ --> $DIR/method_list_2.rs:37:5
|
LL | / pub fn hash(&self, state: &mut T) {
LL | | unimplemented!()
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
- --> $DIR/method_list_2.rs:43:5
+ --> $DIR/method_list_2.rs:41:5
|
LL | / pub fn index(&self, index: usize) -> &Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
- --> $DIR/method_list_2.rs:47:5
+ --> $DIR/method_list_2.rs:45:5
|
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
- --> $DIR/method_list_2.rs:51:5
+ --> $DIR/method_list_2.rs:49:5
|
LL | / pub fn into_iter(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
- --> $DIR/method_list_2.rs:55:5
+ --> $DIR/method_list_2.rs:53:5
|
LL | / pub fn mul(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
- --> $DIR/method_list_2.rs:59:5
+ --> $DIR/method_list_2.rs:57:5
|
LL | / pub fn neg(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
- --> $DIR/method_list_2.rs:63:5
+ --> $DIR/method_list_2.rs:61:5
|
LL | / pub fn next(&mut self) -> Option<Self> {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
- --> $DIR/method_list_2.rs:67:5
+ --> $DIR/method_list_2.rs:65:5
|
LL | / pub fn not(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
- --> $DIR/method_list_2.rs:71:5
+ --> $DIR/method_list_2.rs:69:5
|
LL | / pub fn rem(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
- --> $DIR/method_list_2.rs:75:5
+ --> $DIR/method_list_2.rs:73:5
|
LL | / pub fn shl(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
- --> $DIR/method_list_2.rs:79:5
+ --> $DIR/method_list_2.rs:77:5
|
LL | / pub fn shr(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
- --> $DIR/method_list_2.rs:83:5
+ --> $DIR/method_list_2.rs:81:5
|
LL | / pub fn sub(self, rhs: Self) -> Self {
LL | | unimplemented!()
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:24:5
+ --> $DIR/single_component_path_imports.rs:23:5
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:6:1
+ --> $DIR/single_component_path_imports.rs:5:1
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports_macro.rs:16:1
+ --> $DIR/single_component_path_imports_macro.rs:15:1
|
LL | use m2; // fail
| ^^^^^^^ help: remove it entirely
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:14:10
+ --> $DIR/single_component_path_imports_nested_first.rs:13:10
|
LL | use {regex, serde};
| ^^^^^
= help: remove this import
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:14:17
+ --> $DIR/single_component_path_imports_nested_first.rs:13:17
|
LL | use {regex, serde};
| ^^^^^
= help: remove this import
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:5:1
+ --> $DIR/single_component_path_imports_nested_first.rs:4:1
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
--- /dev/null
+#[warn(clippy::string_slice)]
+#[allow(clippy::no_effect)]
+
+fn main() {
+ &"Ölkanne"[1..];
+ let m = "Mötörhead";
+ &m[2..5];
+ let s = String::from(m);
+ &s[0..2];
+}
--- /dev/null
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:5:6
+ |
+LL | &"Ölkanne"[1..];
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::string-slice` implied by `-D warnings`
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:7:6
+ |
+LL | &m[2..5];
+ | ^^^^^^^
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:9:6
+ |
+LL | &s[0..2];
+ | ^^^^^^^
+
+error: aborting due to 3 previous errors
+
#![warn(clippy::to_string_in_display)]
-#![allow(clippy::inherent_to_string_shadow_display)]
+#![allow(clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args)]
use std::fmt;
--- /dev/null
+#![warn(clippy::trailing_empty_array)]
+#![feature(const_generics_defaults)]
+
+// Do lint:
+
+struct RarelyUseful {
+ field: i32,
+ last: [usize; 0],
+}
+
+struct OnlyField {
+ first_and_last: [usize; 0],
+}
+
+struct GenericArrayType<T> {
+ field: i32,
+ last: [T; 0],
+}
+
+#[must_use]
+struct OnlyAnotherAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[derive(Debug)]
+struct OnlyADeriveAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+const ZERO: usize = 0;
+struct ZeroSizedWithConst {
+ field: i32,
+ last: [usize; ZERO],
+}
+
+#[allow(clippy::eq_op)]
+const fn compute_zero() -> usize {
+ (4 + 6) - (2 * 5)
+}
+struct ZeroSizedWithConstFunction {
+ field: i32,
+ last: [usize; compute_zero()],
+}
+
+const fn compute_zero_from_arg(x: usize) -> usize {
+ x - 1
+}
+struct ZeroSizedWithConstFunction2 {
+ field: i32,
+ last: [usize; compute_zero_from_arg(1)],
+}
+
+struct ZeroSizedArrayWrapper([usize; 0]);
+
+struct TupleStruct(i32, [usize; 0]);
+
+struct LotsOfFields {
+ f1: u32,
+ f2: u32,
+ f3: u32,
+ f4: u32,
+ f5: u32,
+ f6: u32,
+ f7: u32,
+ f8: u32,
+ f9: u32,
+ f10: u32,
+ f11: u32,
+ f12: u32,
+ f13: u32,
+ f14: u32,
+ f15: u32,
+ f16: u32,
+ last: [usize; 0],
+}
+
+// Don't lint
+
+#[repr(C)]
+struct GoodReason {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(C)]
+struct OnlyFieldWithReprC {
+ first_and_last: [usize; 0],
+}
+
+struct NonZeroSizedArray {
+ field: i32,
+ last: [usize; 1],
+}
+
+struct NotLastField {
+ f1: u32,
+ zero_sized: [usize; 0],
+ last: i32,
+}
+
+const ONE: usize = 1;
+struct NonZeroSizedWithConst {
+ field: i32,
+ last: [usize; ONE],
+}
+
+#[derive(Debug)]
+#[repr(C)]
+struct AlsoADeriveAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[must_use]
+#[repr(C)]
+struct AlsoAnotherAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(packed)]
+struct ReprPacked {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(C, packed)]
+struct ReprCPacked {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(align(64))]
+struct ReprAlign {
+ field: i32,
+ last: [usize; 0],
+}
+#[repr(C, align(64))]
+struct ReprCAlign {
+ field: i32,
+ last: [usize; 0],
+}
+
+// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
+#[repr(C)]
+enum DontLintAnonymousStructsFromDesuraging {
+ A(u32),
+ B(f32, [u64; 0]),
+ C { x: u32, y: [u64; 0] },
+}
+
+#[repr(C)]
+struct TupleStructReprC(i32, [usize; 0]);
+
+type NamedTuple = (i32, [usize; 0]);
+
+#[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995)
+struct ConstParamZeroDefault<const N: usize = 0> {
+ field: i32,
+ last: [usize; N],
+}
+
+struct ConstParamNoDefault<const N: usize> {
+ field: i32,
+ last: [usize; N],
+}
+
+#[rustfmt::skip]
+struct ConstParamNonZeroDefault<const N: usize = 1> {
+ field: i32,
+ last: [usize; N],
+}
+
+struct TwoGenericParams<T, const N: usize> {
+ field: i32,
+ last: [T; N],
+}
+
+type A = ConstParamZeroDefault;
+type B = ConstParamZeroDefault<0>;
+type C = ConstParamNoDefault<0>;
+type D = ConstParamNonZeroDefault<0>;
+
+fn main() {}
--- /dev/null
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:6:1
+ |
+LL | / struct RarelyUseful {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::trailing-empty-array` implied by `-D warnings`
+ = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:11:1
+ |
+LL | / struct OnlyField {
+LL | | first_and_last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:15:1
+ |
+LL | / struct GenericArrayType<T> {
+LL | | field: i32,
+LL | | last: [T; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:21:1
+ |
+LL | / struct OnlyAnotherAttribute {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:27:1
+ |
+LL | / struct OnlyADeriveAttribute {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:33:1
+ |
+LL | / struct ZeroSizedWithConst {
+LL | | field: i32,
+LL | | last: [usize; ZERO],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:42:1
+ |
+LL | / struct ZeroSizedWithConstFunction {
+LL | | field: i32,
+LL | | last: [usize; compute_zero()],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:50:1
+ |
+LL | / struct ZeroSizedWithConstFunction2 {
+LL | | field: i32,
+LL | | last: [usize; compute_zero_from_arg(1)],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:55:1
+ |
+LL | struct ZeroSizedArrayWrapper([usize; 0]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:57:1
+ |
+LL | struct TupleStruct(i32, [usize; 0]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:59:1
+ |
+LL | / struct LotsOfFields {
+LL | | f1: u32,
+LL | | f2: u32,
+LL | | f3: u32,
+... |
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `LotsOfFields` with `#[repr(C)]` or another `repr` attribute
+
+error: aborting due to 11 previous errors
+
}
}
+mod num_to_bytes {
+ fn test() {
+ unsafe {
+ let _: [u8; 1] = std::mem::transmute(0u8);
+ let _: [u8; 4] = std::mem::transmute(0u32);
+ let _: [u8; 16] = std::mem::transmute(0u128);
+ let _: [u8; 1] = std::mem::transmute(0i8);
+ let _: [u8; 4] = std::mem::transmute(0i32);
+ let _: [u8; 16] = std::mem::transmute(0i128);
+ let _: [u8; 4] = std::mem::transmute(0.0f32);
+ let _: [u8; 8] = std::mem::transmute(0.0f64);
+ }
+ }
+ const fn test_const() {
+ unsafe {
+ let _: [u8; 1] = std::mem::transmute(0u8);
+ let _: [u8; 4] = std::mem::transmute(0u32);
+ let _: [u8; 16] = std::mem::transmute(0u128);
+ let _: [u8; 1] = std::mem::transmute(0i8);
+ let _: [u8; 4] = std::mem::transmute(0i32);
+ let _: [u8; 16] = std::mem::transmute(0i128);
+ let _: [u8; 4] = std::mem::transmute(0.0f32);
+ let _: [u8; 8] = std::mem::transmute(0.0f64);
+ }
+ }
+}
+
fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
let _: &str = unsafe { std::mem::transmute(b) };
let _: &mut str = unsafe { std::mem::transmute(mb) };
LL | let _: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
+error: transmute from a `u8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:109:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+ |
+ = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
+
+error: transmute from a `u32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:110:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:111:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0u128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:112:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0i8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:113:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:114:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0i128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
+error: transmute from a `f32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:115:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
+
+error: transmute from a `f64` to a `[u8; 8]`
+ --> $DIR/transmute.rs:116:30
+ |
+LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
+
+error: transmute from a `u8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:121:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+
+error: transmute from a `u32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:122:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:123:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0u128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:124:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0i8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:125:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:126:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0i128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
error: transmute from a `&[u8]` to a `&str`
- --> $DIR/transmute.rs:107:28
+ --> $DIR/transmute.rs:134:28
|
LL | let _: &str = unsafe { std::mem::transmute(b) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
= note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
error: transmute from a `&mut [u8]` to a `&mut str`
- --> $DIR/transmute.rs:108:32
+ --> $DIR/transmute.rs:135:32
|
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
-error: aborting due to 24 previous errors
+error: aborting due to 38 previous errors
--- /dev/null
+#![warn(clippy::undocumented_unsafe_blocks)]
+
+// Valid comments
+
+fn nested_local() {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+ };
+ };
+}
+
+fn deep_nest() {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+
+ // Safety:
+ unsafe {};
+
+ let _ = {
+ let _ = {
+ let _ = {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+
+ // Safety:
+ unsafe {};
+ };
+ };
+ };
+
+ // Safety:
+ unsafe {};
+ };
+ };
+ };
+
+ // Safety:
+ unsafe {};
+ };
+
+ // Safety:
+ unsafe {};
+}
+
+fn local_tuple_expression() {
+ // Safety:
+ let _ = (42, unsafe {});
+}
+
+fn line_comment() {
+ // Safety:
+ unsafe {}
+}
+
+fn line_comment_newlines() {
+ // Safety:
+
+ unsafe {}
+}
+
+fn line_comment_empty() {
+ // Safety:
+ //
+ //
+ //
+ unsafe {}
+}
+
+fn line_comment_with_extras() {
+ // This is a description
+ // Safety:
+ unsafe {}
+}
+
+fn block_comment() {
+ /* Safety: */
+ unsafe {}
+}
+
+fn block_comment_newlines() {
+ /* Safety: */
+
+ unsafe {}
+}
+
+#[rustfmt::skip]
+fn inline_block_comment() {
+ /* Safety: */unsafe {}
+}
+
+fn block_comment_with_extras() {
+ /* This is a description
+ * Safety:
+ */
+ unsafe {}
+}
+
+fn block_comment_terminator_same_line() {
+ /* This is a description
+ * Safety: */
+ unsafe {}
+}
+
+fn buried_safety() {
+ // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+ // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+ // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+ // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+ // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
+ // laborum. Safety:
+ // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
+ // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
+ // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
+ // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
+ unsafe {}
+}
+
+fn safety_with_prepended_text() {
+ // This is a test. Safety:
+ unsafe {}
+}
+
+fn local_line_comment() {
+ // Safety:
+ let _ = unsafe {};
+}
+
+fn local_block_comment() {
+ /* Safety: */
+ let _ = unsafe {};
+}
+
+fn comment_array() {
+ // Safety:
+ let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn comment_tuple() {
+ // Safety:
+ let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn comment_unary() {
+ // Safety:
+ let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn comment_match() {
+ // Safety:
+ let _ = match unsafe {} {
+ _ => {},
+ };
+}
+
+fn comment_addr_of() {
+ // Safety:
+ let _ = &unsafe {};
+}
+
+fn comment_repeat() {
+ // Safety:
+ let _ = [unsafe {}; 5];
+}
+
+fn comment_macro_call() {
+ macro_rules! t {
+ ($b:expr) => {
+ $b
+ };
+ }
+
+ t!(
+ // Safety:
+ unsafe {}
+ );
+}
+
+fn comment_macro_def() {
+ macro_rules! t {
+ () => {
+ // Safety:
+ unsafe {}
+ };
+ }
+
+ t!();
+}
+
+fn non_ascii_comment() {
+ // ॐ᧻໒ Safety: ௵∰
+ unsafe {};
+}
+
+fn local_commented_block() {
+ let _ =
+ // Safety:
+ unsafe {};
+}
+
+fn local_nest() {
+ // Safety:
+ let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
+}
+
+// Invalid comments
+
+fn no_comment() {
+ unsafe {}
+}
+
+fn no_comment_array() {
+ let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn no_comment_tuple() {
+ let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn no_comment_unary() {
+ let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn no_comment_match() {
+ let _ = match unsafe {} {
+ _ => {},
+ };
+}
+
+fn no_comment_addr_of() {
+ let _ = &unsafe {};
+}
+
+fn no_comment_repeat() {
+ let _ = [unsafe {}; 5];
+}
+
+fn local_no_comment() {
+ let _ = unsafe {};
+}
+
+fn no_comment_macro_call() {
+ macro_rules! t {
+ ($b:expr) => {
+ $b
+ };
+ }
+
+ t!(unsafe {});
+}
+
+fn no_comment_macro_def() {
+ macro_rules! t {
+ () => {
+ unsafe {}
+ };
+ }
+
+ t!();
+}
+
+fn trailing_comment() {
+ unsafe {} // Safety:
+}
+
+fn internal_comment() {
+ unsafe {
+ // Safety:
+ }
+}
+
+fn interference() {
+ // Safety
+
+ let _ = 42;
+
+ unsafe {};
+}
+
+fn main() {}
--- /dev/null
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:215:5
+ |
+LL | unsafe {}
+ | ^^^^^^^^^
+ |
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + unsafe {}
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:219:5
+ |
+LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:223:5
+ |
+LL | let _ = (42, unsafe {}, "test", unsafe {});
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = (42, unsafe {}, "test", unsafe {});
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:227:5
+ |
+LL | let _ = *unsafe { &42 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = *unsafe { &42 };
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:232:5
+ |
+LL | let _ = match unsafe {} {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = match unsafe {} {
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:238:5
+ |
+LL | let _ = &unsafe {};
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = &unsafe {};
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:242:5
+ |
+LL | let _ = [unsafe {}; 5];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = [unsafe {}; 5];
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:246:5
+ |
+LL | let _ = unsafe {};
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = unsafe {};
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:256:8
+ |
+LL | t!(unsafe {});
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ t!(// Safety: ...
+LL ~ unsafe {});
+ |
+
+error: unsafe block in macro expansion missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:262:13
+ |
+LL | unsafe {}
+ | ^^^^^^^^^
+...
+LL | t!();
+ | ---- in this macro invocation
+ |
+ = help: consider adding a safety comment in the macro definition
+ = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:270:5
+ |
+LL | unsafe {} // Safety:
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe {} // Safety:
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:274:5
+ |
+LL | unsafe {
+ | ^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + unsafe {
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:284:5
+ |
+LL | unsafe {};
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe {};
+ |
+
+error: aborting due to 13 previous errors
+
--- /dev/null
+#![warn(clippy::uninit_vec)]
+
+use std::mem::MaybeUninit;
+
+#[derive(Default)]
+struct MyVec {
+ vec: Vec<u8>,
+}
+
+fn main() {
+ // with_capacity() -> set_len() should be detected
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // reserve() -> set_len() should be detected
+ vec.reserve(1000);
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // new() -> set_len() should be detected
+ let mut vec: Vec<u8> = Vec::new();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // default() -> set_len() should be detected
+ let mut vec: Vec<u8> = Default::default();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ let mut vec: Vec<u8> = Vec::default();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // test when both calls are enclosed in the same unsafe block
+ unsafe {
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ vec.reserve(1000);
+ vec.set_len(200);
+ }
+
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ // test the case where there are other statements in the following unsafe block
+ vec.set_len(200);
+ assert!(vec.len() == 200);
+ }
+
+ // handle vec stored in the field of a struct
+ let mut my_vec = MyVec::default();
+ my_vec.vec.reserve(1000);
+ unsafe {
+ my_vec.vec.set_len(200);
+ }
+
+ my_vec.vec = Vec::with_capacity(1000);
+ unsafe {
+ my_vec.vec.set_len(200);
+ }
+
+ // Test `#[allow(...)]` attributes on inner unsafe block (shouldn't trigger)
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ #[allow(clippy::uninit_vec)]
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // MaybeUninit-wrapped types should not be detected
+ unsafe {
+ let mut vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ let mut vec: Vec<(MaybeUninit<u8>, MaybeUninit<bool>)> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ let mut vec: Vec<(MaybeUninit<u8>, [MaybeUninit<bool>; 2])> = Vec::with_capacity(1000);
+ vec.set_len(200);
+ }
+
+ // known false negative
+ let mut vec1: Vec<u8> = Vec::with_capacity(1000);
+ let mut vec2: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ vec1.set_len(200);
+ vec2.set_len(200);
+ }
+}
--- /dev/null
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:12:5
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::uninit-vec` implied by `-D warnings`
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:18:5
+ |
+LL | vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:24:5
+ |
+LL | let mut vec: Vec<u8> = Vec::new();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:30:5
+ |
+LL | let mut vec: Vec<u8> = Default::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:35:5
+ |
+LL | let mut vec: Vec<u8> = Vec::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:49:5
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:58:5
+ |
+LL | my_vec.vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | my_vec.vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:63:5
+ |
+LL | my_vec.vec = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | my_vec.vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:42:9
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:45:9
+ |
+LL | vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: aborting due to 10 previous errors
+
--- /dev/null
+#![warn(clippy::unit_hash)]
+
+use std::collections::hash_map::DefaultHasher;
+use std::hash::Hash;
+
+enum Foo {
+ Empty,
+ WithValue(u8),
+}
+
+fn do_nothing() {}
+
+fn main() {
+ let mut state = DefaultHasher::new();
+ let my_enum = Foo::Empty;
+
+ match my_enum {
+ Foo::Empty => ().hash(&mut state),
+ Foo::WithValue(x) => x.hash(&mut state),
+ }
+
+ let res = ();
+ res.hash(&mut state);
+
+ #[allow(clippy::unit_arg)]
+ do_nothing().hash(&mut state);
+}
--- /dev/null
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:18:23
+ |
+LL | Foo::Empty => ().hash(&mut state),
+ | ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: `-D clippy::unit-hash` implied by `-D warnings`
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:23:5
+ |
+LL | res.hash(&mut state);
+ | ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:26:5
+ |
+LL | do_nothing().hash(&mut state);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: aborting due to 3 previous errors
+
#![allow(clippy::stable_sort_primitive)]
+use std::cell::Ref;
use std::cmp::Reverse;
fn unnecessary_sort_by() {
// `Reverse(b)` would borrow in the following cases, don't lint
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
+
+ // No warning if element does not implement `Ord`
+ let mut vec: Vec<Ref<usize>> = Vec::new();
+ vec.sort_unstable_by(|a, b| a.cmp(b));
}
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
#![allow(clippy::stable_sort_primitive)]
+use std::cell::Ref;
use std::cmp::Reverse;
fn unnecessary_sort_by() {
// `Reverse(b)` would borrow in the following cases, don't lint
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
+
+ // No warning if element does not implement `Ord`
+ let mut vec: Vec<Ref<usize>> = Vec::new();
+ vec.sort_unstable_by(|a, b| a.cmp(b));
}
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
error: use Vec::sort here instead
- --> $DIR/unnecessary_sort_by.rs:14:5
+ --> $DIR/unnecessary_sort_by.rs:15:5
|
LL | vec.sort_by(|a, b| a.cmp(b));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()`
= note: `-D clippy::unnecessary-sort-by` implied by `-D warnings`
error: use Vec::sort here instead
- --> $DIR/unnecessary_sort_by.rs:15:5
+ --> $DIR/unnecessary_sort_by.rs:16:5
|
LL | vec.sort_unstable_by(|a, b| a.cmp(b));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:16:5
+ --> $DIR/unnecessary_sort_by.rs:17:5
|
LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:17:5
+ --> $DIR/unnecessary_sort_by.rs:18:5
|
LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:20:5
+ --> $DIR/unnecessary_sort_by.rs:21:5
|
LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:21:5
+ --> $DIR/unnecessary_sort_by.rs:22:5
|
LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:31:5
+ --> $DIR/unnecessary_sort_by.rs:32:5
|
LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:32:5
+ --> $DIR/unnecessary_sort_by.rs:33:5
|
LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:88:9
+ --> $DIR/unnecessary_sort_by.rs:93:9
|
LL | args.sort_by(|a, b| a.name().cmp(&b.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:89:9
+ --> $DIR/unnecessary_sort_by.rs:94:9
|
LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:91:9
+ --> $DIR/unnecessary_sort_by.rs:96:9
|
LL | args.sort_by(|a, b| b.name().cmp(&a.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:92:9
+ --> $DIR/unnecessary_sort_by.rs:97:9
|
LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))`
-// edition:2018
#![warn(clippy::unused_async)]
async fn foo() -> i32 {
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:4:1
+ --> $DIR/unused_async.rs:3:1
|
LL | / async fn foo() -> i32 {
LL | | 4
// run-rustfix
-// edition:2018
// aux-build:proc_macro_derive.rs
#![warn(clippy::use_self)]
// run-rustfix
-// edition:2018
// aux-build:proc_macro_derive.rs
#![warn(clippy::use_self)]
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:23:21
+ --> $DIR/use_self.rs:22:21
|
LL | fn new() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
= note: `-D clippy::use-self` implied by `-D warnings`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:24:13
+ --> $DIR/use_self.rs:23:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:26:22
+ --> $DIR/use_self.rs:25:22
|
LL | fn test() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:27:13
+ --> $DIR/use_self.rs:26:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:32:25
+ --> $DIR/use_self.rs:31:25
|
LL | fn default() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:33:13
+ --> $DIR/use_self.rs:32:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:98:24
+ --> $DIR/use_self.rs:97:24
|
LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:98:55
+ --> $DIR/use_self.rs:97:55
|
LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:113:13
+ --> $DIR/use_self.rs:112:13
|
LL | TS(0)
| ^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:148:29
+ --> $DIR/use_self.rs:147:29
|
LL | fn bar() -> Bar {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:149:21
+ --> $DIR/use_self.rs:148:21
|
LL | Bar { foo: Foo {} }
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:160:21
+ --> $DIR/use_self.rs:159:21
|
LL | fn baz() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:161:13
+ --> $DIR/use_self.rs:160:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:178:21
+ --> $DIR/use_self.rs:177:21
|
LL | let _ = Enum::B(42);
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:179:21
+ --> $DIR/use_self.rs:178:21
|
LL | let _ = Enum::C { field: true };
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:180:21
+ --> $DIR/use_self.rs:179:21
|
LL | let _ = Enum::A;
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:222:13
+ --> $DIR/use_self.rs:221:13
|
LL | nested::A::fun_1();
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:223:13
+ --> $DIR/use_self.rs:222:13
|
LL | nested::A::A;
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:225:13
+ --> $DIR/use_self.rs:224:13
|
LL | nested::A {};
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:244:13
+ --> $DIR/use_self.rs:243:13
|
LL | TestStruct::from_something()
| ^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:258:25
+ --> $DIR/use_self.rs:257:25
|
LL | async fn g() -> S {
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:259:13
+ --> $DIR/use_self.rs:258:13
|
LL | S {}
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:263:16
+ --> $DIR/use_self.rs:262:16
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:263:22
+ --> $DIR/use_self.rs:262:22
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:286:29
+ --> $DIR/use_self.rs:285:29
|
LL | fn foo(value: T) -> Foo<T> {
| ^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:287:13
+ --> $DIR/use_self.rs:286:13
|
LL | Foo::<T> { value }
| ^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:459:13
+ --> $DIR/use_self.rs:458:13
|
LL | A::new::<submod::B>(submod::B {})
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:496:13
+ --> $DIR/use_self.rs:495:13
|
LL | S2::new()
| ^^ help: use the applicable keyword: `Self`
-// edition:2018
// aux-build:proc_macro_derive.rs
#![feature(rustc_private)]
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:26:5
+ --> $DIR/used_underscore_binding.rs:25:5
|
LL | _foo + 1
| ^^^^
= note: `-D clippy::used-underscore-binding` implied by `-D warnings`
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:31:20
+ --> $DIR/used_underscore_binding.rs:30:20
|
LL | println!("{}", _foo);
| ^^^^
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:32:16
+ --> $DIR/used_underscore_binding.rs:31:16
|
LL | assert_eq!(_foo, _foo);
| ^^^^
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:32:22
+ --> $DIR/used_underscore_binding.rs:31:22
|
LL | assert_eq!(_foo, _foo);
| ^^^^
error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:45:5
+ --> $DIR/used_underscore_binding.rs:44:5
|
LL | s._underscore_field += 1;
| ^^^^^^^^^^^^^^^^^^^
error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:100:16
+ --> $DIR/used_underscore_binding.rs:99:16
|
LL | uses_i(_i);
| ^^
let _ = vec![1, 2, 3].into_iter();
let _: String = format!("Hello {}", "world");
- // keep parenthesis around `a + b` for suggestion (see #4750)
+ // keep parentheses around `a + b` for suggestion (see #4750)
let a: i32 = 1;
let b: i32 = 1;
let _ = (a + b) * 3;
let _ = vec![1, 2, 3].into_iter().into_iter();
let _: String = format!("Hello {}", "world").into();
- // keep parenthesis around `a + b` for suggestion (see #4750)
+ // keep parentheses around `a + b` for suggestion (see #4750)
let a: i32 = 1;
let b: i32 = 1;
let _ = i32::from(a + b) * 3;
+// edition:2015
// run-rustfix
// aux-build:wildcard_imports_helper.rs
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
#![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
let _ = foofoo();
}
}
+
+ mod attestation_should_be_replaced {
+ use super::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
}
+// edition:2015
// run-rustfix
// aux-build:wildcard_imports_helper.rs
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
#![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
let _ = foofoo();
}
}
+
+ mod attestation_should_be_replaced {
+ use super::*;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
}
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:12:5
+ --> $DIR/wildcard_imports.rs:17:5
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
= note: `-D clippy::wildcard-imports` implied by `-D warnings`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:13:5
+ --> $DIR/wildcard_imports.rs:18:5
|
LL | use crate::mod_mod::*;
| ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:14:5
+ --> $DIR/wildcard_imports.rs:19:5
|
LL | use crate::multi_fn_mod::*;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:16:5
+ --> $DIR/wildcard_imports.rs:21:5
|
LL | use crate::struct_mod::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:20:5
+ --> $DIR/wildcard_imports.rs:25:5
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:21:5
+ --> $DIR/wildcard_imports.rs:26:5
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:92:13
+ --> $DIR/wildcard_imports.rs:97:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:98:75
+ --> $DIR/wildcard_imports.rs:103:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:99:13
+ --> $DIR/wildcard_imports.rs:104:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:110:20
+ --> $DIR/wildcard_imports.rs:115:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:110:30
+ --> $DIR/wildcard_imports.rs:115:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:117:13
+ --> $DIR/wildcard_imports.rs:122:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:146:9
+ --> $DIR/wildcard_imports.rs:151:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:155:9
+ --> $DIR/wildcard_imports.rs:160:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:156:9
+ --> $DIR/wildcard_imports.rs:161:9
|
LL | use crate:: fn_mod::
| _________^
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:167:13
+ --> $DIR/wildcard_imports.rs:172:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:202:17
+ --> $DIR/wildcard_imports.rs:207:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:210:13
+ --> $DIR/wildcard_imports.rs:215:13
|
LL | use super_imports::*;
| ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:219:17
+ --> $DIR/wildcard_imports.rs:224:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:228:13
+ --> $DIR/wildcard_imports.rs:233:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
-error: aborting due to 20 previous errors
+error: usage of wildcard import
+ --> $DIR/wildcard_imports.rs:241:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:17:17
+ --> $DIR/wrong_self_convention.rs:16:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:23:21
+ --> $DIR/wrong_self_convention.rs:22:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:35:15
+ --> $DIR/wrong_self_convention.rs:34:15
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:37:17
+ --> $DIR/wrong_self_convention.rs:36:17
|
LL | fn into_i32(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:39:15
+ --> $DIR/wrong_self_convention.rs:38:15
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:41:15
+ --> $DIR/wrong_self_convention.rs:40:15
|
LL | fn to_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:43:17
+ --> $DIR/wrong_self_convention.rs:42:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:45:19
+ --> $DIR/wrong_self_convention.rs:44:19
|
LL | pub fn as_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:46:21
+ --> $DIR/wrong_self_convention.rs:45:21
|
LL | pub fn into_i64(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:47:19
+ --> $DIR/wrong_self_convention.rs:46:19
|
LL | pub fn is_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:48:19
+ --> $DIR/wrong_self_convention.rs:47:19
|
LL | pub fn to_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:49:21
+ --> $DIR/wrong_self_convention.rs:48:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:94:19
+ --> $DIR/wrong_self_convention.rs:93:19
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:97:25
+ --> $DIR/wrong_self_convention.rs:96:25
|
LL | fn into_i32_ref(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:99:19
+ --> $DIR/wrong_self_convention.rs:98:19
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:103:21
+ --> $DIR/wrong_self_convention.rs:102:21
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:118:19
+ --> $DIR/wrong_self_convention.rs:117:19
|
LL | fn as_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:121:25
+ --> $DIR/wrong_self_convention.rs:120:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:123:19
+ --> $DIR/wrong_self_convention.rs:122:19
|
LL | fn is_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:127:21
+ --> $DIR/wrong_self_convention.rs:126:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:145:25
+ --> $DIR/wrong_self_convention.rs:144:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:151:21
+ --> $DIR/wrong_self_convention.rs:150:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
- --> $DIR/wrong_self_convention.rs:175:22
+ --> $DIR/wrong_self_convention.rs:174:22
|
LL | fn to_u64_v2(&self) -> u64 {
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:184:19
+ --> $DIR/wrong_self_convention.rs:183:19
|
LL | fn to_u64(self) -> u64 {
| ^^^^
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:55:29
+ --> $DIR/wrong_self_convention2.rs:54:29
|
LL | pub fn from_be_self(self) -> Self {
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:64:25
+ --> $DIR/wrong_self_convention2.rs:63:25
|
LL | fn from_be_self(self) -> Self;
| ^^^^
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_conventions_mut.rs:15:24
+ --> $DIR/wrong_self_conventions_mut.rs:14:24
|
LL | pub fn to_many(&mut self) -> Option<&mut [T]> {
| ^^^^^^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference
- --> $DIR/wrong_self_conventions_mut.rs:23:28
+ --> $DIR/wrong_self_conventions_mut.rs:22:28
|
LL | pub fn to_many_mut(&self) -> Option<&[T]> {
| ^^^^^
--- /dev/null
+#[warn(clippy::eq_op)]
+#[test]
+fn eq_op_shouldnt_trigger_in_tests() {
+ let a = 1;
+ let result = a + 1 == 1 + a;
+ assert!(result);
+}
+
+#[test]
+fn eq_op_macros_shouldnt_trigger_in_tests() {
+ let a = 1;
+ let b = 2;
+ assert_eq!(a, a);
+ assert_eq!(a + b, b + a);
+}
/// The current Rust channel
pub channel: String,
+ /// The default Rust edition
+ pub edition: Option<String>,
+
// Configuration for various run-make tests frobbing things like C compilers
// or querying about various LLVM component information.
pub cc: String,
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
+ let mut has_edition = false;
if !testfile.is_dir() {
let file = File::open(testfile).unwrap();
if let Some(edition) = config.parse_edition(ln) {
self.compile_flags.push(format!("--edition={}", edition));
- if edition == "2021" {
- self.compile_flags.push("-Zunstable-options".to_string());
- }
+ has_edition = true;
}
config.parse_and_update_revisions(ln, &mut self.revisions);
}
}
}
+
+ if let (Some(edition), false) = (&config.edition, has_edition) {
+ self.compile_flags.push(format!("--edition={}", edition));
+ }
}
fn update_fail_mode(&mut self, ln: &str, config: &Config) {
let mut config = config();
config.target = "x86_64-pc-windows-gnu".to_owned();
- assert!(check_ignore(&config, "// only-i686"));
+ assert!(check_ignore(&config, "// only-x86"));
assert!(check_ignore(&config, "// only-linux"));
assert!(check_ignore(&config, "// only-msvc"));
assert!(check_ignore(&config, "// only-32bit"));
struct DiagnosticCode {
/// The code itself.
code: String,
- /// An explanation for the code.
- explanation: Option<String>,
}
pub fn rustfix_diagnostics_only(output: &str) -> String {
)
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
.optflag("h", "help", "show this message")
- .reqopt("", "channel", "current Rust channel", "CHANNEL");
+ .reqopt("", "channel", "current Rust channel", "CHANNEL")
+ .optopt("", "edition", "default Rust edition", "EDITION");
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
rustfix_coverage: matches.opt_present("rustfix-coverage"),
has_tidy,
channel: matches.opt_str("channel").unwrap(),
+ edition: matches.opt_str("edition"),
cc: matches.opt_str("cc").unwrap(),
cxx: matches.opt_str("cxx").unwrap(),
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib);
rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
}
- if !self.props.aux_crates.is_empty() {
- rustc.arg("-Zunstable-options");
- }
aux_dir
}
("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+ ("core/primitive.str.html", &["begin</code>, <code>end"]),
+ ("std/primitive.str.html", &["begin</code>, <code>end"]),
];
-Subproject commit fa91a89193d26e6a86e2eee1cbaa38cb28ccebe1
+Subproject commit 9c18177cd36fe07a3c251234240a9c77a4e66785
-Subproject commit ed4b312fa777ebb39ba1348fe3df574c441a485e
+Subproject commit 04f03a360ab8fef3d9c0ff84de2d39b8a196c717
"test_folder": "",
"test_file": "",
};
- var correspondances = {
+ var correspondences = {
"--resource-suffix": "resource_suffix",
"--doc-folder": "doc_folder",
"--test-folder": "test_folder",
};
for (var i = 0; i < args.length; ++i) {
- if (args[i] === "--resource-suffix"
- || args[i] === "--doc-folder"
- || args[i] === "--test-folder"
- || args[i] === "--test-file"
- || args[i] === "--crate-name") {
+ if (correspondences.hasOwnProperty(args[i])) {
i += 1;
if (i >= args.length) {
console.log("Missing argument after `" + args[i - 1] + "` option.");
return null;
}
- opts[correspondances[args[i - 1]]] = args[i];
+ opts[correspondences[args[i - 1]]] = args[i];
} else if (args[i] === "--help") {
showHelp();
process.exit(0);
name: upload
on:
+ push:
release:
types: [created]
+ workflow_dispatch:
jobs:
build-release:
- build: linux-x86_64
os: ubuntu-latest
rust: nightly
+ target: x86_64-unknown-linux-gnu
- build: macos-x86_64
os: macos-latest
rust: nightly
+ target: x86_64-apple-darwin
- build: windows-x86_64-gnu
os: windows-latest
rust: nightly-x86_64-gnu
+ target: x86_64-pc-windows-gnu
- build: windows-x86_64-msvc
os: windows-latest
rust: nightly-x86_64-msvc
+ target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- - name: Install Rust
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: ${{ matrix.rust }}
- override: true
+ # Run build
+ - name: install rustup
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
+ sh rustup-init.sh -y --default-toolchain none
+ rustup target add ${{ matrix.target }}
- name: Add mingw64 to path for x86_64-gnu
run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
if: matrix.rust == 'nightly-x86_64-gnu'
shell: bash
- - name: Install cargo-make
- uses: actions-rs/cargo@v1
- with:
- command: install
- args: --force cargo-make
-
- name: Build release binaries
uses: actions-rs/cargo@v1
with:
- command: make
- args: release
+ command: build
+ args: --release
- name: Build archive
shell: bash
fi
- name: Upload Release Asset
+ if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- - name: cargo-make
- run: cargo install --force cargo-make
-
- name: build
run: |
rustc -Vv
# Generated by Cargo
# will have compiled files and executables
/target
+tests/cargo-fmt/**/target
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
## [Unreleased]
+## [1.4.38] 2021-10-20
+
+### Changed
+
+- Switched from `rustc-ap-*` crates to `rustc_private` for consumption model of rustc internals
+- `annotate-snippets` updated to v0.8 [PR #4762](https://github.com/rust-lang/rustfmt/pull/4762)
+- Greatly improved the performance of `cargo fmt` in large workspaces utilizing the `--all` flag by updating to a newer version of `cargo_metadata` that leverages updated `cargo` output from v1.51+ [PR #4997](https://github.com/rust-lang/rustfmt/pull/4997)
+- Improved formatting of long slice patterns [#4530](https://github.com/rust-lang/rustfmt/issues/4530)
+ - **Note you must have `version = Two` in your configuration to take advantage of the new formatting**
+- Stabilized `match_block_trailing_comma` configuration option [#3380](https://github.com/rust-lang/rustfmt/issues/3380) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma)
+- Stabilized `disable_all_formatting` configuration option [#5026](https://github.com/rust-lang/rustfmt/pull/5026) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting)
+- Various improvements to the configuration documentation website [https://rust-lang.github.io/rustfmt/?version=v1.4.38]([https://rust-lang.github.io/rustfmt/?version=v1.4.38])
+- Addressed various clippy and rustc warnings
+
+
+### Fixed
+
+- Resolved issue where specious whitespace would be inserted when a block style comment was terminated within string literal processing [#4312](https://github.com/rust-lang/rustfmt/issues/4312)
+- Nested out-of-line mods are again parsed and formatted [#4874](https://github.com/rust-lang/rustfmt/issues/4874)
+- Accepts `2021` for edition value from rustfmt command line [PR #4847](https://github.com/rust-lang/rustfmt/pull/4847)
+- Unstable command line options are no longer displayed in `--help` text on stable [PR #4798](https://github.com/rust-lang/rustfmt/issues/4798)
+- Stopped panicking on patterns in match arms which start with non-ascii characters [#4868](https://github.com/rust-lang/rustfmt/issues/4868)
+- Stopped stripping defaults on const params [#4816](https://github.com/rust-lang/rustfmt/issues/4816)
+- Fixed issue with dropped content with GAT aliases with self bounds in impls [#4911](https://github.com/rust-lang/rustfmt/issues/4911)
+- Stopped removing generic args on associated type constraints [#4943](https://github.com/rust-lang/rustfmt/issues/4943)
+- Stopped dropping visibility on certain trait and impl items [#4960](https://github.com/rust-lang/rustfmt/issues/4960)
+- Fixed dropping of qualified paths in struct patterns [#4908](https://github.com/rust-lang/rustfmt/issues/4908) and [#5005](https://github.com/rust-lang/rustfmt/issues/5005)
+- Fixed bug in line width calculation that was causing specious formatting of certain patterns [#4031](https://github.com/rust-lang/rustfmt/issues/4031)
+ - **Note that this bug fix may cause observable formatting changes in cases where code had been formatted with prior versions of rustfmt that contained the bug**
+- Fixed bug where rustfmt would drop parameter attributes if they were too long in certain cases [#4579](https://github.com/rust-lang/rustfmt/issues/4579)
+- Resolved idempotency issue with extern body elements [#4963](https://github.com/rust-lang/rustfmt/issues/4963)
+- rustfmt will now handle doc-style comments on function parameters, since they could appear with certain macro usage patterns even though it's generally invalid syntax [#4936](https://github.com/rust-lang/rustfmt/issues/4936)
+- Fixed bug in `match_block_trailing_comma` where commas were not added to the blocks of bodies whose arm had a guard that did not fit on the same line as the pattern [#4998](https://github.com/rust-lang/rustfmt/pull/4998)
+- Fixed bug in cases where derive attributes started with a block style comment [#4984](https://github.com/rust-lang/rustfmt/issues/4984)
+- Fixed issue where the struct rest could be lost when `struct_field_align_threshold` was enabled [#4926](https://github.com/rust-lang/rustfmt/issues/4926)
+- Handles cases where certain control flow type expressions have comments between patterns/keywords and the pattern ident contains the keyword [#5009](https://github.com/rust-lang/rustfmt/issues/5009)
+- Handles tuple structs that have explicit visibilities and start with a block style comment [#5011](https://github.com/rust-lang/rustfmt/issues/5011)
+- Handles leading line-style comments in certain types of macro calls [#4615](https://github.com/rust-lang/rustfmt/issues/4615)
+
+
+### Added
+- Granular width heuristic options made available for user control [PR #4782](https://github.com/rust-lang/rustfmt/pull/4782). This includes the following:
+ - [`array_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#array_width)
+ - [`attr_fn_like_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#attr_fn_like_width)
+ - [`chain_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#chain_width)
+ - [`fn_call_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#fn_call_width)
+ - [`single_line_if_else_max_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#single_line_if_else_max_width)
+ - [`struct_lit_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_lit_width)
+ - [`struct_variant_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_variant_width)
+
+Note this hit the rustup distributions prior to the v1.4.38 release as part of an out-of-cycle updates, but is listed in this version because the feature was not in the other v1.4.37 releases. See also the `use_small_heuristics` section on the configuration site for more information
+[https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics)
+
+- New `One` variant added to `imports_granularity` configuration option which can be used to reformat all imports into a single use statement [#4669](https://github.com/rust-lang/rustfmt/issues/4669)
+- rustfmt will now skip files that are annotated with `@generated` at the top of the file [#3958](https://github.com/rust-lang/rustfmt/issues/3958)
+- New configuration option `hex_literal_case` that allows user to control the casing utilized for hex literals [PR #4903](https://github.com/rust-lang/rustfmt/pull/4903)
+
+See the section on the configuration site for more information
+https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#hex_literal_case
+
+- `cargo fmt` now directly supports the `--check` flag, which means it's now possible to run `cargo fmt --check` instead of the more verbose `cargo fmt -- --check` [#3888](https://github.com/rust-lang/rustfmt/issues/3888)
+
+### Install/Download Options
+- **rustup (nightly)** - *pending*
+- **GitHub Release Binaries** - [Release v1.4.38](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.38)
+- **Build from source** - [Tag v1.4.38](https://github.com/rust-lang/rustfmt/tree/v1.4.38), see instructions for how to [install rustfmt from source][install-from-source]
+
## [1.4.37] 2021-04-03
### Changed
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
-[[package]]
-name = "arrayref"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
-
-[[package]]
-name = "arrayvec"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
-dependencies = [
- "nodrop",
-]
-
[[package]]
name = "atty"
version = "0.2.13"
[[package]]
name = "autocfg"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
-
-[[package]]
-name = "backtrace"
-version = "0.3.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
-dependencies = [
- "backtrace-sys",
- "cfg-if 0.1.10",
- "libc",
- "rustc-demangle",
-]
-
-[[package]]
-name = "backtrace-sys"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "base64"
-version = "0.10.1"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-dependencies = [
- "byteorder",
-]
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-[[package]]
-name = "blake2b_simd"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
-dependencies = [
- "arrayref",
- "arrayvec",
- "constant_time_eq",
-]
-
[[package]]
name = "bstr"
version = "0.2.8"
[[package]]
name = "bytecount"
-version = "0.6.0"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
+checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
dependencies = [
- "packed_simd",
+ "packed_simd_2",
]
[[package]]
-name = "byteorder"
-version = "1.3.2"
+name = "camino"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
[[package]]
-name = "cargo_metadata"
-version = "0.8.2"
+name = "cargo-platform"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7"
dependencies = [
- "semver",
"serde",
- "serde_derive",
- "serde_json",
]
[[package]]
-name = "cc"
-version = "1.0.46"
+name = "cargo_metadata"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+]
[[package]]
name = "cfg-if"
"vec_map",
]
-[[package]]
-name = "cloudabi"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "constant_time_eq"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
-dependencies = [
- "crossbeam-utils 0.7.0",
-]
-
[[package]]
name = "crossbeam-utils"
-version = "0.6.6"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
-dependencies = [
- "cfg-if 0.1.10",
- "lazy_static",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
+checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
dependencies = [
"autocfg",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "dirs-sys"
-version = "0.3.4"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
dependencies = [
- "cfg-if 0.1.10",
"libc",
"redox_users",
"winapi",
[[package]]
name = "env_logger"
-version = "0.6.2"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
dependencies = [
"atty",
"humantime",
"termcolor",
]
-[[package]]
-name = "failure"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
-dependencies = [
- "backtrace",
- "failure_derive",
-]
-
-[[package]]
-name = "failure_derive"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
[[package]]
name = "getopts"
version = "0.2.21"
"unicode-width",
]
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi",
+]
+
[[package]]
name = "globset"
-version = "0.4.4"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
+checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a"
dependencies = [
"aho-corasick",
"bstr",
[[package]]
name = "humantime"
-version = "1.3.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
-dependencies = [
- "quick-error",
-]
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ignore"
-version = "0.4.11"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e"
+checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
dependencies = [
- "crossbeam-channel",
+ "crossbeam-utils",
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
- "thread_local 1.0.1",
+ "thread_local",
"walkdir",
"winapi-util",
]
[[package]]
name = "itertools"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
+[[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
[[package]]
name = "log"
version = "0.4.14"
checksum = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
[[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "packed_simd"
-version = "0.3.3"
+name = "packed_simd_2"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
+checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17"
dependencies = [
"cfg-if 0.1.10",
+ "libm",
]
[[package]]
[[package]]
name = "proc-macro2"
-version = "1.0.6"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
-[[package]]
-name = "quick-error"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
-
[[package]]
name = "quote"
version = "1.0.6"
]
[[package]]
-name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
-[[package]]
-name = "rand_os"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
-dependencies = [
- "cloudabi",
- "fuchsia-cprng",
- "libc",
- "rand_core 0.4.2",
- "rdrand",
- "winapi",
-]
-
-[[package]]
-name = "rdrand"
-version = "0.4.0"
+name = "redox_syscall"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
dependencies = [
- "rand_core 0.3.1",
+ "bitflags",
]
-[[package]]
-name = "redox_syscall"
-version = "0.1.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
-
[[package]]
name = "redox_users"
-version = "0.3.1"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
- "failure",
- "rand_os",
+ "getrandom",
"redox_syscall",
- "rust-argon2",
]
[[package]]
name = "regex"
-version = "1.3.1"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
+checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
- "thread_local 0.3.6",
+ "thread_local",
]
[[package]]
name = "regex-syntax"
-version = "0.6.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
-
-[[package]]
-name = "rust-argon2"
-version = "0.5.1"
+version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
-dependencies = [
- "base64",
- "blake2b_simd",
- "crossbeam-utils 0.6.6",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rustc-workspace-hack"
[[package]]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
dependencies = [
"annotate-snippets",
"anyhow",
[[package]]
name = "semver"
-version = "0.9.0"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
dependencies = [
- "semver-parser",
"serde",
]
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
[[package]]
name = "serde"
-version = "1.0.101"
+version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.101"
+version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.41"
+version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
dependencies = [
"itoa",
"ryu",
[[package]]
name = "syn"
-version = "1.0.11"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
+checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
-[[package]]
-name = "synstructure"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
[[package]]
name = "term"
version = "0.6.1"
"syn",
]
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-dependencies = [
- "lazy_static",
-]
-
[[package]]
name = "thread_local"
version = "1.0.1"
"winapi-util",
]
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
[[package]]
name = "winapi"
version = "0.3.8"
[package]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"
generic-simd = ["bytecount/generic-simd"]
[dependencies]
-itertools = "0.8"
+itertools = "0.9"
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
term = "0.6"
diff = "0.1"
log = "0.4.14"
-env_logger = "0.6"
+env_logger = "0.8"
getopts = "0.2"
derive-new = "0.5"
-cargo_metadata = "0.8"
+cargo_metadata = "0.14"
bytecount = "0.6"
unicode-width = "0.1.5"
unicode_categories = "0.1.1"
dirs = "2.0.1"
-ignore = "0.4.11"
+ignore = "0.4.17"
annotate-snippets = { version = "0.8", features = ["color"] }
structopt = "0.3"
rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" }
## `disable_all_formatting`
-Don't reformat anything
+Don't reformat anything.
+
+Note that this option may be soft-deprecated in the future once the [ignore](#ignore) option is stabilized. Nightly toolchain users are encouraged to use [ignore](#ignore) instead when possible.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3388)
+- **Stable**: Yes
## `edition`
}
```
+## `format_generated_files`
+
+Format generated files. A file is considered generated
+if any of the first five lines contains `@generated` marker.
+
+- **Default value**: `false`
+- **Possible values**: `true`, `false`
+- **Stable**: No
+
## `format_macro_matchers`
Format the metavariable matching patterns in macros.
See also: [`tab_spaces`](#tab_spaces).
+## `hex_literal_case`
+
+Control the case of the letters in hexadecimal literal values
+
+- **Default value**: `Preserve`
+- **Possible values**: `Upper`, `Lower`
+- **Stable**: No
## `hide_parse_errors`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3380)
+- **Stable**: Yes
#### `false` (default):
#### `false`:
```rust
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum Bar {}
+
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[derive(Copy, Clone)]
How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
- **Default value**: `Preserve`
-- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`
+- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
- **Stable**: No
#### `Preserve` (default):
use qux::i;
```
+#### `One`:
+
+Merge all imports into a single `use` statement as long as they have the same visibility.
+
+```rust
+pub use foo::{x, y};
+use {
+ bar::{
+ a,
+ b::{self, f, g},
+ c,
+ d::e,
+ },
+ qux::{h, i},
+};
+```
+
## `merge_imports`
This option is deprecated. Use `imports_granularity = "Crate"` instead.
#![doc = "Example documentation"]
#[doc = "Example item documentation"]
+pub enum Bar {}
+
+/// Example item documentation
pub enum Foo {}
```
#### `false`:
```rust
fn main() {
+ (foo());
+
((((foo()))));
}
```
type Item = i32;
}
+
+impl Iterator for Dummy {
+ type Item = i32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
```
#### `true`
let x = 1;
let y = 2;
let z = 3;
- let a = Foo { x: x, y: y, z: z };
+ let a = Foo { x, y, z };
+ let b = Foo { x: x, y: y, z: z };
}
```
```rust
fn main() {
+ let lorem = ipsum.map(|dolor| dolor.sit())?;
+
let lorem = try!(ipsum.map(|dolor| dolor.sit()));
}
```
#### `false` (default):
```rust
+// Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+// sed do eiusmod tempor incididunt ut labore et dolore
+// magna aliqua. Ut enim ad minim veniam, quis nostrud
+// exercitation ullamco laboris nisi ut aliquip ex ea
+// commodo consequat.
+
// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
```
-# This is based on https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml
-# and modified (mainly removal of deployment) to suit rustfmt.
-
environment:
global:
PROJECT_NAME: rustfmt
- matrix:
- # Stable channel
- # - TARGET: i686-pc-windows-gnu
- # CHANNEL: stable
- # - TARGET: i686-pc-windows-msvc
- # CHANNEL: stable
- # - TARGET: x86_64-pc-windows-gnu
- # CHANNEL: stable
- # - TARGET: x86_64-pc-windows-msvc
- # CHANNEL: stable
- # Beta channel
- # - TARGET: i686-pc-windows-gnu
- # CHANNEL: beta
- # - TARGET: i686-pc-windows-msvc
- # CHANNEL: beta
- # - TARGET: x86_64-pc-windows-gnu
- # CHANNEL: beta
- # - TARGET: x86_64-pc-windows-msvc
- # CHANNEL: beta
- # Nightly channel
- - TARGET: i686-pc-windows-gnu
- CHANNEL: nightly
- - TARGET: i686-pc-windows-msvc
- CHANNEL: nightly
- - TARGET: x86_64-pc-windows-gnu
- CHANNEL: nightly
- - TARGET: x86_64-pc-windows-msvc
- CHANNEL: nightly
-
-# Install Rust and Cargo
-# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
-install:
- - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- - if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin
- - if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin
- - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
- - rustc -Vv
- - cargo -V
-# ???
build: false
test_script:
- - set CFG_RELEASE_CHANNEL=nightly
- - set CFG_RELEASE=nightly
- - cargo build --verbose
- - cargo test
- - cargo test -- --ignored
+ - echo Why does no one have access to delete me?
<html>
<head>
<meta name="viewport" content="width=device-width">
+ <title>Rustfmt</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
+ <script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<style>
@media (max-width: 767px) {
.searchCondition > div {
margin-right: 30px;
}
+ .header-link {
+ position: relative;
+ }
+ .header-link:hover::before {
+ position: absolute;
+ left: -2em;
+ padding-right: 0.5em;
+ content: '\2002\00a7\2002';
+ }
</style>
</head>
<body>
<label for="stable">stable: </label>
<input type="checkbox" id="stable" v-model="shouldStable">
</div>
+ <div>
+ <label for="viewVersion">version: </label>
+ <select name="viewVersion" id="viewVersion" v-model="viewVersion">
+ <option v-for="option in versionOptions" v-bind:value="option">
+ {{ option }}
+ </option>
+ </select>
+ </div>
</div>
<div v-html="aboutHtml"></div>
<div v-html="configurationAboutHtml"></div>
</article>
</div>
<script>
- const ConfigurationMdUrl = 'https://raw.githubusercontent.com/rust-lang/rustfmt/master/Configurations.md';
+ const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
+ const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
const UrlHash = window.location.hash.replace(/^#/, '');
+ const queryParams = new URLSearchParams(window.location.search);
+ const searchParam = queryParams.get('search');
+ const searchTerm = null !== searchParam ? searchParam : '';
+ const versionParam = queryParams.get('version');
+ const parseVersionParam = (version) => {
+ if (version === 'master') return 'master';
+ if (version.startsWith('v')) return version;
+ return `v${version}`;
+ };
+ const versionNumber = null !== versionParam ? parseVersionParam(versionParam) : 'master';
new Vue({
el: '#app',
- data() {
- const configurationDescriptions = [];
- configurationDescriptions.links = {};
- return {
- aboutHtml: '',
- configurationAboutHtml: '',
- searchCondition: UrlHash,
- configurationDescriptions,
- shouldStable: false
- }
+ data: {
+ aboutHtml: '',
+ configurationAboutHtml: '',
+ configurationDescriptions: [],
+ searchCondition: searchTerm,
+ shouldStable: false,
+ viewVersion: versionNumber,
+ oldViewVersion: undefined,
+ versionOptions: ['master'],
+ scrolledOnce: false,
},
- computed: {
- outputHtml() {
- const ast = this.configurationDescriptions
- .filter(({ head, text, stable }) => {
+ asyncComputed: {
+ async updateVersion() {
+ let latest;
+ try {
+ latest = (await axios.get(RustfmtLatestUrl)).data;
+ } catch(err) {
+ console.log(err);
+ return;
+ }
+ if (versionParam == null) {
+ this.viewVersion = latest.name;
+ }
+ },
+ async outputHtml() {
+ if (this.viewVersion !== this.oldViewVersion) {
+ const ConfigurationMdUrl =
+ `https://raw.githubusercontent.com/rust-lang/rustfmt/${this.viewVersion}/Configurations.md`;
+ let res;
+ try {
+ res = await axios.get(ConfigurationMdUrl).catch(e => { throw e });
+ } catch(e) {
+ this.handleReqFailure(e);
+ return;
+ }
+ const {
+ about,
+ configurationAbout,
+ configurationDescriptions
+ } = parseMarkdownAst(res.data);
+ this.aboutHtml = marked.parser(about);
+ this.configurationAboutHtml = marked.parser(configurationAbout);
+ this.configurationDescriptions = configurationDescriptions;
+ this.oldViewVersion = this.viewVersion;
+ }
- if (
- text.includes(this.searchCondition) === false &&
- head.includes(this.searchCondition) === false
- ) {
- return false;
- }
- return (this.shouldStable)
- ? stable === true
- : true;
- })
- .reduce((stack, { value }) => {
- return stack.concat(value);
- }, []);
+ const ast = this.configurationDescriptions
+ .filter(({ head, text, stable }) => {
+ if (text.includes(this.searchCondition) === false &&
+ head.includes(this.searchCondition) === false) {
+ return false;
+ }
+ return (this.shouldStable)
+ ? stable === true
+ : true;
+ })
+ .reduce((stack, { value }) => {
+ return stack.concat(value);
+ }, []);
ast.links = {};
- return marked.parser(ast);
+
+ queryParams.set('version', this.viewVersion);
+ queryParams.set('search', this.searchCondition);
+ const curUrl = window.location.pathname +
+ '?' + queryParams.toString() + window.location.hash;
+ history.pushState(null, '', curUrl);
+
+ const renderer = new marked.Renderer();
+ renderer.heading = function(text, level) {
+ const id = htmlToId(text);
+ return `<h${level}>
+ <a id="${id}" href="#${id}" name="${id}" class="header-link">${text}</a>
+ </h${level}>`;
+ };
+
+ return marked.parser(ast, {
+ highlight(code, lang) {
+ return hljs.highlight(lang ? lang : 'rust', code).value;
+ },
+ headerIds: true,
+ headerPrefix: '',
+ renderer,
+ });
}
},
created: async function() {
- const res = await axios.get(ConfigurationMdUrl);
- const {
- about,
- configurationAbout,
- configurationDescriptions
- } = parseMarkdownAst(res.data);
- this.aboutHtml = marked.parser(about);
- this.configurationAboutHtml = marked.parser(configurationAbout);
- this.configurationDescriptions = configurationDescriptions;
+ let tags;
+ try {
+ tags = (await axios.get(RusfmtTagsUrl)).data;
+ } catch(e) {
+ this.handleReqFailure(e);
+ return;
+ }
+
+ const excludedTagVersions = new Set(['v0.7', 'v0.8.1']);
+
+ const tagOptions = tags
+ .map(tag => tag.name)
+ .filter(tag => tag.startsWith('v') && !excludedTagVersions.has(tag));
+ this.versionOptions = this.versionOptions.concat(tagOptions);
},
- mounted() {
+ updated() {
if (UrlHash === '') return;
- const interval = setInterval(() => {
+ this.$nextTick(() => {
const target = document.querySelector(`#${UrlHash}`);
- if (target != null) {
+ if (target != null && !this.scrolledOnce) {
target.scrollIntoView(true);
- clearInterval(interval);
+ this.scrolledOnce = true;
}
- }, 100);
+ });
+ },
+ methods: {
+ handleReqFailure(e) {
+ if (e.response.status === 404) {
+ this.aboutHtml =
+ "<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
+ } else if (
+ e.response.status === 403 &&
+ e.response.headers["X-RateLimit-Remaining"] === 0
+ ) {
+ const resetDate = new Date(
+ e.response.headers['X-RateLimit-Reset'] * 1000
+ ).toLocaleString();
+ this.aboutHtml =
+ `<p>You have hit the GitHub API rate limit; documentation cannot be updated.` +
+ `<p>The rate limit will be reset at ${resetDate}.</p>`;
+ } else {
+ this.aboutHtml =
+ `<p>Ecountered an error when fetching documentation data:</p>` +
+ `<pre><code>${e.response.data}</code></pre>` +
+ `<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
+ `<p>Try refreshing the page.</p>`;
+ }
+ }
}
});
const extractDepthOnes = (ast) => {
head: val[0].text,
value: val,
stable: val.some((elem) => {
- return !!elem.text && elem.text.includes("**Stable**: Yes")
+ return elem.type === "list" &&
+ !!elem.raw &&
+ elem.raw.includes("**Stable**: Yes");
}),
text: val.reduce((result, next) => {
return next.text != null
configurationDescriptions
};
}
+ function htmlToId(text) {
+ const tmpl = document.createElement('template');
+ tmpl.innerHTML = text.trim();
+ return encodeURIComponent(CSS.escape(tmpl.content.textContent));
+ }
</script>
</body>
-</html>
\ No newline at end of file
+</html>
[toolchain]
-channel = "nightly-2021-07-23"
+channel = "nightly-2021-10-20"
components = ["rustc-dev"]
use crate::overflow;
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
+use crate::source_map::SpanUtils;
use crate::types::{rewrite_path, PathContext};
use crate::utils::{count_newlines, mk_sp};
|span| span.lo(),
|span| span.hi(),
|span| Some(context.snippet(*span).to_owned()),
- attr.span.lo(),
+ // We update derive attribute spans to start after the opening '('
+ // This helps us focus parsing to just what's inside #[derive(...)]
+ context.snippet_provider.span_after(attr.span, "("),
attr.span.hi(),
false,
);
found reverts to the input file path",
"[Path for the configuration file]",
);
- opts.optopt("", "edition", "Rust edition to use", "[2015|2018]");
+ opts.optopt("", "edition", "Rust edition to use", "[2015|2018|2021]");
opts.optopt(
"",
"color",
use structopt::StructOpt;
+#[path = "test/mod.rs"]
+#[cfg(test)]
+mod cargo_fmt_tests;
+
#[derive(StructOpt, Debug)]
#[structopt(
bin_name = "cargo fmt",
#[structopt(long = "version")]
version: bool,
- /// Specify package to format (only usable in workspaces)
+ /// Specify package to format
#[structopt(short = "p", long = "package", value_name = "package")]
packages: Vec<String>,
#[structopt(name = "rustfmt_options", raw(true))]
rustfmt_options: Vec<String>,
- /// Format all packages (only usable in workspaces)
+ /// Format all packages, and also their local path-based dependencies
#[structopt(long = "all")]
format_all: bool,
+
+ /// Run rustfmt in check mode
+ #[structopt(long = "check")]
+ check: bool,
}
fn main() {
let strategy = CargoFmtStrategy::from_opts(&opts);
let mut rustfmt_args = opts.rustfmt_options;
+ if opts.check {
+ let check_flag = "--check";
+ if !rustfmt_args.iter().any(|o| o == check_flag) {
+ rustfmt_args.push(check_flag.to_owned());
+ }
+ }
if let Some(message_format) = opts.message_format {
if let Err(msg) = convert_message_format_to_rustfmt_args(&message_format, &mut rustfmt_args)
{
manifest_path: Option<&Path>,
targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
+ let metadata = get_cargo_metadata(manifest_path)?;
let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path {
(
mut targets: &mut BTreeSet<Target>,
visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
- let metadata_with_deps = get_cargo_metadata(manifest_path, true)?;
-
- for package in metadata.packages {
+ let metadata = get_cargo_metadata(manifest_path)?;
+ for package in &metadata.packages {
add_targets(&package.targets, &mut targets);
- // Look for local dependencies.
- for dependency in package.dependencies {
- if dependency.source.is_some() || visited.contains(&dependency.name) {
+ // Look for local dependencies using information available since cargo v1.51
+ // It's theoretically possible someone could use a newer version of rustfmt with
+ // a much older version of `cargo`, but we don't try to explicitly support that scenario.
+ // If someone reports an issue with path-based deps not being formatted, be sure to
+ // confirm their version of `cargo` (not `cargo-fmt`) is >= v1.51
+ // https://github.com/rust-lang/cargo/pull/8994
+ for dependency in &package.dependencies {
+ if dependency.path.is_none() || visited.contains(&dependency.name) {
continue;
}
- let dependency_package = metadata_with_deps
- .packages
- .iter()
- .find(|p| p.name == dependency.name && p.source.is_none());
- let manifest_path = if let Some(dep_pkg) = dependency_package {
- PathBuf::from(&dep_pkg.manifest_path)
- } else {
- let mut package_manifest_path = PathBuf::from(&package.manifest_path);
- package_manifest_path.pop();
- package_manifest_path.push(&dependency.name);
- package_manifest_path.push("Cargo.toml");
- package_manifest_path
- };
-
- if manifest_path.exists() {
- visited.insert(dependency.name);
+ let manifest_path = PathBuf::from(dependency.path.as_ref().unwrap()).join("Cargo.toml");
+ if manifest_path.exists()
+ && !metadata
+ .packages
+ .iter()
+ .any(|p| p.manifest_path.eq(&manifest_path))
+ {
+ visited.insert(dependency.name.to_owned());
get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
}
}
hitlist: &[String],
targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
-
+ let metadata = get_cargo_metadata(manifest_path)?;
let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);
for package in metadata.packages {
.unwrap_or(SUCCESS))
}
-fn get_cargo_metadata(
- manifest_path: Option<&Path>,
- include_deps: bool,
-) -> Result<cargo_metadata::Metadata, io::Error> {
+fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
let mut cmd = cargo_metadata::MetadataCommand::new();
- if !include_deps {
- cmd.no_deps();
- }
+ cmd.no_deps();
if let Some(manifest_path) = manifest_path {
cmd.manifest_path(manifest_path);
}
- cmd.other_options(&[String::from("--offline")]);
+ cmd.other_options(vec![String::from("--offline")]);
match cmd.exec() {
Ok(metadata) => Ok(metadata),
}
}
}
-
-#[cfg(test)]
-mod cargo_fmt_tests {
- use super::*;
-
- #[test]
- fn default_options() {
- let empty: Vec<String> = vec![];
- let o = Opts::from_iter(&empty);
- assert_eq!(false, o.quiet);
- assert_eq!(false, o.verbose);
- assert_eq!(false, o.version);
- assert_eq!(empty, o.packages);
- assert_eq!(empty, o.rustfmt_options);
- assert_eq!(false, o.format_all);
- assert_eq!(None, o.manifest_path);
- assert_eq!(None, o.message_format);
- }
-
- #[test]
- fn good_options() {
- let o = Opts::from_iter(&[
- "test",
- "-q",
- "-p",
- "p1",
- "-p",
- "p2",
- "--message-format",
- "short",
- "--",
- "--edition",
- "2018",
- ]);
- assert_eq!(true, o.quiet);
- assert_eq!(false, o.verbose);
- assert_eq!(false, o.version);
- assert_eq!(vec!["p1", "p2"], o.packages);
- assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
- assert_eq!(false, o.format_all);
- assert_eq!(Some(String::from("short")), o.message_format);
- }
-
- #[test]
- fn unexpected_option() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "unexpected"])
- .is_err()
- );
- }
-
- #[test]
- fn unexpected_flag() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "--flag"])
- .is_err()
- );
- }
-
- #[test]
- fn mandatory_separator() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "--check"])
- .is_err()
- );
- assert!(
- !Opts::clap()
- .get_matches_from_safe(&["test", "--", "--check"])
- .is_err()
- );
- }
-
- #[test]
- fn multiple_packages_one_by_one() {
- let o = Opts::from_iter(&[
- "test",
- "-p",
- "package1",
- "--package",
- "package2",
- "-p",
- "package3",
- ]);
- assert_eq!(3, o.packages.len());
- }
-
- #[test]
- fn multiple_packages_grouped() {
- let o = Opts::from_iter(&[
- "test",
- "--package",
- "package1",
- "package2",
- "-p",
- "package3",
- "package4",
- ]);
- assert_eq!(4, o.packages.len());
- }
-
- #[test]
- fn empty_packages_1() {
- assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
- }
-
- #[test]
- fn empty_packages_2() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--", "--check"])
- .is_err()
- );
- }
-
- #[test]
- fn empty_packages_3() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--verbose"])
- .is_err()
- );
- }
-
- #[test]
- fn empty_packages_4() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--check"])
- .is_err()
- );
- }
-
- mod convert_message_format_to_rustfmt_args_tests {
- use super::*;
-
- #[test]
- fn invalid_message_format() {
- assert_eq!(
- convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
- Err(String::from(
- "invalid --message-format value: awesome. Allowed values are: short|json|human"
- )),
- );
- }
-
- #[test]
- fn json_message_format_and_check_arg() {
- let mut args = vec![String::from("--check")];
- assert_eq!(
- convert_message_format_to_rustfmt_args("json", &mut args),
- Err(String::from(
- "cannot include --check arg when --message-format is set to json"
- )),
- );
- }
-
- #[test]
- fn json_message_format_and_emit_arg() {
- let mut args = vec![String::from("--emit"), String::from("checkstyle")];
- assert_eq!(
- convert_message_format_to_rustfmt_args("json", &mut args),
- Err(String::from(
- "cannot include --emit arg when --message-format is set to json"
- )),
- );
- }
-
- #[test]
- fn json_message_format() {
- let mut args = vec![String::from("--edition"), String::from("2018")];
- assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
- assert_eq!(
- args,
- vec![
- String::from("--edition"),
- String::from("2018"),
- String::from("--emit"),
- String::from("json")
- ]
- );
- }
-
- #[test]
- fn human_message_format() {
- let exp_args = vec![String::from("--emit"), String::from("json")];
- let mut act_args = exp_args.clone();
- assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
- assert_eq!(act_args, exp_args);
- }
-
- #[test]
- fn short_message_format() {
- let mut args = vec![String::from("--check")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
- }
-
- #[test]
- fn short_message_format_included_short_list_files_flag() {
- let mut args = vec![String::from("--check"), String::from("-l")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
- }
-
- #[test]
- fn short_message_format_included_long_list_files_flag() {
- let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(
- args,
- vec![String::from("--check"), String::from("--files-with-diff")]
- );
- }
- }
-}
--- /dev/null
+use super::*;
+
+#[test]
+fn invalid_message_format() {
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
+ Err(String::from(
+ "invalid --message-format value: awesome. Allowed values are: short|json|human"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format_and_check_arg() {
+ let mut args = vec![String::from("--check")];
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("json", &mut args),
+ Err(String::from(
+ "cannot include --check arg when --message-format is set to json"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format_and_emit_arg() {
+ let mut args = vec![String::from("--emit"), String::from("checkstyle")];
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("json", &mut args),
+ Err(String::from(
+ "cannot include --emit arg when --message-format is set to json"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format() {
+ let mut args = vec![String::from("--edition"), String::from("2018")];
+ assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
+ assert_eq!(
+ args,
+ vec![
+ String::from("--edition"),
+ String::from("2018"),
+ String::from("--emit"),
+ String::from("json")
+ ]
+ );
+}
+
+#[test]
+fn human_message_format() {
+ let exp_args = vec![String::from("--emit"), String::from("json")];
+ let mut act_args = exp_args.clone();
+ assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
+ assert_eq!(act_args, exp_args);
+}
+
+#[test]
+fn short_message_format() {
+ let mut args = vec![String::from("--check")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_short_list_files_flag() {
+ let mut args = vec![String::from("--check"), String::from("-l")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_long_list_files_flag() {
+ let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(
+ args,
+ vec![String::from("--check"), String::from("--files-with-diff")]
+ );
+}
--- /dev/null
+use super::*;
+
+mod message_format;
+mod targets;
+
+#[test]
+fn default_options() {
+ let empty: Vec<String> = vec![];
+ let o = Opts::from_iter(&empty);
+ assert_eq!(false, o.quiet);
+ assert_eq!(false, o.verbose);
+ assert_eq!(false, o.version);
+ assert_eq!(false, o.check);
+ assert_eq!(empty, o.packages);
+ assert_eq!(empty, o.rustfmt_options);
+ assert_eq!(false, o.format_all);
+ assert_eq!(None, o.manifest_path);
+ assert_eq!(None, o.message_format);
+}
+
+#[test]
+fn good_options() {
+ let o = Opts::from_iter(&[
+ "test",
+ "-q",
+ "-p",
+ "p1",
+ "-p",
+ "p2",
+ "--message-format",
+ "short",
+ "--check",
+ "--",
+ "--edition",
+ "2018",
+ ]);
+ assert_eq!(true, o.quiet);
+ assert_eq!(false, o.verbose);
+ assert_eq!(false, o.version);
+ assert_eq!(true, o.check);
+ assert_eq!(vec!["p1", "p2"], o.packages);
+ assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
+ assert_eq!(false, o.format_all);
+ assert_eq!(Some(String::from("short")), o.message_format);
+}
+
+#[test]
+fn unexpected_option() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "unexpected"])
+ .is_err()
+ );
+}
+
+#[test]
+fn unexpected_flag() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "--flag"])
+ .is_err()
+ );
+}
+
+#[test]
+fn mandatory_separator() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "--emit"])
+ .is_err()
+ );
+ assert!(
+ !Opts::clap()
+ .get_matches_from_safe(&["test", "--", "--emit"])
+ .is_err()
+ );
+}
+
+#[test]
+fn multiple_packages_one_by_one() {
+ let o = Opts::from_iter(&[
+ "test",
+ "-p",
+ "package1",
+ "--package",
+ "package2",
+ "-p",
+ "package3",
+ ]);
+ assert_eq!(3, o.packages.len());
+}
+
+#[test]
+fn multiple_packages_grouped() {
+ let o = Opts::from_iter(&[
+ "test",
+ "--package",
+ "package1",
+ "package2",
+ "-p",
+ "package3",
+ "package4",
+ ]);
+ assert_eq!(4, o.packages.len());
+}
+
+#[test]
+fn empty_packages_1() {
+ assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
+}
+
+#[test]
+fn empty_packages_2() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--", "--check"])
+ .is_err()
+ );
+}
+
+#[test]
+fn empty_packages_3() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--verbose"])
+ .is_err()
+ );
+}
+
+#[test]
+fn empty_packages_4() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--check"])
+ .is_err()
+ );
+}
--- /dev/null
+use super::*;
+
+struct ExpTarget {
+ path: &'static str,
+ edition: &'static str,
+ kind: &'static str,
+}
+
+mod all_targets {
+ use super::*;
+
+ fn assert_correct_targets_loaded(
+ manifest_suffix: &str,
+ source_root: &str,
+ exp_targets: &[ExpTarget],
+ exp_num_targets: usize,
+ ) {
+ let root_path = Path::new("tests/cargo-fmt/source").join(source_root);
+ let get_path = |exp: &str| PathBuf::from(&root_path).join(exp).canonicalize().unwrap();
+ let manifest_path = Path::new(&root_path).join(manifest_suffix);
+ let targets = get_targets(&CargoFmtStrategy::All, Some(manifest_path.as_path()))
+ .expect("Targets should have been loaded");
+
+ assert_eq!(targets.len(), exp_num_targets);
+
+ for target in exp_targets {
+ assert!(targets.contains(&Target {
+ path: get_path(target.path),
+ edition: target.edition.to_owned(),
+ kind: target.kind.to_owned(),
+ }));
+ }
+ }
+
+ mod different_crate_and_dir_names {
+ use super::*;
+
+ fn assert_correct_targets_loaded(manifest_suffix: &str) {
+ let exp_targets = vec![
+ ExpTarget {
+ path: "dependency-dir-name/subdep-dir-name/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "dependency-dir-name/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "src/main.rs",
+ edition: "2018",
+ kind: "main",
+ },
+ ];
+ super::assert_correct_targets_loaded(
+ manifest_suffix,
+ "divergent-crate-dir-names",
+ &exp_targets,
+ 3,
+ );
+ }
+
+ #[test]
+ fn correct_targets_from_root() {
+ assert_correct_targets_loaded("Cargo.toml");
+ }
+
+ #[test]
+ fn correct_targets_from_sub_local_dep() {
+ assert_correct_targets_loaded("dependency-dir-name/Cargo.toml");
+ }
+ }
+
+ mod workspaces {
+ use super::*;
+
+ fn assert_correct_targets_loaded(manifest_suffix: &str) {
+ let exp_targets = vec![
+ ExpTarget {
+ path: "ws/a/src/main.rs",
+ edition: "2018",
+ kind: "bin",
+ },
+ ExpTarget {
+ path: "ws/b/src/main.rs",
+ edition: "2018",
+ kind: "bin",
+ },
+ ExpTarget {
+ path: "ws/c/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "ws/a/d/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "e/src/main.rs",
+ edition: "2018",
+ kind: "main",
+ },
+ ExpTarget {
+ path: "ws/a/d/f/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ];
+ super::assert_correct_targets_loaded(
+ manifest_suffix,
+ "workspaces/path-dep-above",
+ &exp_targets,
+ 6,
+ );
+ }
+
+ #[test]
+ fn includes_outside_workspace_deps() {
+ assert_correct_targets_loaded("ws/Cargo.toml");
+ }
+
+ #[test]
+ fn includes_workspace_from_dep_above() {
+ assert_correct_targets_loaded("e/Cargo.toml");
+ }
+
+ #[test]
+ fn includes_all_packages_from_workspace_subdir() {
+ assert_correct_targets_loaded("ws/a/d/f/Cargo.toml");
+ }
+ }
+}
use crate::shape::{Indent, Shape};
use crate::string::{rewrite_string, StringFormat};
use crate::utils::{
- count_newlines, first_line_width, last_line_width, trim_left_preserve_layout, unicode_str_width,
+ count_newlines, first_line_width, last_line_width, trim_left_preserve_layout,
+ trimmed_last_line_width, unicode_str_width,
};
use crate::{ErrorKind, FormattingError};
String::with_capacity(prev_str.len() + next_str.len() + shape.indent.width() + 128);
result.push_str(prev_str);
let mut allow_one_line = !prev_str.contains('\n') && !next_str.contains('\n');
- let first_sep = if prev_str.is_empty() || next_str.is_empty() {
- ""
- } else {
- " "
- };
+ let first_sep =
+ if prev_str.is_empty() || next_str.is_empty() || trimmed_last_line_width(prev_str) == 0 {
+ ""
+ } else {
+ " "
+ };
let mut one_line_width =
last_line_width(prev_str) + first_line_width(next_str) + first_sep.len();
let missing_comment = rewrite_missing_comment(span, shape, context)?;
if missing_comment.is_empty() {
- if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width {
+ if allow_extend && one_line_width <= shape.width {
result.push_str(first_sep);
} else if !prev_str.is_empty() {
result.push_str(&indent.to_string_with_newline(config))
}
}
-/// Attributes for code blocks in rustdoc.
-/// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>.
+/// Enum indicating if the code block contains rust based on attributes
enum CodeBlockAttribute {
Rust,
- Ignore,
- Text,
- ShouldPanic,
- NoRun,
- CompileFail,
+ NotRust,
}
impl CodeBlockAttribute {
- fn new(attribute: &str) -> CodeBlockAttribute {
- match attribute {
- "rust" | "" => CodeBlockAttribute::Rust,
- "ignore" => CodeBlockAttribute::Ignore,
- "text" => CodeBlockAttribute::Text,
- "should_panic" => CodeBlockAttribute::ShouldPanic,
- "no_run" => CodeBlockAttribute::NoRun,
- "compile_fail" => CodeBlockAttribute::CompileFail,
- _ => CodeBlockAttribute::Text,
+ /// Parse comma separated attributes list. Return rust only if all
+ /// attributes are valid rust attributes
+ /// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>
+ fn new(attributes: &str) -> CodeBlockAttribute {
+ for attribute in attributes.split(",") {
+ match attribute.trim() {
+ "" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018"
+ | "edition2021" => (),
+ "ignore" | "compile_fail" | "text" => return CodeBlockAttribute::NotRust,
+ _ => return CodeBlockAttribute::NotRust,
+ }
}
+ CodeBlockAttribute::Rust
}
}
} else if self.code_block_attr.is_some() {
if line.starts_with("```") {
let code_block = match self.code_block_attr.as_ref().unwrap() {
- CodeBlockAttribute::Ignore | CodeBlockAttribute::Text => {
- trim_custom_comment_prefix(&self.code_block_buffer)
- }
- _ if self.code_block_buffer.is_empty() => String::new(),
- _ => {
+ CodeBlockAttribute::Rust
+ if self.fmt.config.format_code_in_doc_comments()
+ && !self.code_block_buffer.is_empty() =>
+ {
let mut config = self.fmt.config.clone();
config.set().wrap_comments(false);
- if config.format_code_in_doc_comments() {
- if let Some(s) =
- crate::format_code_block(&self.code_block_buffer, &config, false)
- {
- trim_custom_comment_prefix(&s.snippet)
- } else {
- trim_custom_comment_prefix(&self.code_block_buffer)
- }
+ if let Some(s) =
+ crate::format_code_block(&self.code_block_buffer, &config, false)
+ {
+ trim_custom_comment_prefix(&s.snippet)
} else {
trim_custom_comment_prefix(&self.code_block_buffer)
}
}
+ _ => trim_custom_comment_prefix(&self.code_block_buffer),
};
if !code_block.is_empty() {
self.result.push_str(&self.comment_line_separator);
format_macro_matchers: bool, false, false,
"Format the metavariable matching patterns in macros";
format_macro_bodies: bool, true, false, "Format the bodies of macros";
+ hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
+ "Format hexadecimal integer literals";
// Single line expressions and items
empty_item_single_line: bool, true, false,
"Add trailing semicolon after break, continue and return";
trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
"How to handle trailing commas for lists";
- match_block_trailing_comma: bool, false, false,
+ match_block_trailing_comma: bool, false, true,
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
blank_lines_upper_bound: usize, 1, false,
"Maximum number of blank lines which can be put between items";
inline_attribute_width: usize, 0, false,
"Write an item and its attribute on the same line \
if their combined width is below a threshold";
+ format_generated_files: bool, false, false, "Format generated files";
// Options that can change the source code beyond whitespace/blocks (somewhat linty things)
merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
"Require a specific version of rustfmt";
unstable_features: bool, false, false,
"Enables unstable features. Only available on nightly channel";
- disable_all_formatting: bool, false, false, "Don't reformat anything";
+ disable_all_formatting: bool, false, true, "Don't reformat anything";
skip_children: bool, false, false, "Don't reformat out of line modules";
hide_parse_errors: bool, false, false, "Hide errors from the parser";
error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width";
format_strings = false
format_macro_matchers = false
format_macro_bodies = true
+hex_literal_case = "Preserve"
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
edition = "2015"
version = "One"
inline_attribute_width = 0
+format_generated_files = false
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
Module,
/// Use one `use` statement per imported item.
Item,
+ /// Use one `use` statement including all items.
+ One,
+}
+
+/// Controls how rustfmt should handle case in hexadecimal literals.
+#[config_type]
+pub enum HexLiteralCase {
+ /// Leave the literal as-is
+ Preserve,
+ /// Ensure all literals use uppercase lettering
+ Upper,
+ /// Ensure all literals use lowercase lettering
+ Lower,
}
#[config_type]
rewrite_missing_comment, CharClasses, FindUncommented,
};
use crate::config::lists::*;
-use crate::config::{Config, ControlBraceStyle, IndentStyle, Version};
+use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version};
use crate::lists::{
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
struct_lit_tactic, write_list, ListFormatting, Separator,
let pat_string = pat.rewrite(context, pat_shape)?;
let comments_lo = context
.snippet_provider
- .span_after(self.span, self.connector.trim());
+ .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
let comments_span = mk_sp(comments_lo, expr.span.lo());
return rewrite_assign_rhs_with_comments(
context,
) -> Option<String> {
match l.kind {
ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
+ ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape),
_ => wrap_str(
context.snippet(l.span).to_owned(),
context.config.max_width(),
)
}
+fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
+ let span = lit.span;
+ let symbol = lit.token.symbol.as_str();
+
+ if symbol.starts_with("0x") {
+ let hex_lit = match context.config.hex_literal_case() {
+ HexLiteralCase::Preserve => None,
+ HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()),
+ HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()),
+ };
+ if let Some(hex_lit) = hex_lit {
+ return wrap_str(
+ format!(
+ "0x{}{}",
+ hex_lit,
+ lit.token.suffix.map_or(String::new(), |s| s.to_string())
+ ),
+ context.config.max_width(),
+ shape,
+ );
+ }
+ }
+
+ wrap_str(
+ context.snippet(span).to_owned(),
+ context.config.max_width(),
+ shape,
+ )
+}
+
fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
if context.inside_macro() {
if span_ends_with_comma(context, span) {
let path_shape = shape.sub_width(2)?;
let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
- let has_base = match struct_rest {
+ let has_base_or_rest = match struct_rest {
ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
ast::StructRest::Rest(_) if fields.is_empty() => {
return Some(format!("{} {{ .. }}", path_str));
}
- ast::StructRest::Base(_) => true,
+ ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
_ => false,
};
let one_line_width = h_shape.map_or(0, |shape| shape.width);
let body_lo = context.snippet_provider.span_after(span, "{");
- let fields_str = if struct_lit_can_be_aligned(fields, has_base)
+ let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
&& context.config.struct_field_align_threshold() > 0
{
rewrite_with_alignment(
nested_shape,
tactic,
context,
- force_no_trailing_comma
- || has_base
- || !context.use_block_indent()
- || matches!(struct_rest, ast::StructRest::Rest(_)),
+ force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
);
write_list(&item_vec, &fmt)?
use self::newline_style::apply_newline_style;
use crate::comment::{CharClasses, FullCodeCharKind};
use crate::config::{Config, FileName, Verbosity};
+use crate::formatting::generated::is_generated_file;
use crate::issues::BadIssueSeeker;
use crate::modules::Module;
use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
use crate::visitor::FmtVisitor;
use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
+mod generated;
mod newline_style;
// A map of the files of a crate, with their new content
context.parse_session.set_silent_emitter();
for (path, module) in files {
- let should_ignore = !input_is_stdin && context.ignore_file(&path);
+ let source_file = context.parse_session.span_to_file_contents(module.span);
+ let src = source_file.src.as_ref().expect("SourceFile without src");
+
+ let should_ignore = (!input_is_stdin && context.ignore_file(&path))
+ || (!config.format_generated_files() && is_generated_file(src));
+
if (config.skip_children() && path != main_file) || should_ignore {
continue;
}
--- /dev/null
+/// Returns `true` if the given span is a part of generated files.
+pub(super) fn is_generated_file(original_snippet: &str) -> bool {
+ original_snippet
+ .lines()
+ .take(5) // looking for marker only in the beginning of the file
+ .any(|line| line.contains("@generated"))
+}
}
}
+ // Check if self == other with their aliases removed.
+ fn equal_except_alias(&self, other: &Self) -> bool {
+ match (self, other) {
+ (UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2,
+ (UseSegment::Slf(_), UseSegment::Slf(_))
+ | (UseSegment::Super(_), UseSegment::Super(_))
+ | (UseSegment::Crate(_), UseSegment::Crate(_))
+ | (UseSegment::Glob, UseSegment::Glob) => true,
+ (UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2,
+ _ => false,
+ }
+ }
+
+ fn get_alias(&self) -> Option<&str> {
+ match self {
+ UseSegment::Ident(_, a)
+ | UseSegment::Slf(a)
+ | UseSegment::Super(a)
+ | UseSegment::Crate(a) => a.as_deref(),
+ _ => None,
+ }
+ }
+
fn from_path_segment(
context: &RewriteContext<'_>,
path_seg: &ast::PathSegment,
SharedPrefix::Module => {
self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
}
+ SharedPrefix::One => true,
}
}
}
fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
let mut prefix = 0;
for (a, b) in self.path.iter().zip(other.path.iter()) {
- if *a == *b {
+ if a.equal_except_alias(b) {
prefix += 1;
} else {
break;
return Some(new_path);
}
} else if len == 1 {
- let rest = if a.len() == len { &b[1..] } else { &a[1..] };
- return Some(vec![
- b[0].clone(),
- UseSegment::List(vec![
- UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
- UseTree::from_path(rest.to_vec(), DUMMY_SP),
- ]),
- ]);
+ let (common, rest) = if a.len() == len {
+ (&a[0], &b[1..])
+ } else {
+ (&b[0], &a[1..])
+ };
+ let mut list = vec![UseTree::from_path(
+ vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))],
+ DUMMY_SP,
+ )];
+ match rest {
+ [UseSegment::List(rest_list)] => list.extend(rest_list.clone()),
+ _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
+ }
+ return Some(vec![b[0].clone(), UseSegment::List(list)]);
} else {
len -= 1;
}
}
fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
- let similar_trees = trees
- .iter_mut()
- .filter(|tree| tree.share_prefix(&use_tree, merge_by));
+ struct SimilarTree<'a> {
+ similarity: usize,
+ path_len: usize,
+ tree: &'a mut UseTree,
+ }
+
+ let similar_trees = trees.iter_mut().filter_map(|tree| {
+ if tree.share_prefix(&use_tree, merge_by) {
+ // In the case of `SharedPrefix::One`, `similarity` is used for deciding with which
+ // tree `use_tree` should be merge.
+ // In other cases `similarity` won't be used, so set it to `0` as a dummy value.
+ let similarity = if merge_by == SharedPrefix::One {
+ tree.path
+ .iter()
+ .zip(&use_tree.path)
+ .take_while(|(a, b)| a.equal_except_alias(b))
+ .count()
+ } else {
+ 0
+ };
+
+ let path_len = tree.path.len();
+ Some(SimilarTree {
+ similarity,
+ tree,
+ path_len,
+ })
+ } else {
+ None
+ }
+ });
+
if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
- if let Some(tree) = similar_trees.min_by_key(|tree| tree.path.len()) {
- if tree.path.len() == 1 {
+ if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) {
+ if tree.path_len == 1 {
+ return;
+ }
+ }
+ } else if merge_by == SharedPrefix::One {
+ if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) {
+ if sim_tree.similarity > 0 {
+ sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
- } else if let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
- if tree.path.len() > 1 {
- tree.merge(&use_tree, merge_by);
+ } else if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.path_len) {
+ if sim_tree.path_len > 1 {
+ sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
pub(crate) enum SharedPrefix {
Crate,
Module,
+ One,
}
#[cfg(test)]
}
fn eat(&mut self, c: char) {
- assert!(self.input.next().unwrap() == c);
+ assert_eq!(self.input.next().unwrap(), c);
}
fn push_segment(
);
}
+ #[test]
+ fn test_use_tree_merge_one() {
+ test_merge!(One, ["a", "b"], ["{a, b}"]);
+
+ test_merge!(One, ["a::{aa, ab}", "b", "a"], ["{a::{self, aa, ab}, b}"]);
+
+ test_merge!(One, ["a as x", "b as y"], ["{a as x, b as y}"]);
+
+ test_merge!(
+ One,
+ ["a::{aa as xa, ab}", "b", "a"],
+ ["{a::{self, aa as xa, ab}, b}"]
+ );
+
+ test_merge!(
+ One,
+ ["a", "a::{aa, ab::{aba, abb}}"],
+ ["a::{self, aa, ab::{aba, abb}}"]
+ );
+
+ test_merge!(One, ["a", "b::{ba, *}"], ["{a, b::{ba, *}}"]);
+
+ test_merge!(One, ["a", "b", "a::aa"], ["{a::{self, aa}, b}"]);
+
+ test_merge!(
+ One,
+ ["a::aa::aaa", "a::ac::aca", "a::aa::*"],
+ ["a::{aa::{aaa, *}, ac::aca}"]
+ );
+
+ test_merge!(
+ One,
+ ["a", "b::{ba, bb}", "a::{aa::*, ab::aba}"],
+ ["{a::{self, aa::*, ab::aba}, b::{ba, bb}}"]
+ );
+
+ test_merge!(
+ One,
+ ["b", "a::ac::{aca, acb}", "a::{aa::*, ab}"],
+ ["{a::{aa::*, ab, ac::{aca, acb}}, b}"]
+ );
+ }
+
#[test]
fn test_flatten_use_trees() {
assert_eq!(
constness: ast::Const,
defaultness: ast::Defaultness,
unsafety: ast::Unsafe,
- visibility: ast::Visibility,
+ visibility: &'a ast::Visibility,
}
impl<'a> FnSig<'a> {
pub(crate) fn from_method_sig(
method_sig: &'a ast::FnSig,
generics: &'a ast::Generics,
- visibility: ast::Visibility,
+ visibility: &'a ast::Visibility,
) -> FnSig<'a> {
FnSig {
unsafety: method_sig.header.unsafety,
match *fn_kind {
visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
visit::FnCtxt::Assoc(..) => {
- let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis.clone());
+ let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
fn_sig.defaultness = defaultness;
fn_sig
}
is_async: Cow::Borrowed(&fn_sig.header.asyncness),
defaultness,
unsafety: fn_sig.header.unsafety,
- visibility: vis.clone(),
+ visibility: vis,
},
},
_ => unreachable!(),
indent: Indent,
ident: symbol::Ident,
sig: &ast::FnSig,
+ vis: &ast::Visibility,
generics: &ast::Generics,
span: Span,
) -> Option<String> {
&context,
indent,
ident,
- &FnSig::from_method_sig(sig, generics, DEFAULT_VISIBILITY),
+ &FnSig::from_method_sig(sig, generics, vis),
span,
FnBraceStyle::None,
)?;
format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
} else {
let shape = Shape::indented(offset, context.config).sub_width(1)?;
+ let lo = if let Some(generics) = struct_parts.generics {
+ generics.span.hi()
+ } else {
+ struct_parts.ident.span.hi()
+ };
result = overflow::rewrite_with_parens(
context,
&result,
fields.iter(),
shape,
- span,
+ mk_sp(lo, span.hi()),
context.config.fn_call_width(),
None,
)?;
Some(result)
}
-fn rewrite_type<R: Rewrite>(
+pub(crate) fn rewrite_type<R: Rewrite>(
context: &RewriteContext<'_>,
indent: Indent,
ident: symbol::Ident,
};
StaticParts {
prefix: "const",
- vis: &DEFAULT_VISIBILITY,
+ vis: &ti.vis,
ident: ti.ident,
ty,
mutability: ast::Mutability::Not,
Some(format!("{}{};", prefix, ty_str))
}
}
-
-pub(crate) fn rewrite_type_alias(
- ident: symbol::Ident,
- ty_opt: Option<&ptr::P<ast::Ty>>,
- generics: &ast::Generics,
- generic_bounds_opt: Option<&ast::GenericBounds>,
- context: &RewriteContext<'_>,
- indent: Indent,
- vis: &ast::Visibility,
- span: Span,
-) -> Option<String> {
- rewrite_type(
- context,
- indent,
- ident,
- vis,
- generics,
- generic_bounds_opt,
- ty_opt,
- span,
- )
-}
-
struct OpaqueType<'a> {
bounds: &'a ast::GenericBounds,
}
}
}
-pub(crate) fn rewrite_opaque_impl_type(
- context: &RewriteContext<'_>,
- ident: symbol::Ident,
- generics: &ast::Generics,
- generic_bounds: &ast::GenericBounds,
- indent: Indent,
-) -> Option<String> {
- let ident_str = rewrite_ident(context, ident);
- // 5 = "type "
- let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
- let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
- let prefix = format!("type {} =", generics_str);
- let rhs = OpaqueType {
- bounds: generic_bounds,
- };
-
- rewrite_assign_rhs(
- context,
- &prefix,
- &rhs,
- Shape::indented(indent, context.config).sub_width(1)?,
- )
- .map(|s| s + ";")
-}
-
-pub(crate) fn rewrite_associated_impl_type(
+pub(crate) fn rewrite_impl_type(
ident: symbol::Ident,
vis: &ast::Visibility,
defaultness: ast::Defaultness,
indent: Indent,
span: Span,
) -> Option<String> {
- let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
+ // Opaque type
+ let result = if let Some(rustc_ast::ast::Ty {
+ kind: ast::TyKind::ImplTrait(_, ref bounds),
+ ..
+ }) = ty_opt.map(|t| &**t)
+ {
+ rewrite_type(
+ context,
+ indent,
+ ident,
+ &DEFAULT_VISIBILITY,
+ generics,
+ None,
+ Some(&OpaqueType { bounds }),
+ span,
+ )
+ } else {
+ rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span)
+ }?;
match defaultness {
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
let param_attrs_result = self
.attrs
.rewrite(context, Shape::legacy(shape.width, shape.indent))?;
- let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
+ // N.B. Doc comments aren't typically valid syntax, but could appear
+ // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
+ let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
let num_attrs = self.attrs.len();
(
mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
param_attrs_result.contains('\n'),
+ self.attrs.iter().any(|a| a.is_doc_comment()),
)
} else {
- (mk_sp(self.span.lo(), self.span.lo()), false)
+ (mk_sp(self.span.lo(), self.span.lo()), false, false)
};
if let Some(ref explicit_self) = self.to_self() {
has_multiple_attr_lines,
)
} else if is_named_param(self) {
+ let param_name = &self
+ .pat
+ .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
let mut result = combine_strs_with_missing_comments(
context,
¶m_attrs_result,
- &self
- .pat
- .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
+ param_name,
span,
shape,
- !has_multiple_attr_lines,
+ !has_multiple_attr_lines && !has_doc_comments,
)?;
if !is_empty_infer(&*self.ty, self.pat.span) {
result.push_str(&after_comment);
let overhead = last_line_width(&result);
let max_width = shape.width.checked_sub(overhead)?;
- let ty_str = self
+ if let Some(ty_str) = self
.ty
- .rewrite(context, Shape::legacy(max_width, shape.indent))?;
- result.push_str(&ty_str);
+ .rewrite(context, Shape::legacy(max_width, shape.indent))
+ {
+ result.push_str(&ty_str);
+ } else {
+ result = combine_strs_with_missing_comments(
+ context,
+ &(param_attrs_result + &shape.to_string_with_newline(context.config)),
+ param_name,
+ span,
+ shape,
+ !has_multiple_attr_lines,
+ )?;
+ result.push_str(&before_comment);
+ result.push_str(colon_spaces(context.config));
+ result.push_str(&after_comment);
+ let overhead = last_line_width(&result);
+ let max_width = shape.width.checked_sub(overhead)?;
+ let ty_str = self
+ .ty
+ .rewrite(context, Shape::legacy(max_width, shape.indent))?;
+ result.push_str(&ty_str);
+ }
}
Some(result)
context,
shape.indent,
self.ident,
- &FnSig::from_method_sig(&fn_sig, generics, self.vis.clone()),
+ &FnSig::from_method_sig(&fn_sig, generics, &self.vis),
span,
FnBraceStyle::None,
)
ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
**ty_alias_kind;
- rewrite_type_alias(
- self.ident,
- type_default.as_ref(),
- generics,
- Some(generic_bounds),
+ rewrite_type(
&context,
shape.indent,
+ self.ident,
&self.vis,
+ generics,
+ Some(generic_bounds),
+ type_default.as_ref(),
self.span,
)
}
result.push_str(&comment);
if !inner_item.is_empty() {
- if tactic == DefinitiveListTactic::Vertical || tactic == DefinitiveListTactic::Mixed
- {
- // We cannot keep pre-comments on the same line if the comment if normalized.
+ use DefinitiveListTactic::*;
+ if matches!(tactic, Vertical | Mixed | SpecialMacro(_)) {
+ // We cannot keep pre-comments on the same line if the comment is normalized.
let keep_comment = if formatting.config.normalize_comments()
|| item.pre_comment_style == ListItemCommentStyle::DifferentLine
{
line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s));
}
} else {
- result.push(' ');
+ result.push(' ')
}
}
item_max_width = None;
}
result.push_str(&nested_indent_str);
result.push_str(&body_str);
+ result.push_str(&comma);
return Some(result);
}
}
pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) {
+ self.format_missing_indent(end, true)
+ }
+
+ pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
+ self.format_missing_indent(end, false)
+ }
+
+ fn format_missing_indent(&mut self, end: BytePos, should_indent: bool) {
let config = self.config;
self.format_missing_inner(end, |this, last_snippet, snippet| {
this.push_str(last_snippet.trim_end());
// No new lines in the snippet.
this.push_str("\n");
}
- let indent = this.block_indent.to_string(config);
- this.push_str(&indent);
- })
- }
-
- pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
- self.format_missing_inner(end, |this, last_snippet, _| {
- this.push_str(last_snippet.trim_end());
+ if should_indent {
+ let indent = this.block_indent.to_string(config);
+ this.push_str(&indent);
+ }
})
}
FieldDef(&'a ast::FieldDef),
TuplePatField(&'a TuplePatField<'a>),
Ty(&'a ast::Ty),
+ Pat(&'a ast::Pat),
}
impl<'a> Rewrite for OverflowableItem<'a> {
OverflowableItem::FieldDef(sf) => f(*sf),
OverflowableItem::TuplePatField(pat) => f(*pat),
OverflowableItem::Ty(ty) => f(*ty),
+ OverflowableItem::Pat(pat) => f(*pat),
}
}
}
}
-impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty);
+impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty, Pat);
impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
pub(crate) fn into_overflowable_list<'a, T>(
use crate::comment::{combine_strs_with_missing_comments, FindUncommented};
use crate::config::lists::*;
+use crate::config::Version;
use crate::expr::{can_be_overflowed_expr, rewrite_unary_prefix, wrap_struct_field};
use crate::lists::{
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
PatKind::Path(ref q_self, ref path) => {
rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
}
- PatKind::TupleStruct(_, ref path, ref pat_vec) => {
- let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
+ PatKind::TupleStruct(ref q_self, ref path, ref pat_vec) => {
+ let path_str =
+ rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)?;
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
}
PatKind::Lit(ref expr) => expr.rewrite(context, shape),
- PatKind::Slice(ref slice_pat) => {
+ PatKind::Slice(ref slice_pat) if context.config.version() == Version::One => {
let rw: Vec<String> = slice_pat
.iter()
.map(|p| {
.collect();
Some(format!("[{}]", rw.join(", ")))
}
- PatKind::Struct(_, ref path, ref fields, ellipsis) => {
- rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
+ PatKind::Slice(ref slice_pat) => overflow::rewrite_with_square_brackets(
+ context,
+ "",
+ slice_pat.iter(),
+ shape,
+ self.span,
+ None,
+ None,
+ ),
+ PatKind::Struct(ref qself, ref path, ref fields, ellipsis) => {
+ rewrite_struct_pat(qself, path, fields, ellipsis, self.span, context, shape)
}
PatKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Pat)
}
fn rewrite_struct_pat(
+ qself: &Option<ast::QSelf>,
path: &ast::Path,
fields: &[ast::PatField],
ellipsis: bool,
) -> Option<String> {
// 2 = ` {`
let path_shape = shape.sub_width(2)?;
- let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
+ let path_str = rewrite_path(context, PathContext::Expr, qself.as_ref(), path, path_shape)?;
if fields.is_empty() && !ellipsis {
return Some(format!("{} {{}}", path_str));
merge_use_trees(normalized_items, SharedPrefix::Module)
}
ImportGranularity::Item => flatten_use_trees(normalized_items),
+ ImportGranularity::One => merge_use_trees(normalized_items, SharedPrefix::One),
ImportGranularity::Preserve => normalized_items,
};
impl Spanned for ast::Param {
fn span(&self) -> Span {
if crate::items::is_named_param(self) {
- mk_sp(self.pat.span.lo(), self.ty.span.hi())
+ mk_sp(crate::items::span_lo_for_param(self), self.ty.span.hi())
} else {
self.ty.span
}
self.parse_sess.source_map().span_to_filename(span).into()
}
+ pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> {
+ self.parse_sess
+ .source_map()
+ .lookup_source_file(span.data().lo)
+ }
+
pub(crate) fn span_to_first_line_string(&self, span: Span) -> String {
let file_lines = self.parse_sess.source_map().span_to_lines(span).ok();
#[test]
fn stdin_disable_all_formatting_test() {
init_log();
- match option_env!("CFG_RELEASE_CHANNEL") {
- None | Some("nightly") => {}
- // These tests require nightly.
- _ => return,
- }
let input = String::from("fn main() { println!(\"This should not be formatted.\"); }");
let mut child = Command::new(rustfmt().to_str().unwrap())
.stdin(Stdio::piped())
reader
.lines()
.map(|line| line.expect("failed getting line"))
- .take_while(|line| line_regex.is_match(line))
+ .filter(|line| line_regex.is_match(line))
.filter_map(|line| {
regex.captures_iter(&line).next().map(|capture| {
(
SegmentParam::Const(const_) => const_.rewrite(context, shape),
SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
SegmentParam::Type(ty) => ty.rewrite(context, shape),
- SegmentParam::Binding(assoc_ty_constraint) => {
- let mut result = match assoc_ty_constraint.kind {
- ast::AssocTyConstraintKind::Bound { .. } => {
- format!("{}: ", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- ast::AssocTyConstraintKind::Equality { .. } => {
- match context.config.type_punctuation_density() {
- TypeDensity::Wide => {
- format!("{} = ", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- TypeDensity::Compressed => {
- format!("{}=", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- }
- }
- };
+ SegmentParam::Binding(atc) => atc.rewrite(context, shape),
+ }
+ }
+}
- let budget = shape.width.checked_sub(result.len())?;
- let rewrite = assoc_ty_constraint
- .kind
- .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
- result.push_str(&rewrite);
- Some(result)
- }
+impl Rewrite for ast::AssocTyConstraint {
+ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+ use ast::AssocTyConstraintKind::{Bound, Equality};
+
+ let mut result = String::with_capacity(128);
+ result.push_str(rewrite_ident(context, self.ident));
+
+ if let Some(ref gen_args) = self.gen_args {
+ let budget = shape.width.checked_sub(result.len())?;
+ let shape = Shape::legacy(budget, shape.indent + result.len());
+ let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
+ result.push_str(&gen_str);
}
+
+ let infix = match (&self.kind, context.config.type_punctuation_density()) {
+ (Bound { .. }, _) => ": ",
+ (Equality { .. }, TypeDensity::Wide) => " = ",
+ (Equality { .. }, TypeDensity::Compressed) => "=",
+ };
+ result.push_str(infix);
+
+ let budget = shape.width.checked_sub(result.len())?;
+ let shape = Shape::legacy(budget, shape.indent + result.len());
+ let rewrite = self.kind.rewrite(context, shape)?;
+ result.push_str(&rewrite);
+
+ Some(result)
}
}
};
if let Some(ref args) = segment.args {
+ let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
match **args {
ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
- let param_list = data
- .args
- .iter()
- .map(|x| match x {
- ast::AngleBracketedArg::Arg(generic_arg) => {
- SegmentParam::from_generic_arg(generic_arg)
- }
- ast::AngleBracketedArg::Constraint(constraint) => {
- SegmentParam::Binding(constraint)
- }
- })
- .collect::<Vec<_>>();
-
// HACK: squeeze out the span between the identifier and the parameters.
// The hack is requried so that we don't remove the separator inside macro calls.
// This does not work in the presence of comment, hoping that people are
};
result.push_str(separator);
- let generics_str = overflow::rewrite_with_angle_brackets(
- context,
- "",
- param_list.iter(),
- shape,
- mk_sp(*span_lo, span_hi),
- )?;
-
// Update position of last bracket.
*span_lo = context
.snippet_provider
.span_after(mk_sp(*span_lo, span_hi), "<");
-
- result.push_str(&generics_str)
- }
- ast::GenericArgs::Parenthesized(ref data) => {
- result.push_str(&format_function_type(
- data.inputs.iter().map(|x| &**x),
- &data.output,
- false,
- data.span,
- context,
- shape,
- )?);
}
_ => (),
}
+ result.push_str(&generics_str)
}
Some(result)
}
}
+fn rewrite_generic_args(
+ gen_args: &ast::GenericArgs,
+ context: &RewriteContext<'_>,
+ shape: Shape,
+ span: Span,
+) -> Option<String> {
+ match gen_args {
+ ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
+ let args = data
+ .args
+ .iter()
+ .map(|x| match x {
+ ast::AngleBracketedArg::Arg(generic_arg) => {
+ SegmentParam::from_generic_arg(generic_arg)
+ }
+ ast::AngleBracketedArg::Constraint(constraint) => {
+ SegmentParam::Binding(constraint)
+ }
+ })
+ .collect::<Vec<_>>();
+
+ overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+ }
+ ast::GenericArgs::Parenthesized(ref data) => format_function_type(
+ data.inputs.iter().map(|x| &**x),
+ &data.output,
+ false,
+ data.span,
+ context,
+ shape,
+ ),
+ _ => Some("".to_owned()),
+ }
+}
+
fn rewrite_bounded_lifetime(
lt: &ast::Lifetime,
bounds: &[ast::GenericBound],
if let ast::GenericParamKind::Const {
ref ty,
kw_span: _,
- default: _,
+ default,
} = &self.kind
{
result.push_str("const ");
result.push_str(rewrite_ident(context, self.ident));
result.push_str(": ");
result.push_str(&ty.rewrite(context, shape)?);
+ if let Some(default) = default {
+ let eq_str = match context.config.type_punctuation_density() {
+ TypeDensity::Compressed => "=",
+ TypeDensity::Wide => " = ",
+ };
+ result.push_str(eq_str);
+ let budget = shape.width.checked_sub(result.len())?;
+ let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
+ result.push_str(&rewrite);
+ }
} else {
result.push_str(rewrite_ident(context, self.ident));
}
use rustc_ast::{ast, token::DelimToken, visit, AstLike};
use rustc_data_structures::sync::Lrc;
-use rustc_span::{symbol, BytePos, Pos, Span, DUMMY_SP};
+use rustc_span::{symbol, BytePos, Pos, Span};
use crate::attr::*;
use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
use crate::config::{BraceStyle, Config};
use crate::coverage::transform_missing_snippet;
use crate::items::{
- format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
- rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
- rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
+ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
+ rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts,
+ StructParts,
};
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
use crate::modules::Module;
indent,
item.ident,
&fn_signature,
+ &item.vis,
generics,
item.span,
);
**alias_kind;
match ty {
Some(ty) => {
- let rewrite = rewrite_type_alias(
- item.ident,
- Some(&*ty),
- generics,
- Some(generic_bounds),
+ let rewrite = rewrite_type(
&self.get_context(),
self.block_indent,
+ item.ident,
&item.vis,
+ generics,
+ Some(generic_bounds),
+ Some(&*ty),
item.span,
);
self.push_rewrite(item.span, rewrite);
let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
if let Some(ref body) = block {
let inner_attrs = inner_attributes(&ti.attrs);
- let vis = ast::Visibility {
- kind: ast::VisibilityKind::Inherited,
- span: DUMMY_SP,
- tokens: None,
- };
let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)),
generics,
&sig.decl,
ti.span,
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span);
+ self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span);
self.push_rewrite(ti.span, rewrite);
}
}
ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
**ty_alias_kind;
- let rewrite = rewrite_type_alias(
- ti.ident,
- type_default.as_ref(),
- generics,
- Some(generic_bounds),
+ let rewrite = rewrite_type(
&self.get_context(),
self.block_indent,
+ ti.ident,
&ti.vis,
+ generics,
+ Some(generic_bounds),
+ type_default.as_ref(),
ti.span,
);
self.push_rewrite(ti.span, rewrite);
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span);
+ self.rewrite_required_fn(indent, ii.ident, sig, &ii.vis, generics, ii.span);
self.push_rewrite(ii.span, rewrite);
}
}
ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
- let rewrite_associated = || {
- rewrite_associated_impl_type(
+ self.push_rewrite(
+ ii.span,
+ rewrite_impl_type(
ii.ident,
&ii.vis,
defaultness,
&self.get_context(),
self.block_indent,
ii.span,
- )
- };
- let rewrite = match ty {
- None => rewrite_associated(),
- Some(ty) => match ty.kind {
- ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type(
- &self.get_context(),
- ii.ident,
- generics,
- bounds,
- self.block_indent,
- ),
- _ => rewrite_associated(),
- },
- };
- self.push_rewrite(ii.span, rewrite);
+ ),
+ );
}
ast::AssocItemKind::MacCall(ref mac) => {
self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
--- /dev/null
+[package]
+name = "cargo-fmt-test"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+indexmap = "1.0.2"
+
+[workspace]
+members = [
+ "dependency-dir-name",
+]
\ No newline at end of file
--- /dev/null
+[package]
+name = "dependency-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+subdep-crate-name = { path = "subdep-dir-name" }
+indexmap = "1.0.2"
+rusty-hook = "0.8.4"
\ No newline at end of file
--- /dev/null
+#[cfg(test)]
+mod tests {
+#[test]
+fn it_works() {
+ assert_eq!(2 + 2, 4);
+}
+}
--- /dev/null
+[package]
+name = "subdep-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
--- /dev/null
+#[cfg(test)]
+mod tests {
+#[test]
+fn sub_test_that_works() {
+ assert_eq!(3 + 3, 6);
+}
+ }
--- /dev/null
+fn main() {
+println!("Hello, world!");
+}
--- /dev/null
+[package]
+name = "e"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../ws/c" }
+
+[workspace]
--- /dev/null
+struct E{ }
--- /dev/null
+[workspace]
+members = [
+ "a",
+ "b"
+]
\ No newline at end of file
--- /dev/null
+[package]
+name = "a"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+d = { path = "./d" }
--- /dev/null
+[package]
+name = "d"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+e = { path = "../../../e" }
+f = { path = "f" }
--- /dev/null
+[package]
+name = "f"
+version = "0.1.0"
+edition = "2018"
--- /dev/null
+struct F{ }
\ No newline at end of file
--- /dev/null
+struct D{ }
\ No newline at end of file
--- /dev/null
+struct D{ }
\ No newline at end of file
--- /dev/null
+[package]
+name = "b"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../c" }
--- /dev/null
+struct B{ }
\ No newline at end of file
--- /dev/null
+[package]
+name = "c"
+version = "0.1.0"
+edition = "2018"
--- /dev/null
+struct C{ }
\ No newline at end of file
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ & abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ | abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ << abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ < abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ > abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ == abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ && abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ || abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ match val {
+ ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine | ThisIsA::SecondValueSeparatedByAPipe | ThisIsA::ThirdValueSeparatedByAPipe => {
+ //
+ }
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Lower
+fn main() {
+ let h1 = 0xCAFE_5EA7;
+ let h2 = 0xCAFE_F00Du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Upper
+fn main() {
+ let h1 = 0xCaFE_5ea7;
+ let h2 = 0xCAFE_F00Du32;
+}
// Comment 3
}
+#[inherent]
+impl Visible for Bar {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
+
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y> where X: Foo<'a, Z> {
fn foo() { "hi" }
}
--- /dev/null
+// rustfmt-imports_granularity: One
+
+use b;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+
+use a as x;
+use b::ba;
+use a::{aa, ab};
+
+use a::aa::aaa;
+use a::ab::aba as x;
+use a::aa::*;
+
+use a::aa;
+use a::ad::ada;
+#[cfg(test)]
+use a::{ab, ac::aca};
+use b;
+#[cfg(test)]
+use b::{
+ ba, bb,
+ bc::bca::{bcaa, bcab},
+};
+
+pub use a::aa;
+pub use a::ae;
+use a::{ab, ac, ad};
+use b::ba;
+pub use b::{bb, bc::bca};
+
+use a::aa::aaa;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+use b::{
+ ba,
+ bb::{self, bba},
+};
+
+use crate::a;
+use crate::b::ba;
+use c::ca;
+
+use super::a;
+use c::ca;
+use super::b::ba;
+
+use crate::a;
+use super::b;
+use c::{self, ca};
+
+use a::{
+ // some comment
+ aa::{aaa, aab},
+ ab,
+ // another comment
+ ac::aca,
+};
+use b as x;
+use a::ad::ada;
--- /dev/null
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!( false );
+/// ```
+///
+/// ```,
+/// assert!( false );
+/// ```
+///
+/// ```,,,,,
+/// assert!( false );
+/// ```
+///
+/// ```,,, rust ,,
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```,,, rust , ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
--- /dev/null
+// rustfmt-version: Two
+fn main() {
+ let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] = panic!();
+}
--- /dev/null
+info!(//debug
+ "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+ self.name, function_code, data, crc, output_cmd
+);
--- /dev/null
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize = 1, const N2: usize = 2>;
+struct Bar<const N: usize, const N2: usize = { N +
+1 }>;
+struct Lots<const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+ const LessThan100ButClose: usize = {1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1}
+>;
+struct FooBarrrrrrrr<const N: usize = {13478234326456456444323871+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+1+1+1 + 1},>;
--- /dev/null
+
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X { a: 1_000, b: 1_000, .. }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
\ No newline at end of file
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10, ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA { bbbbbbbbb: i32, cccccccc: i32 }
+
+enum SomeEnumNamedD {
+ E(InnerStructA),
+ F {
+ ggggggggggggggggggggggggg: bool,
+ h: bool,
+ }
+}
+
+impl SomeEnumNamedD {
+ fn f_variant() -> Self {
+ Self::F { ggggggggggggggggggggggggg: true, h: true }
+ }
+}
+
+fn main() {
+ let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+ let something_we_care_about = matches!(
+ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+ SomeEnumNamedD::F {
+ ggggggggggggggggggggggggg: true,
+ ..
+ }
+ );
+
+ if something_we_care_about {
+ println!("Yup it happened");
+ }
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X { a: i32, b: i32 }
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ a: 1,
+ ..
+ });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+ });
+}
\ No newline at end of file
--- /dev/null
+#[derive(/*Debug, */Clone)]
+struct Foo;
--- /dev/null
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone, Eq, PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
+
+#[derive(
+/*
+ Some really important comment that just had to go inside the derive.
+ Also had to be put over multiple lines
+*/
+Debug, Clone, Eq, PartialEq,
+)]
+struct Bar {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone,/* Another comment */Eq, PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
--- /dev/null
+pub(crate) struct ASlash(
+ // hello
+ i32
+);
+
+pub(crate) struct AStar(
+ /* hello */
+ i32
+);
+
+pub(crate) struct BStar(/* hello */ i32);
+
--- /dev/null
+fn a1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
+fn a2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
--- /dev/null
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+ type Type<'a> where T: 'a;
+ fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+ type Type<'a> where T: 'a = &'a T;
+ fn foo(x: &T) -> Self::Type<'_> {
+ x
+ }
+}
--- /dev/null
+trait Bar {
+ type X<'a> where Self: 'a;
+}
--- /dev/null
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+ () => {
+ #[spirv(fragment)]
+ pub fn main_fs(
+ mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+ #[spirv(descriptor_set = 1)]iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+ [::spirv_std::glam::Vec3A; 4],
+ >,
+ ) {
+ }
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+ type SomeGAT<'a> where Self: 'a = impl SomeOtherTrait;
+}
\ No newline at end of file
--- /dev/null
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+ fn process<T>(v: T) -> <Self as GAT>::R<T>
+ where Self: GAT<R<T> = T>
+ {
+ SomeStruct::do_something(v)
+ }
+}
--- /dev/null
+trait Foo {
+ type Arg<'a>;
+}
+
+struct Bar<T>(T) where for<'a> T: Foo<Arg<'a> = ()>;
--- /dev/null
+mod test {
+ extern "C" {fn test();}
+}
+
+extern "C" {fn test();}
\ No newline at end of file
"line1";
"line2"
}
+ ThisIsA::Guard if true => {
+ "line1";
+ "line2"
+ }
+ ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine) if true => {
+ "line1";
+ "line2"
+ }
b => (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
}
+ DDDDDDDD
+ DDDDDDDDD
+ EEEEEEE;
+
+trait Visible {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ |
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <<
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >>
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ==
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &&
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ||
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ match val {
+ ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine |
+ ThisIsA::SecondValueSeparatedByAPipe |
+ ThisIsA::ThirdValueSeparatedByAPipe => {
+ //
+ }
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main() {
+ println!("hello, world");
+}
--- /dev/null
+// rustfmt-hex_literal_case: Lower
+fn main() {
+ let h1 = 0xcafe_5ea7;
+ let h2 = 0xcafe_f00du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Preserve
+fn main() {
+ let h1 = 0xcAfE_5Ea7;
+ let h2 = 0xCaFe_F00du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Upper
+fn main() {
+ let h1 = 0xCAFE_5EA7;
+ let h2 = 0xCAFE_F00Du32;
+}
// Comment 3
}
+#[inherent]
+impl Visible for Bar {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
+
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y>
where
X: Foo<'a, Z>,
--- /dev/null
+// rustfmt-imports_granularity: One
+
+use {
+ a::{
+ aa::*,
+ ab,
+ ac::{aca, acb},
+ },
+ b,
+};
+
+use {
+ a::{self as x, aa, ab},
+ b::ba,
+};
+
+use a::{
+ aa::{aaa, *},
+ ab::aba as x,
+};
+
+#[cfg(test)]
+use a::{ab, ac::aca};
+#[cfg(test)]
+use b::{
+ ba, bb,
+ bc::bca::{bcaa, bcab},
+};
+use {
+ a::{aa, ad::ada},
+ b,
+};
+
+pub use {
+ a::{aa, ae},
+ b::{bb, bc::bca},
+};
+use {
+ a::{ab, ac, ad},
+ b::ba,
+};
+
+use {
+ a::{
+ aa::{aaa, *},
+ ab,
+ ac::{aca, acb},
+ },
+ b::{
+ ba,
+ bb::{self, bba},
+ },
+};
+
+use {
+ crate::{a, b::ba},
+ c::ca,
+};
+
+use {
+ super::{a, b::ba},
+ c::ca,
+};
+
+use {
+ super::b,
+ crate::a,
+ c::{self, ca},
+};
+
+use {
+ a::{
+ aa::{aaa, aab},
+ ab,
+ ac::aca,
+ ad::ada,
+ },
+ b as x,
+};
--- /dev/null
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!(false);
+/// ```
+///
+/// ```,
+/// assert!(false);
+/// ```
+///
+/// ```,,,,,
+/// assert!(false);
+/// ```
+///
+/// ```,,, rust ,,
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```,,, rust , ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
--- /dev/null
+// rustfmt-version: Two
+fn main() {
+ let [
+ aaaaaaaaaaaaaaaaaaaaaaaaaa,
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+ cccccccccccccccccccccccccc,
+ ddddddddddddddddddddddddd,
+ ] = panic!();
+}
--- /dev/null
+info!(
+ //debug
+ "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+ self.name, function_code, data, crc, output_cmd
+);
--- /dev/null
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize = 1, const N2: usize = 2>;
+struct Bar<const N: usize, const N2: usize = { N + 1 }>;
+struct Lots<
+ const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },
+ const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },
+>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+ const LessThan100ButClose: usize = {
+ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
+ },
+>;
+struct FooBarrrrrrrr<
+ const N: usize = {
+ 13478234326456456444323871
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ },
+>;
--- /dev/null
+#![feature(more_qualified_paths)]
+
+fn main() {
+ // destructure through a qualified path
+ let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+ br: i8,
+}
+
+struct Foo;
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = StructStruct;
+}
--- /dev/null
+#![feature(more_qualified_paths)]
+
+mod foo_bar {
+ pub enum Example {
+ Example1 {},
+ Example2 {},
+ }
+}
+
+fn main() {
+ foo!(crate::foo_bar::Example, Example1);
+
+ let i1 = foo_bar::Example::Example1 {};
+
+ assert_eq!(i1.foo_example(), 1);
+
+ let i2 = foo_bar::Example::Example2 {};
+
+ assert_eq!(i2.foo_example(), 2);
+}
+
+#[macro_export]
+macro_rules! foo {
+ ($struct:path, $variant:ident) => {
+ impl $struct {
+ pub fn foo_example(&self) -> i32 {
+ match self {
+ <$struct>::$variant { .. } => 1,
+ _ => 2,
+ }
+ }
+ }
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ c: 1_000,
+ d: 1_000,
+ e: 1_000,
+ f: 1_000,
+ g: 1_000,
+ h: 1_000,
+ i: 1_000,
+ j: 1_000,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA {
+ bbbbbbbbb: i32,
+ cccccccc: i32,
+}
+
+enum SomeEnumNamedD {
+ E(InnerStructA),
+ F {
+ ggggggggggggggggggggggggg: bool,
+ h: bool,
+ },
+}
+
+impl SomeEnumNamedD {
+ fn f_variant() -> Self {
+ Self::F {
+ ggggggggggggggggggggggggg: true,
+ h: true,
+ }
+ }
+}
+
+fn main() {
+ let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+ let something_we_care_about = matches!(
+ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+ SomeEnumNamedD::F {
+ ggggggggggggggggggggggggg: true,
+ ..
+ }
+ );
+
+ if something_we_care_about {
+ println!("Yup it happened");
+ }
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X { a: 1, .. });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ }
+ );
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ c: 1_000,
+ d: 1_000,
+ e: 1_000,
+ f: 1_000,
+ g: 1_000,
+ h: 1_000,
+ i: 1_000,
+ j: 1_000,
+ ..
+ }
+ );
+}
--- /dev/null
+#[derive(/*Debug, */ Clone)]
+struct Foo;
--- /dev/null
+#[derive(
+ /* ---------- Some really important comment that just had to go inside the derive --------- */
+ Debug,
+ Clone,
+ Eq,
+ PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
+
+#[derive(
+ /*
+ Some really important comment that just had to go inside the derive.
+ Also had to be put over multiple lines
+ */
+ Debug,
+ Clone,
+ Eq,
+ PartialEq,
+)]
+struct Bar {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(
+ /* ---------- Some really important comment that just had to go inside the derive --------- */
+ Debug,
+ Clone,
+ /* Another comment */ Eq,
+ PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct Foo;
+
+#[derive(Clone)]
+struct Bar;
--- /dev/null
+#![feature(more_qualified_paths)]
+macro_rules! show {
+ ($ty:ty, $ex:expr) => {
+ match $ex {
+ <$ty>::A(_val) => println!("got a"), // formatting should not remove <$ty>::
+ <$ty>::B => println!("got b"),
+ }
+ };
+}
--- /dev/null
+fn main() {
+ // the "in" inside the pattern produced invalid syntax
+ for variable_in_here /* ... */ in 0..1 {}
+}
--- /dev/null
+fn main() {
+ for in_in_in_in_in_in_in_in /* ... */ in 0..1 {}
+}
--- /dev/null
+fn main() {
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {}
+ }
+}
--- /dev/null
+fn main() {
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {
+ if false {
+
+ } else if false {
+
+ } else {
+
+ }
+ }
+ }
+}
--- /dev/null
+fn main() {
+ let in_ = false;
+
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {
+ if in_ {
+
+ } else if in_ {
+
+ } else {
+
+ }
+ }
+ }
+}
--- /dev/null
+fn main() {
+ for variable_in_a /* ... */ in 0..1 {
+ for variable_in_b /* ... */ in 0..1 {
+ for variable_in_c /* ... */ in 0..1 {
+ for variable_in_d /* ... */ in 0..1 {
+ for variable_in_e /* ... */ in 0..1 {
+ for variable_in_f /* ... */ in 0..1 {
+ for variable_in_g /* ... */ in 0..1 {
+ for variable_in_h /* ... */ in 0..1 {
+ for variable_in_i /* ... */ in 0..1 {
+ for variable_in_j /* ... */ in 0..1 {
+ for variable_in_k /* ... */ in 0..1 {
+ for variable_in_l /* ... */ in 0..1 {
+ for variable_in_m /* ... */ in 0..1 {
+ for variable_in_n /* ... */ in 0..1 {
+ for variable_in_o /* ... */ in 0..1 {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+pub(crate) struct ASlash(
+ // hello
+ i32,
+);
+
+pub(crate) struct AStar(/* hello */ i32);
+
+pub(crate) struct BStar(/* hello */ i32);
--- /dev/null
+fn foo() {
+ with_woff2_glyf_table("tests/fonts/woff2/SFNT-TTF-Composite.woff2", |glyf| {
+ let actual = glyf
+ .records
+ .iter()
+ .map(|glyph| match glyph {
+ GlyfRecord::Parsed(
+ found @ Glyph {
+ data: GlyphData::Composite { .. },
+ ..
+ },
+ ) => Some(found),
+ _ => None,
+ })
+ .find(|candidate| candidate.is_some())
+ .unwrap()
+ .unwrap();
+
+ assert_eq!(*actual, expected)
+ });
+}
--- /dev/null
+fn a1(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+ a: u8,
+) {
+}
+fn b1(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+ bb: u8,
+) {
+}
+fn a2(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8,
+) {
+}
+fn b2(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8,
+) {
+}
--- /dev/null
+fn bindings() {
+ let err = match (place_desc, explanation) {
+ (
+ Some(ref name),
+ BorrowExplanation::MustBeValidFor {
+ category:
+ category @ (ConstraintCategory::Return
+ | ConstraintCategory::CallArgument
+ | ConstraintCategory::OpaqueType),
+ from_closure: false,
+ ref region_name,
+ span,
+ ..
+ },
+ ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+ .report_escaping_closure_capture(
+ borrow_spans,
+ borrow_span,
+ region_name,
+ category,
+ span,
+ &format!("`{}`", name),
+ ),
+ (
+ ref name,
+ BorrowExplanation::MustBeValidFor {
+ category: ConstraintCategory::Assignment,
+ from_closure: false,
+ region_name:
+ RegionName {
+ source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
+ ..
+ },
+ span,
+ ..
+ },
+ ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+ (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
+ location,
+ &name,
+ &borrow,
+ drop_span,
+ borrow_spans,
+ explanation,
+ ),
+ (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
+ location,
+ &borrow,
+ drop_span,
+ borrow_spans,
+ proper_span,
+ explanation,
+ ),
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+ type Type<'a>
+ where
+ T: 'a;
+ fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+ type Type<'a>
+ where
+ T: 'a,
+ = &'a T;
+ fn foo(x: &T) -> Self::Type<'_> {
+ x
+ }
+}
--- /dev/null
+trait Bar {
+ type X<'a>
+ where
+ Self: 'a;
+}
--- /dev/null
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+ () => {
+ #[spirv(fragment)]
+ pub fn main_fs(
+ mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+ #[spirv(descriptor_set = 1)]
+ iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+ [::spirv_std::glam::Vec3A; 4],
+ >,
+ ) {
+ }
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+ type SomeGAT<'a>
+ where
+ Self: 'a,
+ = impl SomeOtherTrait;
+}
--- /dev/null
+#[discard_params_doc]
+trait Trait {
+ fn foo(
+ &self,
+ /// some docs
+ bar: String,
+ /// another docs
+ baz: i32,
+ );
+}
--- /dev/null
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+ fn process<T>(v: T) -> <Self as GAT>::R<T>
+ where
+ Self: GAT<R<T> = T>,
+ {
+ SomeStruct::do_something(v)
+ }
+}
--- /dev/null
+trait Foo {
+ type Arg<'a>;
+}
+
+struct Bar<T>(T)
+where
+ for<'a> T: Foo<Arg<'a> = ()>;
--- /dev/null
+mod test {
+ extern "C" {
+ fn test();
+ }
+}
+
+extern "C" {
+ fn test();
+}
"line1";
"line2"
},
+ ThisIsA::Guard if true => {
+ "line1";
+ "line2"
+ },
+ ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine)
+ if true =>
+ {
+ "line1";
+ "line2"
+ },
b => (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+ DDDDDDDD
+ DDDDDDDDD
+ EEEEEEE;
+
+trait Visible {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
&mut |entry, contents| {
let file = entry.path();
- let filestr = file.to_string_lossy().replace("\\", "/");
let filename = file.file_name().unwrap();
if filename != "Cargo.toml" {
return;
}
// Library crates are not yet ready to migrate to 2021.
- //
- // The reference and rustc-dev-guide are submodules, so are left at
- // 2018 for now. They should be removed from this exception list
- // when bumped.
- if path.components().any(|c| c.as_os_str() == "library")
- || filestr.contains("src/doc/reference/style-check/Cargo.toml")
- || filestr.contains("src/doc/rustc-dev-guide/ci/date-check/Cargo.toml")
- {
+ if path.components().any(|c| c.as_os_str() == "library") {
let has = contents.lines().any(is_edition_2018);
if !has {
tidy_error!(
&src_path.join("test/ui"),
&src_path.join("test/ui-fulldeps"),
&src_path.join("test/rustdoc-ui"),
+ &src_path.join("test/rustdoc"),
],
&mut |path| super::filter_dirs(path),
&mut |entry, contents| {
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1330;
+const ROOT_ENTRY_LIMIT: usize = 1331;
const ISSUES_ENTRY_LIMIT: usize = 2488;
fn check_entries(path: &Path, bad: &mut bool) {
allow-unauthenticated = [
"C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
"D-*",
+ "needs-fcp",
+ "relnotes",
"requires-nightly",
"regression-*",
"perf-*",
- # I-* without I-nominated
- "I-*", "!I-nominated",
+ # I-* without I-*nominated
+ "I-*", "!I-*nominated",
"AsyncAwait-OnDeck",
]