"humantime 2.0.1",
"ignore",
"im-rc",
+ "itertools 0.10.0",
"jobserver",
"lazy_static",
"lazycell",
"rand 0.8.3",
"rustc-workspace-hack",
"rustfix",
- "semver 0.10.0",
+ "semver 1.0.3",
"serde",
"serde_ignored",
"serde_json",
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
dependencies = [
"jobserver",
]
version = "0.1.54"
dependencies = [
"cargo_metadata 0.12.0",
- "clippy-mini-macro-test",
"clippy_lints",
"compiletest_rs",
"derive-new",
+ "filetime",
"quote",
"regex",
"rustc-workspace-hack",
"tester",
]
-[[package]]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-
[[package]]
name = "clippy_dev"
version = "0.0.1"
[[package]]
name = "compiler_builtins"
-version = "0.1.43"
+version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
+checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
dependencies = [
"cc",
"rustc-std-workspace-core",
"either",
]
+[[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "0.4.6"
"fs-err",
"getopts",
"jsonpath_lib",
- "lazy_static",
+ "once_cell",
"regex",
- "serde",
"serde_json",
- "shlex 0.1.1",
+ "shlex",
]
[[package]]
"serde",
"serde_derive",
"serde_json",
- "shlex 1.0.0",
+ "shlex",
"tempfile",
"toml",
]
[[package]]
name = "measureme"
-version = "9.1.1"
+version = "9.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c"
+checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d"
dependencies = [
"log",
"memmap2",
[[package]]
name = "memchr"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memmap2"
"hex 0.4.2",
"libc",
"log",
+ "measureme",
"rand 0.8.3",
"rustc-workspace-hack",
"rustc_version",
"rustc-std-workspace-core",
]
+[[package]]
+name = "object"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
[[package]]
name = "once_cell"
version = "1.7.2"
[[package]]
name = "racer"
-version = "2.1.46"
+version = "2.1.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
+checksum = "513c70e67444a0d62fdc581dffa521c6820942a5f08300d0864863f8d0e750e3"
dependencies = [
"bitflags",
"clap",
"itertools 0.9.0",
"jobserver",
"libc",
- "object",
+ "object 0.25.2",
"pathdiff",
"rustc_apfloat",
"rustc_ast",
"rand 0.7.3",
"rustc_ast",
"rustc_data_structures",
+ "rustc_errors",
"rustc_fs_util",
"rustc_graphviz",
"rustc_hir",
"serde",
]
+[[package]]
+name = "semver"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
-[[package]]
-name = "shlex"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
-
[[package]]
name = "shlex"
version = "1.0.0"
"hermit-abi",
"libc",
"miniz_oxide",
- "object",
+ "object 0.22.0",
"panic_abort",
"panic_unwind",
"profiler_builtins",
[[package]]
name = "tar"
-version = "0.4.33"
+version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
+checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
dependencies = [
"filetime",
"libc",
#![forbid(unsafe_code)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#[macro_use]
extern crate alloc;
)]
#![feature(box_syntax)]
#![feature(box_patterns)]
-// On bootstrap bump, this will likely have to become const_fn_unsize
-#![cfg_attr(bootstrap, feature(const_fn))] // For the `transmute` in `P::new`
+#![cfg_attr(bootstrap, feature(const_fn_unsize))]
#![feature(const_fn_transmute)]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(iter_zip)]
#![feature(label_break_value)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
//! in the HIR, especially for multiple identifiers.
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(box_patterns)]
#![feature(iter_zip)]
#![recursion_limit = "256"]
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
fn next_node_id(&mut self) -> NodeId;
- fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+ fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
let proc_macros =
c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
- let trait_map = self
- .resolver
- .trait_map()
- .iter()
- .filter_map(|(&k, v)| {
- self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
- })
- .collect();
+ 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 mut def_id_to_hir_id = IndexVec::default();
}}
gate_doc!(
- include => external_doc
cfg => doc_cfg
masked => doc_masked
notable_trait => doc_notable_trait
#![feature(bindings_after_at)]
#![feature(iter_is_partitioned)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(box_patterns)]
#![recursion_limit = "256"]
self.pclose();
}
ast::TyKind::AnonymousStruct(ref fields, ..) => {
- self.s.word("struct");
- self.print_record_struct_body(fields, ty.span);
+ self.head("struct");
+ self.print_record_struct_body(&fields, ty.span);
}
ast::TyKind::AnonymousUnion(ref fields, ..) => {
- self.s.word("union");
- self.print_record_struct_body(fields, ty.span);
+ self.head("union");
+ self.print_record_struct_body(&fields, ty.span);
}
ast::TyKind::Paren(ref typ) => {
self.popen();
}
}
- crate fn print_record_struct_body(
- &mut self,
- fields: &Vec<ast::FieldDef>,
- span: rustc_span::Span,
- ) {
- self.nbsp();
+ crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.bopen();
self.hardbreak_if_not_bol();
}
ast::VariantData::Struct(ref fields, ..) => {
self.print_where_clause(&generics.where_clause);
+ self.nbsp();
self.print_record_struct_body(fields, span);
}
}
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
//! to this crate.
-#![cfg_attr(bootstrap, feature(or_patterns))]
-
#[macro_use]
extern crate rustc_macros;
#![feature(decl_macro)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![recursion_limit = "256"]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-[[package]]
-name = "byteorder"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
-
[[package]]
name = "cfg-if"
version = "1.0.0"
[[package]]
name = "cranelift-bforest"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
- "byteorder",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"regalloc",
"smallvec",
"target-lexicon",
- "thiserror",
]
[[package]]
name = "cranelift-codegen-meta"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
[[package]]
name = "cranelift-codegen-shared"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
[[package]]
name = "cranelift-entity"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
[[package]]
name = "cranelift-frontend"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-jit"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
- "errno",
"libc",
"log",
"region",
[[package]]
name = "cranelift-module"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"log",
- "thiserror",
]
[[package]]
name = "cranelift-native"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen",
"target-lexicon",
[[package]]
name = "cranelift-object"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cfg-if",
]
-[[package]]
-name = "errno"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
-dependencies = [
- "gcc",
- "libc",
-]
-
-[[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
[[package]]
name = "gimli"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
dependencies = [
"indexmap",
]
[[package]]
name = "object"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
+checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
dependencies = [
"crc32fast",
"indexmap",
]
-[[package]]
-name = "proc-macro2"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
[[package]]
name = "regalloc"
version = "0.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
-[[package]]
-name = "syn"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
[[package]]
name = "target-lexicon"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
-[[package]]
-name = "thiserror"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
[[package]]
name = "winapi"
version = "0.3.9"
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
-cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
-cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] }
+cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
+cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
target-lexicon = "0.12.0"
-gimli = { version = "0.23.0", default-features = false, features = ["write"]}
-object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.24.0", default-features = false, features = ["write"]}
+object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.0.2"
smallvec = "1.6.1"
# Uncomment to use local checkout of cranelift
-#[patch."https://github.com/bytecodealliance/wasmtime/"]
+#[patch."https://github.com/bytecodealliance/wasmtime.git"]
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
#cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-native = { path = ../wasmtime/cranelift/native" }
+#cranelift-native = { path = "../wasmtime/cranelift/native" }
#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
opt-level = 0
debug = false
-[profile.dev.package.syn]
-opt-level = 0
-debug = false
-
-[profile.release.package.syn]
-opt-level = 0
-debug = false
-
[package.metadata.rust-analyzer]
rustc_private = true
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]]
name = "cfg-if"
[[package]]
name = "compiler_builtins"
-version = "0.1.40"
+version = "0.1.43"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
-version = "0.2.94"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
pushd compiler-builtins
git checkout -- .
-git checkout 0.1.40
+git checkout 0.1.43
git apply ../../crate_patches/000*-compiler-builtins-*.patch
popd
--- /dev/null
+From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 18 Feb 2021 18:30:55 +0100
+Subject: [PATCH] Disable 128bit atomic operations
+
+Cranelift doesn't support them yet
+---
+ src/mem/mod.rs | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/src/mem/mod.rs b/src/mem/mod.rs
+index 107762c..2d1ae10 100644
+--- a/src/mem/mod.rs
++++ b/src/mem/mod.rs
+@@ -137,10 +137,6 @@ intrinsics! {
+ pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+ memcpy_element_unordered_atomic(dest, src, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+- memcpy_element_unordered_atomic(dest, src, bytes);
+- }
+
+ #[cfg(target_has_atomic_load_store = "8")]
+ pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
+@@ -158,10 +154,6 @@ intrinsics! {
+ pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+ memmove_element_unordered_atomic(dest, src, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+- memmove_element_unordered_atomic(dest, src, bytes);
+- }
+
+ #[cfg(target_has_atomic_load_store = "8")]
+ pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
+@@ -179,8 +171,4 @@ intrinsics! {
+ pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
+ memset_element_unordered_atomic(s, c, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
+- memset_element_unordered_atomic(s, c, bytes);
+- }
+ }
+--
+2.26.2.7.g19db9cfb68
+
+++ /dev/null
-From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 21 Jan 2021 14:46:36 +0100
-Subject: [PATCH] Remove rotate_left from Int
-
----
- src/int/mod.rs | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/src/int/mod.rs b/src/int/mod.rs
-index 06054c8..3bea17b 100644
---- a/src/int/mod.rs
-+++ b/src/int/mod.rs
-@@ -85,7 +85,6 @@ pub trait Int:
- fn wrapping_sub(self, other: Self) -> Self;
- fn wrapping_shl(self, other: u32) -> Self;
- fn wrapping_shr(self, other: u32) -> Self;
-- fn rotate_left(self, other: u32) -> Self;
- fn overflowing_add(self, other: Self) -> (Self, bool);
- fn leading_zeros(self) -> u32;
- }
-@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
- <Self>::wrapping_shr(self, other)
- }
-
-- fn rotate_left(self, other: u32) -> Self {
-- <Self>::rotate_left(self, other)
-- }
--
- fn overflowing_add(self, other: Self) -> (Self, bool) {
- <Self>::overflowing_add(self, other)
- }
---
-2.26.2.7.g19db9cfb68
-
+++ /dev/null
-From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 18 Feb 2021 18:30:55 +0100
-Subject: [PATCH] Disable 128bit atomic operations
-
-Cranelift doesn't support them yet
----
- src/mem/mod.rs | 12 ------------
- 1 file changed, 12 deletions(-)
-
-diff --git a/src/mem/mod.rs b/src/mem/mod.rs
-index 107762c..2d1ae10 100644
---- a/src/mem/mod.rs
-+++ b/src/mem/mod.rs
-@@ -137,10 +137,6 @@ intrinsics! {
- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
- memcpy_element_unordered_atomic(dest, src, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
-- memcpy_element_unordered_atomic(dest, src, bytes);
-- }
-
- #[cfg(target_has_atomic_load_store = "8")]
- pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
-@@ -158,10 +154,6 @@ intrinsics! {
- pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
- memmove_element_unordered_atomic(dest, src, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
-- memmove_element_unordered_atomic(dest, src, bytes);
-- }
-
- #[cfg(target_has_atomic_load_store = "8")]
- pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
-@@ -179,8 +171,4 @@ intrinsics! {
- pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
- memset_element_unordered_atomic(s, c, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
-- memset_element_unordered_atomic(s, c, bytes);
-- }
- }
---
-2.26.2.7.g19db9cfb68
-
);
let r = _mm_slli_si128(a, 16);
assert_eq_m128i(r, _mm_set1_epi8(0));
-
- #[rustfmt::skip]
- let a = _mm_setr_epi8(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- );
- let r = _mm_slli_si128(a, -1);
- assert_eq_m128i(_mm_set1_epi8(0), r);
-
- #[rustfmt::skip]
- let a = _mm_setr_epi8(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- );
- let r = _mm_slli_si128(a, -0x80000000);
- assert_eq_m128i(r, _mm_set1_epi8(0));
}
#[cfg(target_arch = "x86_64")]
8, 9, 10, 11, 12, 13, 14, 15
);
let r1 = _mm_extract_epi8(a, 0);
- let r2 = _mm_extract_epi8(a, 19);
+ let r2 = _mm_extract_epi8(a, 3);
assert_eq!(r1, 0xFF);
assert_eq!(r2, 3);
}
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
-diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
-index 0475aeb..9558198 100644
---- a/library/core/tests/num/int_macros.rs
-+++ b/library/core/tests/num/int_macros.rs
-@@ -88,6 +88,7 @@ mod tests {
- assert_eq!(x.trailing_ones(), 0);
- }
-
-+ /*
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -112,6 +113,7 @@ mod tests {
- assert_eq!(B.rotate_left(128), B);
- assert_eq!(C.rotate_left(128), C);
- }
-+ */
-
- #[test]
- fn test_swap_bytes() {
-diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
-index 04ed14f..a6e372e 100644
---- a/library/core/tests/num/uint_macros.rs
-+++ b/library/core/tests/num/uint_macros.rs
-@@ -52,6 +52,7 @@ mod tests {
- assert_eq!(x.trailing_ones(), 0);
- }
-
-+ /*
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -76,6 +77,7 @@ mod tests {
- assert_eq!(B.rotate_left(128), B);
- assert_eq!(C.rotate_left(128), C);
- }
-+ */
-
- #[test]
- fn test_swap_bytes() {
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 1a6be3a..42dbd59 100644
--- a/library/core/tests/ptr.rs
[toolchain]
-channel = "nightly-2021-04-28"
+channel = "nightly-2021-05-26"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
+
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
-diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
-index 23e689fcae7..5f077b765b6 100644
---- a/compiler/rustc_data_structures/Cargo.toml
-+++ b/compiler/rustc_data_structures/Cargo.toml
-@@ -32,7 +32,6 @@ tempfile = "3.0.5"
-
- [dependencies.parking_lot]
- version = "0.11"
--features = ["nightly"]
-
- [target.'cfg(windows)'.dependencies]
- winapi = { version = "0.3", features = ["fileapi", "psapi"] }
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index d95b5b7f17f..00b6f0e3635 100644
--- a/library/alloc/Cargo.toml
[dependencies]
core = { path = "../core" }
--compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
+-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
++compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] }
[dev-dependencies]
rand = "0.7"
+ rand_xorshift = "0.2"
EOF
cat > config.toml <<EOF
pushd regex
echo "[TEST] rust-lang/regex example shootout-regex-dna"
cargo clean
+ export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
# Make sure `[codegen mono items] start` doesn't poison the diff
../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
};
if !self.no_builtin_ranlib {
- match object::File::parse(&data) {
+ match object::File::parse(&*data) {
Ok(object) => {
symbol_table.insert(
entry_name.as_bytes().to_vec(),
// Verify function
verify_func(tcx, &clif_comments, &context.func);
- // Perform rust specific optimizations
- tcx.sess.time("optimize clif ir", || {
- crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
- });
-
// If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
// instruction, which doesn't have an encoding.
context.compute_cfg();
// invalidate it when it would change.
context.domtree.clear();
- context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+ // Perform rust specific optimizations
+ tcx.sess.time("optimize clif ir", || {
+ crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
+ });
// Define function
tcx.sess.time("define function", || {
+ context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
module
.define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
.unwrap()
pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
let location = fx.get_caller_location(span).load_scalar(fx);
- let msg_ptr = fx.anonymous_str("assert", msg_str);
+ let msg_ptr = fx.anonymous_str(msg_str);
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
let args = [msg_ptr, msg_len, location];
self.module.isa().triple()
}
- pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
- use std::collections::hash_map::DefaultHasher;
- use std::hash::{Hash, Hasher};
-
- let mut hasher = DefaultHasher::new();
- msg.hash(&mut hasher);
- let msg_hash = hasher.finish();
+ pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
let mut data_ctx = DataContext::new();
data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
- let msg_id = self
- .module
- .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
- .unwrap();
+ let msg_id = self.module.declare_anonymous_data(false, false).unwrap();
// Ignore DuplicateDefinition error, as the data will be the same
let _ = self.module.define_data(msg_id, &data_ctx);
/// Can be set using `-Cllvm-args=display_cg_time=...`.
pub display_cg_time: bool,
+ /// The register allocator to use.
+ ///
+ /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
+ /// `-Cllvm-args=regalloc=...`.
+ pub regalloc: String,
+
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
/// once before passing the clif ir to Cranelift for compilation.
///
args.split(' ').map(|arg| arg.to_string()).collect()
},
display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+ regalloc: std::env::var("CG_CLIF_REGALLOC")
+ .unwrap_or_else(|_| "backtracking".to_string()),
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
}
match name {
"mode" => config.codegen_mode = value.parse()?,
"display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+ "regalloc" => config.regalloc = value.to_string(),
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
_ => return Err(format!("Unknown option `{}`", name)),
use rustc_span::DUMMY_SP;
+use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::ErrorReported;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
- alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+ alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
+ Scalar,
};
use rustc_middle::ty::ConstKind;
let mut alloc = Allocation::from_bytes(
std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(),
align,
+ Mutability::Not,
);
alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap();
let alloc = fx.tcx.intern_const_alloc(alloc);
data_ctx.set_align(alloc.align.bytes());
if let Some(section_name) = section_name {
- // FIXME set correct segment for Mach-O files
- data_ctx.set_segment_section("", &*section_name);
+ let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
+ if let Some(names) = section_name.split_once(',') {
+ names
+ } else {
+ tcx.sess.fatal(&format!(
+ "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
+ section_name
+ ));
+ }
+ } else {
+ ("", &*section_name)
+ };
+ data_ctx.set_segment_section(segment_name, section_name);
}
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
operand: &Operand<'tcx>,
) -> Option<ConstValue<'tcx>> {
match operand {
- Operand::Copy(_) | Operand::Move(_) => None,
Operand::Constant(const_) => match const_.literal {
ConstantKind::Ty(const_) => {
fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
}
ConstantKind::Val(val, _) => Some(val),
},
+ // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
+ // inside a temporary before being passed to the intrinsic requiring the const argument.
+ // This code tries to find a single constant defining definition of the referenced local.
+ Operand::Copy(place) | Operand::Move(place) => {
+ if !place.projection.is_empty() {
+ return None;
+ }
+ let mut computed_const_val = None;
+ for bb_data in fx.mir.basic_blocks() {
+ for stmt in &bb_data.statements {
+ match &stmt.kind {
+ StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
+ match &local_and_rvalue.1 {
+ Rvalue::Cast(CastKind::Misc, operand, ty) => {
+ if computed_const_val.is_some() {
+ return None; // local assigned twice
+ }
+ if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
+ return None;
+ }
+ let const_val = mir_operand_get_const_val(fx, operand)?;
+ if fx.layout_of(ty).size
+ != const_val.try_to_scalar_int()?.size()
+ {
+ return None;
+ }
+ computed_const_val = Some(const_val);
+ }
+ Rvalue::Use(operand) => {
+ computed_const_val = mir_operand_get_const_val(fx, operand)
+ }
+ _ => return None,
+ }
+ }
+ StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ }
+ if &**stmt_place == place =>
+ {
+ return None;
+ }
+ StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+ return None;
+ } // conservative handling
+ StatementKind::Assign(_)
+ | StatementKind::FakeRead(_)
+ | StatementKind::SetDiscriminant { .. }
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::Nop => {}
+ }
+ }
+ match &bb_data.terminator().kind {
+ TerminatorKind::Goto { .. }
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::Assert { .. } => {}
+ TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. } => unreachable!(),
+ TerminatorKind::InlineAsm { .. } => return None,
+ TerminatorKind::Call { destination: Some((call_place, _)), .. }
+ if call_place == place =>
+ {
+ return None;
+ }
+ TerminatorKind::Call { .. } => {}
+ }
+ }
+ computed_const_val
+ }
}
}
let mut object = None;
let work_product = cgu.work_product(tcx);
if let Some(saved_file) = &work_product.saved_file {
- let obj_out = tcx
- .output_filenames(())
- .temp_path(OutputType::Object, Some(&cgu.name().as_str()));
+ let obj_out =
+ tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
object = Some(obj_out.clone());
let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
}
}
}
- crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
+ crate::main_shim::maybe_create_entry_wrapper(
+ tcx,
+ &mut module,
+ &mut cx.unwind_context,
+ false,
+ cgu.is_primary(),
+ );
let debug_context = cx.debug_context;
let unwind_context = cx.unwind_context;
.as_str()
.to_string();
- let tmp_file = tcx
- .output_filenames(())
- .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+ let tmp_file =
+ tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
crate::metadata::write_metadata(tcx, object);
.collect::<Vec<_>>()
.join("\n");
- let output_object_file =
- tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
+ let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
// Assemble `global_asm`
let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
&mut jit_module,
&mut cx.unwind_context,
true,
+ true,
);
(jit_module, cx)
use object::{Object, ObjectSymbol};
let lib = libloading::Library::new(&path).unwrap();
let obj = std::fs::read(path).unwrap();
- let obj = object::File::parse(&obj).unwrap();
+ let obj = object::File::parse(&*obj).unwrap();
imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
let name = symbol.name().unwrap().to_string();
if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
let true_ = fx.bcx.ins().iconst(types::I32, 1);
fx.bcx.ins().trapnz(true_, TrapCode::User(1));
return;
- } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
- && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
- && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+ } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+ && matches!(
+ template[1],
+ InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+ )
+ && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+ && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+ && matches!(
+ template[6],
+ InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+ )
{
assert_eq!(operands.len(), 4);
- let (leaf, eax_place) = match operands[0] {
+ let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
let reg = expect_reg(reg);
assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
}
_ => unreachable!(),
};
- let ebx_place = match operands[1] {
+ let ebx_place = match operands[0] {
InlineAsmOperand::Out { reg, late: true, place } => {
- let reg = expect_reg(reg);
- assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::reg
+ ))
+ );
crate::base::codegen_place(fx, place.unwrap())
}
_ => unreachable!(),
) -> (Value, Value, Value, Value) {
let leaf_0 = fx.bcx.create_block();
let leaf_1 = fx.bcx.create_block();
+ let leaf_7 = fx.bcx.create_block();
let leaf_8000_0000 = fx.bcx.create_block();
let leaf_8000_0001 = fx.bcx.create_block();
let unsupported_leaf = fx.bcx.create_block();
let mut switch = cranelift_frontend::Switch::new();
switch.set_entry(0, leaf_0);
switch.set_entry(1, leaf_1);
+ switch.set_entry(7, leaf_7);
switch.set_entry(0x8000_0000, leaf_8000_0000);
switch.set_entry(0x8000_0001, leaf_8000_0001);
switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
+ fx.bcx.switch_to_block(leaf_7);
+ // This leaf technically has subleaves, but we just return zero for all subleaves.
+ let zero = fx.bcx.ins().iconst(types::I32, 0);
+ fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
+
fx.bcx.switch_to_block(leaf_8000_0000);
let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
let zero = fx.bcx.ins().iconst(types::I32, 0);
pub(crate) use cpuid::codegen_cpuid_call;
pub(crate) use llvm::codegen_llvm_intrinsic_call;
-use rustc_span::symbol::{sym, kw};
use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{kw, sym};
use crate::prelude::*;
use cranelift_codegen::ir::AtomicRmwOp;
flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
+ flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
+
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
builder
}
Some(value) => {
- let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+ let mut builder =
+ cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
if let Err(_) = builder.enable(value) {
sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
}
builder
}
None => {
- let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+ let mut builder =
+ cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
builder.enable("nehalem").unwrap();
builder
}
};
-
+
isa_builder.finish(flags)
}
module: &mut impl Module,
unwind_context: &mut UnwindContext,
is_jit: bool,
+ is_primary_cgu: bool,
) {
let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
Some((def_id, entry_ty)) => (
None => return,
};
- let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
- if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+ if main_def_id.is_local() {
+ let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
+ if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+ return;
+ }
+ } else if !is_primary_cgu {
return;
}
}
let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
- let msg_ptr = fx.anonymous_str("trap", &real_msg);
+ let msg_ptr = fx.anonymous_str(&real_msg);
fx.bcx.ins().call(puts, &[msg_ptr]);
}
dst_align,
src_align,
true,
+ MemFlags::trusted(),
);
}
CValueInner::ByRef(_, Some(_)) => todo!(),
Visibility::Protected => llvm::Visibility::Protected,
}
}
-
-pub fn linkage_from_llvm(linkage: llvm::Linkage) -> Linkage {
- match linkage {
- llvm::Linkage::ExternalLinkage => Linkage::External,
- llvm::Linkage::AvailableExternallyLinkage => Linkage::AvailableExternally,
- llvm::Linkage::LinkOnceAnyLinkage => Linkage::LinkOnceAny,
- llvm::Linkage::LinkOnceODRLinkage => Linkage::LinkOnceODR,
- llvm::Linkage::WeakAnyLinkage => Linkage::WeakAny,
- llvm::Linkage::WeakODRLinkage => Linkage::WeakODR,
- llvm::Linkage::AppendingLinkage => Linkage::Appending,
- llvm::Linkage::InternalLinkage => Linkage::Internal,
- llvm::Linkage::PrivateLinkage => Linkage::Private,
- llvm::Linkage::ExternalWeakLinkage => Linkage::ExternalWeak,
- llvm::Linkage::CommonLinkage => Linkage::Common,
- }
-}
-
-pub fn visibility_from_llvm(linkage: llvm::Visibility) -> Visibility {
- match linkage {
- llvm::Visibility::Default => Visibility::Default,
- llvm::Visibility::Hidden => Visibility::Hidden,
- llvm::Visibility::Protected => Visibility::Protected,
- }
-}
}
impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+ #[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.cx.tcx
}
}
impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+ #[inline]
fn target_spec(&self) -> &Target {
&self.cx.target_spec()
}
impl Deref for Builder<'_, 'll, 'tcx> {
type Target = CodegenCx<'ll, 'tcx>;
+ #[inline]
fn deref(&self) -> &Self::Target {
self.cx
}
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeFoldable};
-use rustc_target::spec::RelocModel;
/// Codegens a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
}
- if cx.tcx.sess.relocation_model() == RelocModel::Static {
+ if cx.should_assume_dso_local(llfn, true) {
llvm::LLVMRustSetDSOLocal(llfn, true);
}
}
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
-use rustc_target::spec::RelocModel;
use tracing::debug;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
}
}
- if self.tcx.sess.relocation_model() == RelocModel::Static {
- unsafe {
+ unsafe {
+ if self.should_assume_dso_local(g, true) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
set_global_alignment(&self, g, self.align_of(ty));
llvm::LLVMSetInitializer(g, v);
- let linkage = base::linkage_from_llvm(llvm::LLVMRustGetLinkage(g));
- let visibility = base::visibility_from_llvm(llvm::LLVMRustGetVisibility(g));
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(g, true) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
impl HasDataLayout for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn target_spec(&self) -> &Target {
&self.tcx.sess.target
}
}
impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>,
tag_type_metadata: Option<&'ll DIType>,
- containing_scope: &'ll DIScope,
common_members: Vec<Option<&'ll DIType>>,
span: Span,
}
_ => bug!(),
};
- // This will always find the metadata in the type map.
let fallback = use_enum_fallback(cx);
- let self_metadata = if fallback {
- self.containing_scope
- } else {
- type_metadata(cx, self.enum_type, self.span)
- };
+ // This will always find the metadata in the type map.
+ let self_metadata = type_metadata(cx, self.enum_type, self.span);
match self.layout.variants {
Variants::Single { index } => {
cx,
self.layout,
variant_info,
- NoTag,
+ None,
self_metadata,
self.span,
);
..
} => {
let tag_info = if fallback {
- RegularTag {
+ // For MSVC, we generate a union of structs for each variant with an explicit
+ // discriminant field roughly equivalent to the following C:
+ // ```c
+ // union enum$<{name}> {
+ // struct {variant 0 name} {
+ // tag$ variant$;
+ // <variant 0 fields>
+ // } variant0;
+ // <other variant structs>
+ // }
+ // ```
+ // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
+ // determine which variant is active and then displays it.
+ Some(DirectTag {
tag_field: Field::from(tag_field),
tag_type_metadata: self.tag_type_metadata.unwrap(),
- }
+ })
} else {
// This doesn't matter in this case.
- NoTag
+ None
};
variants
.iter_enumerated()
MemberDescription {
name: if fallback {
- String::new()
+ format!("variant{}", i.as_u32())
} else {
variant_info.variant_name()
},
ref variants,
tag_field,
} => {
+ let calculate_niche_value = |i: VariantIdx| {
+ if i == dataful_variant {
+ None
+ } else {
+ let value = (i.as_u32() as u128)
+ .wrapping_sub(niche_variants.start().as_u32() as u128)
+ .wrapping_add(niche_start);
+ let value = tag.value.size(cx).truncate(value);
+ // NOTE(eddyb) do *NOT* remove this assert, until
+ // we pass the full 128-bit value to LLVM, otherwise
+ // truncation will be silent and remain undetected.
+ assert_eq!(value as u64 as u128, value);
+ Some(value as u64)
+ }
+ };
+
+ // For MSVC, we will generate a union of two fields, one for the dataful variant
+ // and one that just points to the discriminant. We also create an enum that
+ // contains tag values for the non-dataful variants and make the discriminant field
+ // that type. We then use natvis to render the enum type correctly in Windbg/VS.
+ // This will generate debuginfo roughly equivalent to the following C:
+ // ```c
+ // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
+ // struct <dataful variant name> {
+ // <fields in dataful variant>
+ // } dataful_variant;
+ // enum Discriminant$ {
+ // <non-dataful variants>
+ // } discriminant;
+ // }
+ // ```
+ // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
+ // and evaluates `this.discriminant`. If the value is between the min niche and max
+ // niche, then the enum is in the dataful variant and `this.dataful_variant` is
+ // rendered. Otherwise, the enum is in one of the non-dataful variants. In that
+ // case, we just need to render the name of the `this.discriminant` enum.
if fallback {
- let variant = self.layout.for_variant(cx, dataful_variant);
- // Create a description of the non-null variant.
- let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+ let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant);
+
+ let mut discr_enum_ty = tag.value.to_ty(cx.tcx);
+ // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
+ // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
+ // to just be `usize`.
+ if let ty::RawPtr(_) = discr_enum_ty.kind() {
+ discr_enum_ty = cx.tcx.types.usize;
+ }
+
+ let tags: Vec<_> = variants
+ .iter_enumerated()
+ .filter_map(|(variant_idx, _)| {
+ calculate_niche_value(variant_idx).map(|tag| {
+ let variant = variant_info_for(variant_idx);
+ let name = variant.variant_name();
+
+ Some(unsafe {
+ llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ tag as i64,
+ !discr_enum_ty.is_signed(),
+ )
+ })
+ })
+ })
+ .collect();
+
+ let discr_enum = unsafe {
+ llvm::LLVMRustDIBuilderCreateEnumerationType(
+ DIB(cx),
+ self_metadata,
+ "Discriminant$".as_ptr().cast(),
+ "Discriminant$".len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ tag.value.size(cx).bits(),
+ tag.value.align(cx).abi.bits() as u32,
+ create_DIArray(DIB(cx), &tags),
+ type_metadata(cx, discr_enum_ty, self.span),
+ true,
+ )
+ };
+
+ let variant_info = variant_info_for(dataful_variant);
+ let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
cx,
- variant,
- variant_info_for(dataful_variant),
- OptimizedTag,
- self.containing_scope,
+ dataful_variant_layout,
+ variant_info,
+ Some(NicheTag),
+ self_metadata,
self.span,
);
- let variant_member_descriptions =
- member_description_factory.create_member_descriptions(cx);
+ let member_descriptions = member_desc_factory.create_member_descriptions(cx);
set_members_of_composite_type(
cx,
self.enum_type,
variant_type_metadata,
- variant_member_descriptions,
+ member_descriptions,
Some(&self.common_members),
);
- // Encode the information about the null variant in the union
- // member's name.
- let mut name = String::from("RUST$ENCODED$ENUM$");
- // Right now it's not even going to work for `niche_start > 0`,
- // and for multiple niche variants it only supports the first.
- fn compute_field_path<'a, 'tcx>(
- cx: &CodegenCx<'a, 'tcx>,
- name: &mut String,
- layout: TyAndLayout<'tcx>,
- offset: Size,
- size: Size,
- ) {
- for i in 0..layout.fields.count() {
- let field_offset = layout.fields.offset(i);
- if field_offset > offset {
- continue;
- }
- let inner_offset = offset - field_offset;
- let field = layout.field(cx, i);
- if inner_offset + size <= field.size {
- write!(name, "{}$", i).unwrap();
- compute_field_path(cx, name, field, inner_offset, size);
- }
- }
- }
- compute_field_path(
- cx,
- &mut name,
- self.layout,
- self.layout.fields.offset(tag_field),
- self.layout.field(cx, tag_field).size,
- );
- let variant_info = variant_info_for(*niche_variants.start());
- variant_info.map_struct_name(|variant_name| {
- name.push_str(variant_name);
- });
-
- // Create the (singleton) list of descriptions of union members.
- vec![MemberDescription {
- name,
- type_metadata: variant_type_metadata,
- offset: Size::ZERO,
- size: variant.size,
- align: variant.align.abi,
- flags: DIFlags::FlagZero,
- discriminant: None,
- source_info: variant_info.source_info(cx),
- }]
+ let (size, align) =
+ cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty);
+
+ vec![
+ MemberDescription {
+ // Name the dataful variant so that we can identify it for natvis
+ name: "dataful_variant".to_string(),
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: self.layout.size,
+ align: self.layout.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: variant_info.source_info(cx),
+ },
+ MemberDescription {
+ name: "discriminant".into(),
+ type_metadata: discr_enum,
+ offset: dataful_variant_layout.fields.offset(tag_field),
+ size,
+ align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ ]
} else {
variants
.iter_enumerated()
cx,
variant,
variant_info,
- OptimizedTag,
+ Some(NicheTag),
self_metadata,
self.span,
);
Some(&self.common_members),
);
- let niche_value = if i == dataful_variant {
- None
- } else {
- let value = (i.as_u32() as u128)
- .wrapping_sub(niche_variants.start().as_u32() as u128)
- .wrapping_add(niche_start);
- let value = tag.value.size(cx).truncate(value);
- // NOTE(eddyb) do *NOT* remove this assert, until
- // we pass the full 128-bit value to LLVM, otherwise
- // truncation will be silent and remain undetected.
- assert_eq!(value as u64 as u128, value);
- Some(value as u64)
- };
+ let niche_value = calculate_niche_value(i);
MemberDescription {
name: variant_info.variant_name(),
}
}
-// FIXME: terminology here should be aligned with `abi::TagEncoding`.
-// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
-// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
#[derive(Copy, Clone)]
enum EnumTagInfo<'ll> {
- RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
- OptimizedTag,
- NoTag,
+ DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+ NicheTag,
}
#[derive(Copy, Clone)]
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
- discriminant_info: EnumTagInfo<'ll>,
+ discriminant_info: Option<EnumTagInfo<'ll>>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
- RegularTag { tag_field, .. } => {
+ Some(DirectTag { tag_field, .. }) => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
let offset = enum_layout.fields.offset(tag_field.as_usize());
- let args =
- ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
+ let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
(Some(offset), Some(args))
}
_ => (None, None),
offsets,
args,
tag_type_metadata: match discriminant_info {
- RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
+ Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
_ => None,
},
span,
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
- Variants::Single { .. }
- | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
- Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+ Variants::Single { .. } => None,
+ Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
+ | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
Some(discriminant_type_metadata(tag.value))
}
};
unsafe {
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
- containing_scope,
+ None,
enum_name.as_ptr().cast(),
enum_name.len(),
file_metadata,
enum_type,
layout,
tag_type_metadata: discriminant_type_metadata,
- containing_scope,
common_members: vec![],
span,
}),
enum_type,
layout,
tag_type_metadata: None,
- containing_scope,
common_members: outer_fields,
span,
}),
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
- containing_scope,
+ Some(containing_scope),
union_type_name.as_ptr().cast(),
union_type_name.len(),
unknown_file_metadata(cx),
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
use back::write::{create_informational_target_machine, create_target_machine};
// LLVMRustVisibility
#[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Visibility {
Default = 0,
Hidden = 1,
extern "C" {
pub type PassManagerBuilder;
}
-extern "C" {
- pub type ObjectFile;
-}
-#[repr(C)]
-pub struct SectionIterator<'a>(InvariantOpaque<'a>);
extern "C" {
pub type Pass;
}
pub fn LLVMDeleteGlobal(GlobalVar: &Value);
pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+ pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
pub fn LLVMDisposeMessage(message: *mut c_char);
- // Stuff that's in llvm-wrapper/ because it's not upstream yet.
-
- /// Opens an object file.
- pub fn LLVMCreateObjectFile(
- MemBuf: &'static mut MemoryBuffer,
- ) -> Option<&'static mut ObjectFile>;
- /// Closes an object file.
- pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
-
- /// Enumerates the sections in an object file.
- pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
- /// Destroys a section iterator.
- pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
- /// Returns `true` if the section iterator is at the end of the section
- /// list:
- pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
- /// Moves the section iterator to point to the next section.
- pub fn LLVMMoveToNextSection(SI: &SectionIterator<'_>);
- /// Returns the current section size.
- pub fn LLVMGetSectionSize(SI: &SectionIterator<'_>) -> c_ulonglong;
- /// Returns the current section contents as a string buffer.
- pub fn LLVMGetSectionContents(SI: &SectionIterator<'_>) -> *const c_char;
-
- /// Reads the given file and returns it as a memory buffer. Use
- /// LLVMDisposeMemoryBuffer() to get rid of it.
- pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
- Path: *const c_char,
- ) -> Option<&'static mut MemoryBuffer>;
-
pub fn LLVMStartMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustDIBuilderCreateUnionType(
Builder: &DIBuilder<'a>,
- Scope: &'a DIScope,
+ Scope: Option<&'a DIScope>,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
- #[allow(improper_ctypes)]
- pub fn LLVMRustGetSectionName(
- SI: &SectionIterator<'_>,
- data: &mut Option<std::ptr::NonNull<c_char>>,
- ) -> size_t;
-
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
}
}
-// Memory-managed interface to object files.
-
-pub struct ObjectFile {
- pub llof: &'static mut ffi::ObjectFile,
-}
-
-unsafe impl Send for ObjectFile {}
-
-impl ObjectFile {
- // This will take ownership of llmb
- pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
- unsafe {
- let llof = LLVMCreateObjectFile(llmb)?;
- Some(ObjectFile { llof })
- }
- }
-}
-
-impl Drop for ObjectFile {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
- }
- }
-}
-
-// Memory-managed interface to section iterators.
-
-pub struct SectionIter<'a> {
- pub llsi: &'a mut SectionIterator<'a>,
-}
-
-impl Drop for SectionIter<'a> {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
- }
- }
-}
-
-pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
- unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
-}
-
pub fn set_section(llglobal: &Value, section_name: &str) {
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
unsafe {
unsafe {
llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(g, false) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
attributes::from_fn_attrs(self, lldecl, instance);
unsafe {
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(lldecl, false) {
llvm::LLVMRustSetDSOLocal(lldecl, true);
}
}
}
impl CodegenCx<'ll, 'tcx> {
- /// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
+ /// Whether a definition or declaration can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
pub(crate) unsafe fn should_assume_dso_local(
&self,
- linkage: Linkage,
- visibility: Visibility,
+ llval: &llvm::Value,
+ is_declaration: bool,
) -> bool {
- if matches!(linkage, Linkage::Internal | Linkage::Private) {
+ let linkage = llvm::LLVMRustGetLinkage(llval);
+ let visibility = llvm::LLVMRustGetVisibility(llval);
+
+ if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
return true;
}
- if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
+ if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage
+ {
return true;
}
- // Static relocation model should force copy relocations everywhere.
- if self.tcx.sess.relocation_model() == RelocModel::Static {
+ // Symbols from executables can't really be imported any further.
+ let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable);
+ let is_declaration_for_linker =
+ is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
+ if all_exe && !is_declaration_for_linker {
return true;
}
- // Symbols from executables can't really be imported any further.
- if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+ // PowerPC64 prefers TOC indirection to avoid copy relocations.
+ if matches!(&*self.tcx.sess.target.arch, "powerpc64" | "powerpc64le") {
+ return false;
+ }
+
+ // Thread-local variables generally don't support copy relocations.
+ let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
+ .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True)
+ .unwrap_or(false);
+ if is_thread_local_var {
+ return false;
+ }
+
+ // Static relocation model should force copy relocations everywhere.
+ if self.tcx.sess.relocation_model() == RelocModel::Static {
return true;
}
[dependencies]
bitflags = "1.2.1"
-cc = "1.0.67"
+cc = "1.0.68"
itertools = "0.9"
tracing = "0.1"
libc = "0.2.50"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_attr = { path = "../rustc_attr" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
-rustc_data_structures = { path = "../rustc_data_structures"}
+rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_session = { path = "../rustc_session" }
[dependencies.object]
-version = "0.22.0"
+version = "0.25.2"
default-features = false
-features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"]
+features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
use rustc_errors::Handler;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
+use rustc_middle::middle::cstore::LibSource;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
+use rustc_target::abi::Endian;
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
};
use cc::windows_registry;
+use object::elf;
+use object::write::Object;
+use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
use tempfile::Builder as TempFileBuilder;
use std::ffi::OsString;
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
/// directory being searched for `extern crate` (observing an incomplete file).
/// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
+pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
- let result = fs::write(&out_filename, &metadata.raw_data);
+ let result = fs::write(&out_filename, metadata);
if let Err(e) = result {
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
// code above.
match flavor {
RlibFlavor::Normal => {
- // Instead of putting the metadata in an object file section, rlibs
- // contain the metadata in a separate file.
- ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
+ // metadata in rlib files is wrapped in a "dummy" object file for
+ // the target platform so the rlib can be processed entirely by
+ // normal linkers for the platform.
+ let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
+ ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
// After adding all files to the archive, we need to update the
// symbol table of the archive. This currently dies on macOS (see
}
}
}
+ return ab;
- ab
+ // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
+ // creates a dylib crate type it will pass `--whole-archive` (or the
+ // platform equivalent) to include all object files from an rlib into the
+ // final dylib itself. This causes linkers to iterate and try to include all
+ // files located in an archive, so if metadata is stored in an archive then
+ // it needs to be of a form that the linker will be able to process.
+ //
+ // Note, though, that we don't actually want this metadata to show up in any
+ // final output of the compiler. Instead this is purely for rustc's own
+ // metadata tracking purposes.
+ //
+ // With the above in mind, each "flavor" of object format gets special
+ // handling here depending on the target:
+ //
+ // * MachO - macos-like targets will insert the metadata into a section that
+ // is sort of fake dwarf debug info. Inspecting the source of the macos
+ // linker this causes these sections to be skipped automatically because
+ // it's not in an allowlist of otherwise well known dwarf section names to
+ // go into the final artifact.
+ //
+ // * WebAssembly - we actually don't have any container format for this
+ // target. WebAssembly doesn't support the `dylib` crate type anyway so
+ // there's no need for us to support this at this time. Consequently the
+ // metadata bytes are simply stored as-is into an rlib.
+ //
+ // * COFF - Windows-like targets create an object with a section that has
+ // the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
+ // ever sees the section it doesn't process it and it's removed.
+ //
+ // * ELF - All other targets are similar to Windows in that there's a
+ // `SHF_EXCLUDE` flag we can set on sections in an object file to get
+ // automatically removed from the final output.
+ //
+ // Note that this metdata format is kept in sync with
+ // `rustc_codegen_ssa/src/back/metadata.rs`.
+ fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+ let endianness = match sess.target.options.endian {
+ Endian::Little => Endianness::Little,
+ Endian::Big => Endianness::Big,
+ };
+ let architecture = match &sess.target.arch[..] {
+ "arm" => Architecture::Arm,
+ "aarch64" => Architecture::Aarch64,
+ "x86" => Architecture::I386,
+ "s390x" => Architecture::S390x,
+ "mips" => Architecture::Mips,
+ "mips64" => Architecture::Mips64,
+ "x86_64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::X86_64_X32
+ } else {
+ Architecture::X86_64
+ }
+ }
+ "powerpc" => Architecture::PowerPc,
+ "powerpc64" => Architecture::PowerPc64,
+ "riscv32" => Architecture::Riscv32,
+ "riscv64" => Architecture::Riscv64,
+ "sparc64" => Architecture::Sparc64,
+
+ // This is used to handle all "other" targets. This includes targets
+ // in two categories:
+ //
+ // * Some targets don't have support in the `object` crate just yet
+ // to write an object file. These targets are likely to get filled
+ // out over time.
+ //
+ // * Targets like WebAssembly don't support dylibs, so the purpose
+ // of putting metadata in object files, to support linking rlibs
+ // into dylibs, is moot.
+ //
+ // In both of these cases it means that linking into dylibs will
+ // not be supported by rustc. This doesn't matter for targets like
+ // WebAssembly and for targets not supported by the `object` crate
+ // yet it means that work will need to be done in the `object` crate
+ // to add a case above.
+ _ => return metadata.to_vec(),
+ };
+
+ if sess.target.is_like_osx {
+ let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
+
+ let section =
+ file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else if sess.target.is_like_windows {
+ const IMAGE_SCN_LNK_REMOVE: u32 = 0;
+ let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags =
+ SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else {
+ const SHF_EXCLUDE: u64 = 0x80000000;
+ let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
+
+ match &sess.target.arch[..] {
+ // copied from `mipsel-linux-gnu-gcc foo.c -c` and
+ // inspecting the resulting `e_flags` field.
+ "mips" => {
+ let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
+ "mips64" => {
+ let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
+ // that the `+d` target feature represents whether the double
+ // float abi is enabled.
+ "riscv64" if sess.target.options.features.contains("+d") => {
+ let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ _ => {}
+ }
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ }
+ }
}
/// Create a static archive.
let search_path = archive_search_paths(sess);
let mut last = (NativeLibKind::Unspecified, None);
for lib in relevant_libs {
- // Skip if this library is the same as the last.
- last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
-
let name = match lib.name {
Some(l) => l,
None => continue,
};
+
+ // Skip if this library is the same as the last.
+ last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
let verbatim = lib.verbatim.unwrap_or(false);
match lib.kind {
NativeLibKind::Dylib { as_needed } => {
}
// Adds the static "rlib" versions of all crates to the command line.
- // There's a bit of magic which happens here specifically related to LTO and
- // dynamic libraries. Specifically:
- //
- // * For LTO, we remove upstream object files.
- // * For dylibs we remove metadata and bytecode from upstream rlibs
+ // There's a bit of magic which happens here specifically related to LTO,
+ // namely that we remove upstream object files.
//
// When performing LTO, almost(*) all of the bytecode from the upstream
// libraries has already been included in our object file output. As a
// their bytecode wasn't included. The object files in those libraries must
// still be passed to the linker.
//
- // When making a dynamic library, linkers by default don't include any
- // object files in an archive if they're not necessary to resolve the link.
- // We basically want to convert the archive (rlib) to a dylib, though, so we
- // *do* want everything included in the output, regardless of whether the
- // linker thinks it's needed or not. As a result we must use the
- // --whole-archive option (or the platform equivalent). When using this
- // option the linker will fail if there are non-objects in the archive (such
- // as our own metadata and/or bytecode). All in all, for rlibs to be
- // entirely included in dylibs, we need to remove all non-object files.
- //
- // Note, however, that if we're not doing LTO or we're not producing a dylib
- // (aka we're making an executable), we can just pass the rlib blindly to
- // the linker (fast) because it's fine if it's not actually included as
- // we're at the end of the dependency chain.
+ // Note, however, that if we're not doing LTO we can just pass the rlib
+ // blindly to the linker (fast) because it's fine if it's not actually
+ // included as we're at the end of the dependency chain.
fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
cmd: &mut dyn Linker,
sess: &'a Session,
let src = &codegen_results.crate_info.used_crate_source[&cnum];
let cratepath = &src.rlib.as_ref().unwrap().0;
+ let mut link_upstream = |path: &Path| {
+ // If we're creating a dylib, then we need to include the
+ // whole of each object in our archive into that artifact. This is
+ // because a `dylib` can be reused as an intermediate artifact.
+ //
+ // Note, though, that we don't want to include the whole of a
+ // compiler-builtins crate (e.g., compiler-rt) because it'll get
+ // repeatedly linked anyway.
+ let path = fix_windows_verbatim_for_gcc(path);
+ if crate_type == CrateType::Dylib
+ && codegen_results.crate_info.compiler_builtins != Some(cnum)
+ {
+ cmd.link_whole_rlib(&path);
+ } else {
+ cmd.link_rlib(&path);
+ }
+ };
+
// See the comment above in `link_staticlib` and `link_rlib` for why if
// there's a static library that's not relevant we skip all object
// files.
if (!are_upstream_rust_objects_already_included(sess)
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
- && crate_type != CrateType::Dylib
&& !skip_native
{
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
+ link_upstream(cratepath);
return;
}
return;
}
archive.build();
-
- // If we're creating a dylib, then we need to include the
- // whole of each object in our archive into that artifact. This is
- // because a `dylib` can be reused as an intermediate artifact.
- //
- // Note, though, that we don't want to include the whole of a
- // compiler-builtins crate (e.g., compiler-rt) because it'll get
- // repeatedly linked anyway.
- if crate_type == CrateType::Dylib
- && codegen_results.crate_info.compiler_builtins != Some(cnum)
- {
- cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
- } else {
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
- }
+ link_upstream(&dst);
});
}
let mut last = (NativeLibKind::Unspecified, None);
for &(cnum, _) in crates {
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
- // Skip if this library is the same as the last.
- last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
-
let name = match lib.name {
Some(l) => l,
None => continue,
if !relevant_lib(sess, &lib) {
continue;
}
+
+ // Skip if this library is the same as the last.
+ last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
let verbatim = lib.verbatim.unwrap_or(false);
match lib.kind {
NativeLibKind::Dylib { as_needed } => {
use std::fs::File;
use std::path::Path;
+use object::{Object, ObjectSection};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
let entry = entry_result
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
if entry.name() == METADATA_FILENAME.as_bytes() {
- return Ok(entry.data());
+ let data = entry
+ .data(data)
+ .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
+ return search_for_metadata(path, data, ".rmeta");
}
}
}
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
- use object::{Object, ObjectSection};
-
- load_metadata_with(path, |data| {
- let file = object::File::parse(&data)
- .map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?;
- file.section_by_name(".rustc")
- .ok_or_else(|| format!("no .rustc section in '{}'", path.display()))?
- .data()
- .map_err(|e| {
- format!("failed to read .rustc section in '{}': {}", path.display(), e)
- })
- })
+ load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc"))
}
}
+
+fn search_for_metadata<'a>(
+ path: &Path,
+ bytes: &'a [u8],
+ section: &str,
+) -> Result<&'a [u8], String> {
+ let file = match object::File::parse(bytes) {
+ Ok(f) => f,
+ // The parse above could fail for odd reasons like corruption, but for
+ // now we just interpret it as this target doesn't support metadata
+ // emission in object files so the entire byte slice itself is probably
+ // a metadata file. Ideally though if necessary we could at least check
+ // the prefix of bytes to see if it's an actual metadata object and if
+ // not forward the error along here.
+ Err(_) => return Ok(bytes),
+ };
+ file.section_by_name(section)
+ .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
+ .data()
+ .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
+}
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
/// for a gap area is only used as the line execution count if there are no other regions on a
/// line."
+#[derive(Debug)]
pub struct FunctionCoverage<'tcx> {
instance: Instance<'tcx>,
source_hash: u64,
expression_id, lhs, op, rhs, region
);
let expression_index = self.expression_index(u32::from(expression_id));
+ debug_assert!(
+ expression_index.as_usize() < self.expressions.len(),
+ "expression_index {} is out of range for expressions.len() = {}
+ for {:?}",
+ expression_index.as_usize(),
+ self.expressions.len(),
+ self,
+ );
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
lhs,
op,
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
+use rustc_target::abi::{TagEncoding, Variants};
use std::fmt::Write;
ty::Float(float_ty) => output.push_str(float_ty.name_str()),
ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
ty::Adt(def, substs) => {
- push_item_name(tcx, def.did, qualified, output);
- push_type_params(tcx, substs, output, visited);
+ if def.is_enum() && cpp_like_names {
+ msvc_enum_fallback(tcx, t, def, substs, output, visited);
+ } else {
+ push_item_name(tcx, def.did, qualified, output);
+ push_type_params(tcx, substs, output, visited);
+ }
}
ty::Tuple(component_types) => {
if cpp_like_names {
}
}
+ /// MSVC names enums differently than other platforms so that the debugging visualization
+ // format (natvis) is able to understand enums and render the active variant correctly in the
+ // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
+ // `EnumMemberDescriptionFactor::create_member_descriptions`.
+ fn msvc_enum_fallback(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ def: &AdtDef,
+ substs: SubstsRef<'tcx>,
+ output: &mut String,
+ visited: &mut FxHashSet<Ty<'tcx>>,
+ ) {
+ let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
+
+ if let Variants::Multiple {
+ tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+ tag,
+ variants,
+ ..
+ } = &layout.variants
+ {
+ let dataful_variant_layout = &variants[*dataful_variant];
+
+ // calculate the range of values for the dataful variant
+ let dataful_discriminant_range =
+ &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
+
+ let min = dataful_discriminant_range.start();
+ let min = tag.value.size(&tcx).truncate(*min);
+
+ let max = dataful_discriminant_range.end();
+ let max = tag.value.size(&tcx).truncate(*max);
+
+ output.push_str("enum$<");
+ push_item_name(tcx, def.did, true, output);
+ push_type_params(tcx, substs, output, visited);
+
+ let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+
+ output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
+ } else {
+ output.push_str("enum$<");
+ push_item_name(tcx, def.did, true, output);
+ push_type_params(tcx, substs, output, visited);
+ output.push('>');
+ }
+ }
+
fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
if qualified {
output.push_str(&tcx.crate_name(def_id.krate).as_str());
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(assert_matches)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(drain_filter)]
#![feature(try_blocks)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(associated_type_bounds)]
-#![feature(iter_zip)]
#![recursion_limit = "256"]
-#![feature(box_syntax)]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
};
use rustc_middle::mir::{self, Location, TerminatorKind};
-use rustc_middle::ty;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::LayoutOf;
self.visit_rvalue(rvalue, location);
}
- fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
- let check = match terminator.kind {
- mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
- match *c.ty().kind() {
- ty::FnDef(did, _) => Some((did, args)),
- _ => None,
- }
- }
- _ => None,
- };
- if let Some((def_id, args)) = check {
- if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
- // box_free(x) shares with `drop x` the property that it
- // is not guaranteed to be statically dominated by the
- // definition of x, so x must always be in an alloca.
- if let mir::Operand::Move(ref place) = args[0] {
- self.visit_place(
- place,
- PlaceContext::MutatingUse(MutatingUseContext::Drop),
- location,
- );
- }
- }
- }
-
- self.super_terminator(terminator, location);
- }
-
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
self.process_place(&place.as_ref(), context, location);
version = "0.11"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi"] }
+winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
memmap2 = "0.2.1"
Ok(Lock { _file: file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+ }
}
// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
Ok(Lock { file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+ }
}
impl Drop for Lock {
use std::mem;
use std::os::windows::prelude::*;
+ use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
use winapi::um::fileapi::LockFileEx;
use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
Ok(Lock { _file: file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+ }
}
// Note that we don't need a Drop impl on the Windows: The file is unlocked
#![feature(array_windows)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
-#![feature(unboxed_closures)]
#![feature(generator_trait)]
-#![feature(fn_traits)]
#![feature(min_specialization)]
#![feature(auto_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
-#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
Some(rpos) => {
// Cycle detected.
processor.process_backedge(
- stack[rpos..].iter().map(GetObligation(&self.nodes)),
+ stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
PhantomData,
);
}
});
}
}
-
-// I need a Clone closure.
-#[derive(Clone)]
-struct GetObligation<'a, O>(&'a [Node<O>]);
-
-impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
- type Output = &'a O;
- extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
- &self.0[*args.0].obligation
- }
-}
-
-impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
- extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
- &self.0[*args.0].obligation
- }
-}
entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
entries.hash_stable(hcx, hasher);
}
-
-/// A vector container that makes sure that its items are hashed in a stable
-/// order.
-#[derive(Debug)]
-pub struct StableVec<T>(Vec<T>);
-
-impl<T> StableVec<T> {
- pub fn new(v: Vec<T>) -> Self {
- StableVec(v)
- }
-}
-
-impl<T> ::std::ops::Deref for StableVec<T> {
- type Target = Vec<T>;
-
- fn deref(&self) -> &Vec<T> {
- &self.0
- }
-}
-
-impl<T, HCX> HashStable<HCX> for StableVec<T>
-where
- T: HashStable<HCX> + ToStableHashKey<HCX>,
-{
- fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- let StableVec(ref v) = *self;
-
- let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect();
- sorted.sort_unstable();
- sorted.hash_stable(hcx, hasher);
- }
-}
use std::ops::Add;
use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
- /// This is a single threaded variant of AtomicCell provided by crossbeam.
- /// Unlike `Atomic` this is intended for all `Copy` types,
- /// but it lacks the explicit ordering arguments.
- #[derive(Debug)]
- pub struct AtomicCell<T: Copy>(Cell<T>);
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn new(v: T) -> Self {
- AtomicCell(Cell::new(v))
- }
-
- #[inline]
- pub fn get_mut(&mut self) -> &mut T {
- self.0.get_mut()
- }
- }
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn into_inner(self) -> T {
- self.0.into_inner()
- }
-
- #[inline]
- pub fn load(&self) -> T {
- self.0.get()
- }
-
- #[inline]
- pub fn store(&self, val: T) {
- self.0.set(val)
- }
-
- #[inline]
- pub fn swap(&self, val: T) -> T {
- self.0.replace(val)
- }
- }
-
/// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
- /// It differs from `AtomicCell` in that it has explicit ordering arguments
- /// and is only intended for use with the native atomic types.
+ /// It has explicit ordering arguments and is only intended for use with
+ /// the native atomic types.
/// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
/// as it's not intended to be used separately.
#[derive(Debug)]
(oper_a(), oper_b())
}
- pub struct SerialScope;
-
- impl SerialScope {
- pub fn spawn<F>(&self, f: F)
- where F: FnOnce(&SerialScope)
- {
- f(self)
- }
- }
-
- pub fn scope<F, R>(f: F) -> R
- where F: FnOnce(&SerialScope) -> R
- {
- f(&SerialScope)
- }
-
#[macro_export]
macro_rules! parallel {
($($blocks:tt),*) => {
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
- pub use crossbeam_utils::atomic::AtomicCell;
-
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;
unsafe impl<T> Pointer for Box<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Box::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Box::from_raw(ptr as *mut T)
}
unsafe impl<T> Pointer for Rc<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Rc::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Rc::from_raw(ptr as *const T)
}
unsafe impl<T> Pointer for Arc<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Arc::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Arc::from_raw(ptr as *const T)
}
unsafe impl<'a, T: 'a> Pointer for &'a T {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *const T as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&*(ptr as *const T)
}
unsafe impl<'a, T: 'a> Pointer for &'a mut T {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *mut T as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&mut *(ptr as *mut T)
}
self.inner.borrow_mut().bug(msg)
}
+ #[inline]
pub fn err_count(&self) -> usize {
self.inner.borrow().err_count()
}
}
}
+ #[inline]
fn err_count(&self) -> usize {
self.err_count + self.stashed_diagnostics.len()
}
self.resolver.check_unused_macros();
}
- /// Resolves a path mentioned inside Rust code.
+ /// Resolves a `path` mentioned inside Rust code, returning an absolute path.
///
- /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+ /// This unifies the logic used for resolving `include_X!`.
///
- /// Returns an absolute path to the file that `path` refers to.
+ /// FIXME: move this to `rustc_builtin_macros` and make it private.
pub fn resolve_path(
&self,
path: impl Into<PathBuf>,
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, is_builtin_attr};
+use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
-use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{ExpnId, FileName, Span};
use smallvec::{smallvec, SmallVec};
-use std::io::ErrorKind;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::rc::Rc;
-use std::{iter, mem, slice};
+use std::{iter, mem};
macro_rules! ast_fragments {
(
noop_flat_map_generic_param(param, self)
}
- fn visit_attribute(&mut self, at: &mut ast::Attribute) {
- // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
- // contents="file contents")]` attributes
- if !self.cx.sess.check_name(at, sym::doc) {
- return noop_visit_attribute(at, self);
- }
-
- if let Some(list) = at.meta_item_list() {
- if !list.iter().any(|it| it.has_name(sym::include)) {
- return noop_visit_attribute(at, self);
- }
-
- let mut items = vec![];
-
- for mut it in list {
- if !it.has_name(sym::include) {
- items.push({
- noop_visit_meta_list_item(&mut it, self);
- it
- });
- continue;
- }
-
- if let Some(file) = it.value_str() {
- let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
- self.check_attributes(slice::from_ref(at));
- if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
- // avoid loading the file if they haven't enabled the feature
- return noop_visit_attribute(at, self);
- }
-
- let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
- Ok(filename) => filename,
- Err(mut err) => {
- err.emit();
- continue;
- }
- };
-
- match self.cx.source_map().load_file(&filename) {
- Ok(source_file) => {
- let src = source_file
- .src
- .as_ref()
- .expect("freshly loaded file should have a source");
- let src_interned = Symbol::intern(src.as_str());
-
- let include_info = vec![
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::file),
- file,
- DUMMY_SP,
- )),
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::contents),
- src_interned,
- DUMMY_SP,
- )),
- ];
-
- let include_ident = Ident::with_dummy_span(sym::include);
- let item = attr::mk_list_item(include_ident, include_info);
- items.push(ast::NestedMetaItem::MetaItem(item));
- }
- Err(e) => {
- let lit_span = it.name_value_literal_span().unwrap();
-
- if e.kind() == ErrorKind::InvalidData {
- self.cx
- .struct_span_err(
- lit_span,
- &format!("{} wasn't a utf-8 file", filename.display()),
- )
- .span_label(lit_span, "contains invalid utf-8")
- .emit();
- } else {
- let mut err = self.cx.struct_span_err(
- lit_span,
- &format!("couldn't read {}: {}", filename.display(), e),
- );
- err.span_label(lit_span, "couldn't read file");
-
- err.emit();
- }
- }
- }
- } else {
- let mut err = self
- .cx
- .struct_span_err(it.span(), "expected path to external documentation");
-
- // Check if the user erroneously used `doc(include(...))` syntax.
- let literal = it.meta_item_list().and_then(|list| {
- if list.len() == 1 {
- list[0].literal().map(|literal| &literal.kind)
- } else {
- None
- }
- });
-
- let (path, applicability) = match &literal {
- Some(LitKind::Str(path, ..)) => {
- (path.to_string(), Applicability::MachineApplicable)
- }
- _ => (String::from("<path>"), Applicability::HasPlaceholders),
- };
-
- err.span_suggestion(
- it.span(),
- "provide a file path with `=`",
- format!("include = \"{}\"", path),
- applicability,
- );
-
- err.emit();
- }
- }
-
- let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
- *at = ast::Attribute {
- kind: ast::AttrKind::Normal(
- AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None },
- None,
- ),
- span: at.span,
- id: at.id,
- style: at.style,
- };
- } else {
- noop_visit_attribute(at, self)
- }
- }
-
fn visit_id(&mut self, id: &mut ast::NodeId) {
if self.monotonic {
debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
-#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
#![feature(iter_zip)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
&sess.parse_sess,
def.id,
features,
+ edition,
)
.pop()
.unwrap();
&sess.parse_sess,
def.id,
features,
+ edition,
)
.pop()
.unwrap();
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
+use rustc_span::edition::Edition;
+use rustc_span::{Span, SyntaxContext};
use rustc_data_structures::sync::Lrc;
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `node_id`: the NodeId of the macro we are parsing.
/// - `features`: language features so we can do feature gating.
+/// - `edition`: the edition of the crate defining the macro
///
/// # Returns
///
sess: &ParseSess,
node_id: NodeId,
features: &Features,
+ edition: Edition,
) -> Vec<TokenTree> {
// Will contain the final collection of `self::TokenTree`
let mut result = Vec::new();
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
- let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
+ let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
match tree {
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
let span = match trees.next() {
let kind =
token::NonterminalKind::from_symbol(frag.name, || {
- span.edition()
+ // FIXME(#85708) - once we properly decode a foreign
+ // crate's `SyntaxContext::root`, then we can replace
+ // this with just `span.edition()`. A
+ // `SyntaxContext::root()` from the current crate will
+ // have the edition of the current crate, and a
+ // `SyntaxxContext::root()` from a foreign crate will
+ // have the edition of that crate (which we manually
+ // retrieve via the `edition` parameter).
+ if span.ctxt() == SyntaxContext::root() {
+ edition
+ } else {
+ span.edition()
+ }
})
.unwrap_or_else(
|| {
/// - `expect_matchers`: same as for `parse` (see above).
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `features`: language features so we can do feature gating.
+/// - `edition` - the edition of the crate defining the macro
fn parse_tree(
tree: tokenstream::TokenTree,
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
sess: &ParseSess,
node_id: NodeId,
features: &Features,
+ edition: Edition,
) -> TokenTree {
// Depending on what `tree` is, we could be parsing different parts of a macro
match tree {
sess.span_diagnostic.span_err(span.entire(), &msg);
}
// Parse the contents of the sequence itself
- let sequence = parse(tts, expect_matchers, sess, node_id, features);
+ let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
// Get the Kleene operator and optional separator
let (separator, kleene) =
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
span,
Lrc::new(Delimited {
delim,
- tts: parse(tts, expect_matchers, sess, node_id, features),
+ tts: parse(tts, expect_matchers, sess, node_id, features, edition),
}),
),
}
(accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
/// Allows unsizing coercions in `const fn`.
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+ /// Allows `impl Trait` with multiple unrelated lifetimes.
+ (accepted, member_constraints, "1.54.0", Some(61997), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
- /// Allows `#[doc(include = "some-file")]`.
- (active, external_doc, "1.22.0", Some(44732), None),
-
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),
/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
- /// Allows `impl Trait` with multiple unrelated lifetimes.
- (active, member_constraints, "1.37.0", Some(61997), None),
-
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
sym::capture_disjoint_fields,
sym::inherent_associated_types,
sym::type_alias_impl_trait,
- sym::native_link_modifiers,
- sym::native_link_modifiers_bundle,
- sym::native_link_modifiers_verbatim,
- sym::native_link_modifiers_whole_archive,
- sym::native_link_modifiers_as_needed,
sym::rustc_insignificant_dtor,
sym::unnamed_fields,
];
rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
- rustc_attr!(
- TEST, rustc_dirty, AssumedUsed,
- template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
- ),
rustc_attr!(
TEST, rustc_clean, AssumedUsed,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
(removed, const_fn, "1.54.0", Some(57563), None,
Some("split into finer-grained feature gates")),
+ /// Allows `#[doc(include = "some-file")]`.
+ (removed, external_doc, "1.54.0", Some(44732), None,
+ Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::unhash::UnhashMap;
use rustc_index::vec::IndexVec;
-use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{kw, sym, Symbol};
self.table.index_to_key.len()
}
+ #[inline]
pub fn def_key(&self, id: LocalDefId) -> DefKey {
self.table.def_key(id.local_def_index)
}
}
/// Adds a root definition (no parent) and a few other reserved definitions.
- pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
+ pub fn new(stable_crate_id: StableCrateId) -> Definitions {
let key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
},
};
- let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
let parent_hash = DefPathHash::new(stable_crate_id, 0);
let def_path_hash = key.compute_stable_hash(parent_hash);
// ignore-tidy-filelength
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::DefId;
-crate use crate::hir_id::HirId;
+crate use crate::hir_id::{HirId, ItemLocalId};
use crate::{itemlikevisit, 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::fx::FxHashMap;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
/// they are declared in the static array generated by proc_macro_harness.
pub proc_macros: Vec<HirId>,
- pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
+ /// 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]>,
}
impl FnRetTy<'_> {
+ #[inline]
pub fn span(&self) -> Span {
match *self {
Self::DefaultReturn(span) => span,
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
#![feature(in_band_lifetimes)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::def_id::{DefPathHash, StableCrateId};
#[test]
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).
- let d0 = CrateDisambiguator::from(Fingerprint::new(12, 34));
- let d1 = CrateDisambiguator::from(Fingerprint::new(56, 78));
+ let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]);
+ let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]);
- let h0 = mk_test_hash("foo", d0);
- let h1 = mk_test_hash("foo", d1);
+ let h0 = mk_test_hash(id0);
+ let h1 = mk_test_hash(id1);
assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
assert_ne!(h0.local_hash(), h1.local_hash());
- fn mk_test_hash(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> DefPathHash {
- let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
+ fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
let parent_hash = DefPathHash::new(stable_crate_id, 0);
let key = DefKey {
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
use rustc_ast as ast;
rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_session = { path = "../rustc_session" }
+rustc_errors = { path = "../rustc_errors" }
-//! Debugging code to test fingerprints computed for query results.
-//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
-//! we will compare the fingerprint from the current and from the previous
+//! Debugging code to test fingerprints computed for query results. For each node marked with
+//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
//! compilation session as appropriate:
//!
//! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
use std::vec::Vec;
const EXCEPT: Symbol = sym::except;
-const LABEL: Symbol = sym::label;
const CFG: Symbol = sym::cfg;
// Base and Extra labels to build up the labels
/// For generic cases like inline-assembly, modules, etc.
const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR];
+/// Impl `DepNode`s.
+const LABELS_TRAIT: &[&[&str]] = &[
+ BASE_HIR,
+ &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of],
+];
+
/// Impl `DepNode`s.
const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL];
dirty: Labels,
}
-impl Assertion {
- fn from_clean_labels(labels: Labels) -> Assertion {
- Assertion { clean: labels, dirty: Labels::default() }
- }
-
- fn from_dirty_labels(labels: Labels) -> Assertion {
- Assertion { clean: Labels::default(), dirty: labels }
- }
-}
-
pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
if !tcx.sess.opts.debugging_opts.query_dep_graph {
return;
}
- // can't add `#[rustc_dirty]` etc without opting in to this feature
+ // can't add `#[rustc_clean]` etc without opting in to this feature
if !tcx.features().rustc_attrs {
return;
}
let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
krate.visit_all_item_likes(&mut dirty_clean_visitor);
- let mut all_attrs = FindAllAttrs {
- tcx,
- attr_names: &[sym::rustc_dirty, sym::rustc_clean],
- found_attrs: vec![],
- };
+ let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
intravisit::walk_crate(&mut all_attrs, krate);
// Note that we cannot use the existing "unused attribute"-infrastructure
impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
- let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
- false
- } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
- true
- } else {
+ if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
// skip: not rustc_clean/dirty
return None;
- };
+ }
if !check_config(self.tcx, attr) {
// skip: not the correct `cfg=`
return None;
}
- let assertion = if let Some(labels) = self.labels(attr) {
- if is_clean {
- Assertion::from_clean_labels(labels)
- } else {
- Assertion::from_dirty_labels(labels)
- }
- } else {
- self.assertion_auto(item_id, attr, is_clean)
- };
+ let assertion = self.assertion_auto(item_id, attr);
Some(assertion)
}
/// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
- fn assertion_auto(
- &mut self,
- item_id: LocalDefId,
- attr: &Attribute,
- is_clean: bool,
- ) -> Assertion {
+ fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
let (name, mut auto) = self.auto_labels(item_id, attr);
let except = self.except(attr);
for e in except.iter() {
self.tcx.sess.span_fatal(attr.span, &msg);
}
}
- if is_clean {
- Assertion { clean: auto, dirty: except }
- } else {
- Assertion { clean: except, dirty: auto }
- }
- }
-
- fn labels(&self, attr: &Attribute) -> Option<Labels> {
- for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
- if item.has_name(LABEL) {
- let value = expect_associated_value(self.tcx, &item);
- return Some(self.resolve_labels(&item, value));
- }
- }
- None
+ Assertion { clean: auto, dirty: except }
}
/// `except=` attribute value
HirItem::Union(..) => ("ItemUnion", LABELS_ADT),
// Represents a Trait Declaration
- // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
- // the depnodes don't exist (because they legitimately didn't need to be
- // calculated)
- //
- // michaelwoerister and vitiral came up with a possible solution,
- // to just do this before every query
- // ```
- // ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node)
- // ```
- //
- // However, this did not seem to work effectively and more bugs were hit.
- // Nebie @vitiral gave up :)
- //
- //HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
+ HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
// An implementation, eg `impl<A> Trait for Foo { .. }`
HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
}
}
-/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
-/// for a `cfg="foo"` attribute and check whether we have a cfg
-/// flag called `foo`.
-///
-/// Also make sure that the `label` and `except` fields do not
-/// both exist.
+/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
+/// a cfg flag called `foo`.
fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
debug!("check_config(attr={:?})", attr);
let config = &tcx.sess.parse_sess.config;
debug!("check_config: config={:?}", config);
- let (mut cfg, mut except, mut label) = (None, false, false);
+ let mut cfg = None;
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.has_name(CFG) {
let value = expect_associated_value(tcx, &item);
debug!("check_config: searching for cfg {:?}", value);
cfg = Some(config.contains(&(value, None)));
- }
- if item.has_name(LABEL) {
- label = true;
- }
- if item.has_name(EXCEPT) {
- except = true;
+ } else if !item.has_name(EXCEPT) {
+ tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
}
}
- if label && except {
- tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`");
- }
-
match cfg {
None => tcx.sess.span_fatal(attr.span, "no cfg attribute"),
Some(c) => c,
}
}
-// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
+// A visitor that collects all #[rustc_clean] attributes from
// the HIR. It is used to verify that we really ran checks for all annotated
// nodes.
-pub struct FindAllAttrs<'a, 'tcx> {
+pub struct FindAllAttrs<'tcx> {
tcx: TyCtxt<'tcx>,
- attr_names: &'a [Symbol],
found_attrs: Vec<&'tcx Attribute>,
}
-impl FindAllAttrs<'_, 'tcx> {
+impl FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
- for attr_name in self.attr_names {
- if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
- return true;
- }
+ if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
+ return true;
}
false
fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
for attr in &self.found_attrs {
if !checked_attrs.contains(&attr.id) {
- self.tcx.sess.span_err(
- attr.span,
- "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
- );
+ self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
checked_attrs.insert(attr.id);
}
}
}
}
-impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> {
+impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::{base_n, flock};
+use rustc_errors::ErrorReported;
use rustc_fs_util::{link_or_copy, LinkOrCopy};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
use std::fs as std_fs;
use std::io;
pub fn prepare_session_directory(
sess: &Session,
crate_name: &str,
- crate_disambiguator: CrateDisambiguator,
-) {
+ stable_crate_id: StableCrateId,
+) -> Result<(), ErrorReported> {
if sess.opts.incremental.is_none() {
- return;
+ return Ok(());
}
let _timer = sess.timer("incr_comp_prepare_session_directory");
debug!("prepare_session_directory");
// {incr-comp-dir}/{crate-name-and-disambiguator}
- let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
+ let crate_dir = crate_path(sess, crate_name, stable_crate_id);
debug!("crate-dir: {}", crate_dir.display());
- if create_dir(sess, &crate_dir, "crate").is_err() {
- return;
- }
+ create_dir(sess, &crate_dir, "crate")?;
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
crate_dir.display(),
err
));
- return;
+ return Err(ErrorReported);
}
};
// Lock the new session directory. If this fails, return an
// error without retrying
- let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
- Ok(e) => e,
- Err(_) => return,
- };
+ let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
// Now that we have the lock, we can actually create the session
// directory
- if create_dir(sess, &session_dir, "session").is_err() {
- return;
- }
+ create_dir(sess, &session_dir, "session")?;
// Find a suitable source directory to copy from. Ignore those that we
// have already tried before.
);
sess.init_incr_comp_session(session_dir, directory_lock, false);
- return;
+ return Ok(());
};
debug!("attempting to copy data from source: {}", source_directory.display());
}
sess.init_incr_comp_session(session_dir, directory_lock, true);
- return;
+ return Ok(());
} else {
debug!("copying failed - trying next directory");
directory_path
}
-fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> {
match std_fs::create_dir_all(path) {
Ok(()) => {
debug!("{} directory created successfully", dir_tag);
path.display(),
err
));
- Err(())
+ Err(ErrorReported)
}
}
}
/// Allocate the lock-file and lock it.
-fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> {
+fn lock_directory(
+ sess: &Session,
+ session_dir: &Path,
+) -> Result<(flock::Lock, PathBuf), ErrorReported> {
let lock_file_path = lock_file_path(session_dir);
debug!("lock_directory() - lock_file: {}", lock_file_path.display());
) {
// the lock should be exclusive
Ok(lock) => Ok((lock, lock_file_path)),
- Err(err) => {
- sess.err(&format!(
+ Err(lock_err) => {
+ let mut err = sess.struct_err(&format!(
"incremental compilation: could not create \
- session directory lock file: {}",
- err
+ session directory lock file: {}",
+ lock_err
));
- Err(())
+ if flock::Lock::error_unsupported(&lock_err) {
+ err.note(&format!(
+ "the filesystem for the incremental path at {} \
+ does not appear to support locking, consider changing the \
+ incremental path to a filesystem that supports locking \
+ or disable incremental compilation",
+ session_dir.display()
+ ));
+ if std::env::var_os("CARGO").is_some() {
+ err.help(
+ "incremental compilation can be disabled by setting the \
+ environment variable CARGO_INCREMENTAL=0 (see \
+ https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)",
+ );
+ err.help(
+ "the entire build directory can be changed to a different \
+ filesystem by setting the environment variable CARGO_TARGET_DIR \
+ to a different path (see \
+ https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)",
+ );
+ }
+ }
+ err.emit();
+ Err(ErrorReported)
}
}
}
Ok(UNIX_EPOCH + duration)
}
-fn crate_path(
- sess: &Session,
- crate_name: &str,
- crate_disambiguator: CrateDisambiguator,
-) -> PathBuf {
+fn crate_path(sess: &Session, crate_name: &str, stable_crate_id: StableCrateId) -> PathBuf {
let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
- // The full crate disambiguator is really long. 64 bits of it should be
- // sufficient.
- let crate_disambiguator = crate_disambiguator.to_fingerprint().to_smaller_hash();
- let crate_disambiguator = base_n::encode(crate_disambiguator as u128, INT_ENCODE_BASE);
+ let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE);
- let crate_name = format!("{}-{}", crate_name, crate_disambiguator);
+ let crate_name = format!("{}-{}", crate_name, stable_crate_id);
incr_dir.join(crate_name)
}
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::definitions::DefPathTable;
-use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::query::OnDiskCache;
use rustc_serialize::opaque::Decoder;
use rustc_serialize::Decodable;
Error { message: String },
}
-impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
- pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
+impl LoadResult<(SerializedDepGraph, WorkProductMap)> {
+ pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) {
match self {
LoadResult::Error { message } => {
sess.warn(&message);
}
}
-pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
+pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
let dep_graph = SerializedDepGraph::decode(&mut decoder)
.expect("Error reading cached dep-graph");
- LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
+ LoadResult::Ok { data: (dep_graph, prev_work_products) }
}
}
}))
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::join;
-use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::TyCtxt;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encodable as RustcEncodable;
pub fn build_dep_graph(
sess: &Session,
- prev_graph: PreviousDepGraph,
+ prev_graph: SerializedDepGraph,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
) -> Option<DepGraph> {
if sess.opts.incremental.is_none() {
}
Some(DepGraph::new(
+ &sess.prof,
prev_graph,
prev_work_products,
encoder,
#![feature(allow_internal_unstable)]
#![feature(bench_black_box)]
-#![feature(const_panic)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(unboxed_closures)]
/// `u32::MAX`. You can also customize things like the `Debug` impl,
/// what traits are derived, and so forth via the macro.
#[macro_export]
-#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
+#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
macro_rules! newtype_index {
// ---- public rules ----
}
}
- unsafe impl ::std::iter::Step for $type {
+ impl ::std::iter::Step for $type {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
<usize as ::std::iter::Step>::steps_between(
}
}
+ // Safety: The implementation of `Step` upholds all invariants.
+ unsafe impl ::std::iter::TrustedStep for $type {}
+
impl From<$type> for u32 {
#[inline]
fn from(v: $type) -> u32 {
}
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
+ Ok(vec![self.tcx.crate_name(cnum).to_string()])
}
fn path_qualified(
self,
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(never_type)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
+#![feature(min_specialization)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(internal_output_capture)]
#![feature(nll)]
#![feature(generator_trait)]
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
use rustc_errors::{ErrorReported, PResult};
use rustc_expand::base::ExtCtxt;
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate;
use rustc_lint::LintStore;
use rustc_metadata::creader::CStore;
let crate_types = util::collect_crate_types(sess, &krate.attrs);
sess.init_crate_types(crate_types);
- let disambiguator = util::compute_crate_disambiguator(sess);
- sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
- rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
+ let stable_crate_id = StableCrateId::new(
+ crate_name,
+ sess.crate_types().contains(&CrateType::Executable),
+ sess.opts.cg.metadata.clone(),
+ );
+ sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
+ rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?;
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {
query_result_on_disk_cache,
queries.as_dyn(),
&crate_name,
- &outputs,
+ outputs,
)
})
});
sess.time("MIR_effect_checking", || {
for def_id in tcx.body_owners() {
- if tcx.sess.opts.debugging_opts.thir_unsafeck {
- tcx.ensure().thir_check_unsafety(def_id);
- } else {
+ tcx.ensure().thir_check_unsafety(def_id);
+ if !tcx.sess.opts.debugging_opts.thir_unsafeck {
mir::transform::check_unsafety::check_unsafety(tcx, def_id);
}
.tempdir_in(out_filename.parent().unwrap())
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
- let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
+ let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
}
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
krate,
&crate_name,
- );
+ )?;
// Compute the dependency graph (in the background). We want to do
// this as early as possible, to give the DepGraph maximum time to
// called, which happens within passes::register_plugins().
self.dep_graph_future().ok();
- result
+ Ok(result)
})
}
(String::from("d"), Level::Forbid),
];
- assert_same_hash(&v1, &v2);
+ // The hash should be order-dependent
+ assert_different_hash(&v1, &v2);
}
#[test]
},
];
- assert_same_hash(&v1, &v2);
- assert_same_hash(&v1, &v3);
- assert_same_hash(&v2, &v3);
+ // The hash should be order-dependent
+ assert_different_hash(&v1, &v2);
+ assert_different_hash(&v1, &v3);
+ assert_different_hash(&v2, &v3);
}
#[test]
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
use rustc_data_structures::jobserver;
-use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
use rustc_metadata::dynamic_lib::DynamicLibrary;
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
-use rustc_session::CrateDisambiguator;
use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
}
}
-pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
- use std::hash::Hasher;
-
- // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
- // into various other hashes quite a bit (symbol hashes, incr. comp. hashes,
- // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits
- // should still be safe enough to avoid collisions in practice.
- let mut hasher = StableHasher::new();
-
- let mut metadata = session.opts.cg.metadata.clone();
- // We don't want the crate_disambiguator to dependent on the order
- // -C metadata arguments, so sort them:
- metadata.sort();
- // Every distinct -C metadata value is only incorporated once:
- metadata.dedup();
-
- hasher.write(b"metadata");
- for s in &metadata {
- // Also incorporate the length of a metadata string, so that we generate
- // different values for `-Cmetadata=ab -Cmetadata=c` and
- // `-Cmetadata=a -Cmetadata=bc`
- hasher.write_usize(s.len());
- hasher.write(s.as_bytes());
- }
-
- // Also incorporate crate type, so that we don't get symbol conflicts when
- // linking against a library of the same name, if this is an executable.
- let is_exe = session.crate_types().contains(&CrateType::Executable);
- hasher.write(if is_exe { b"exe" } else { b"lib" });
-
- CrateDisambiguator::from(hasher.finish::<Fingerprint>())
-}
-
pub(crate) fn check_attr_crate_type(
sess: &Session,
attrs: &[ast::Attribute],
if let Some(list) = attr.meta_item_list() {
for meta in list {
- if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
+ if meta.has_name(sym::hidden) {
return true;
}
}
}
}
- /// Checks the validity of lint names derived from the command line
- pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+ /// Checks the validity of lint names derived from the command line. Returns
+ /// true if the lint is valid, false otherwise.
+ pub fn check_lint_name_cmdline(
+ &self,
+ sess: &Session,
+ lint_name: &str,
+ level: Option<Level>,
+ ) -> bool {
let db = match self.check_lint_name(lint_name, None) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
};
if let Some(mut db) = db {
- let msg = format!(
- "requested on the command line with `{} {}`",
- match level {
- Level::Allow => "-A",
- Level::Warn => "-W",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- },
- lint_name
- );
- db.note(&msg);
+ if let Some(level) = level {
+ let msg = format!(
+ "requested on the command line with `{} {}`",
+ match level {
+ Level::Allow => "-A",
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ },
+ lint_name
+ );
+ db.note(&msg);
+ }
db.emit();
+ false
+ } else {
+ true
}
}
}
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.original_crate_name(cnum)])
+ Ok(vec![self.tcx.crate_name(cnum)])
}
fn path_qualified(
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts {
- store.check_lint_name_cmdline(sess, &lint_name, level);
+ store.check_lint_name_cmdline(sess, &lint_name, Some(level));
let orig_level = level;
// If the cap is less than this specified level, e.g., if we've got
}
}
+ for lint_name in &sess.opts.force_warns {
+ let valid = store.check_lint_name_cmdline(sess, lint_name, None);
+ if valid {
+ let lints = store
+ .find_lints(lint_name)
+ .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+ self.sets.force_warns.extend(&lints);
+ }
+ }
+
self.sets.list.push(LintSet::CommandLine { specs });
}
LintLevelSource::Default => false,
LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+ LintLevelSource::ForceWarn(_symbol) => {
+ bug!("forced warn lint returned a forbid lint level")
+ }
};
debug!(
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
LintLevelSource::CommandLine(_, _) => {
diag_builder.note("`forbid` lint level was set on command line");
}
+ _ => bug!("forced warn lint returned a forbid lint level"),
}
diag_builder.emit();
};
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
| ast::ItemKind::Struct(..)
| ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
+ ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
_ => (),
}
}
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{is_range_literal, ExprKind, Node};
-use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::Abi;
-use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
use std::cmp;
) -> Option<Ty<'tcx>> {
debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
if let ty::Adt(ty_def, substs) = ty.kind() {
- if ty_def.variants.len() != 2 {
- return None;
- }
-
- let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
- let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
- let fields = if variant_fields[0].is_empty() {
- &variant_fields[1]
- } else if variant_fields[1].is_empty() {
- &variant_fields[0]
- } else {
- return None;
+ let field_ty = match &ty_def.variants.raw[..] {
+ [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) {
+ ([], [field]) | ([field], []) => field.ty(cx.tcx, substs),
+ _ => return None,
+ },
+ _ => return None,
};
- if fields.len() != 1 {
- return None;
- }
-
- let field_ty = fields[0].ty(cx.tcx, substs);
if !ty_is_known_nonnull(cx, field_ty, ckind) {
return None;
}
}
match *ty.kind() {
- ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => {
- FfiSafe
- }
-
ty::Adt(def, substs) => {
+ if def.is_box() && matches!(self.mode, CItemKind::Definition) {
+ if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+ return FfiSafe;
+ } else {
+ return FfiUnsafe {
+ ty,
+ reason: format!("box cannot be represented as a single pointer"),
+ help: None,
+ };
+ }
+ }
if def.is_phantom_data() {
return FfiPhantom(ty);
}
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
MISSING_ABI,
+ INVALID_DOC_ATTRIBUTES,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
DISJOINT_CAPTURE_MIGRATION,
LEGACY_DERIVE_HELPERS,
/// before applying the suggestion.
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub enum Applicability {
- /// The suggestion is definitely what the user intended. This suggestion should be
+ /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
+ /// This suggestion should be automatically applied.
+ ///
+ /// In case of multiple `MachineApplicable` suggestions (whether as part of
+ /// the same `multipart_suggestion` or not), all of them should be
/// automatically applied.
MachineApplicable,
[build-dependencies]
build_helper = { path = "../../src/build_helper" }
-cc = "1.0.67"
+cc = "1.0.68"
install_fatal_error_handler(FatalErrorHandler);
}
-extern "C" LLVMMemoryBufferRef
-LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
- MemoryBuffer::getFile(Path, -1, false);
- if (!BufOr) {
- LLVMRustSetLastError(BufOr.getError().message().c_str());
- return nullptr;
- }
- return wrap(BufOr.get().release());
-}
-
extern "C" char *LLVMRustGetLastError(void) {
char *Ret = LastError;
LastError = nullptr;
}
}
-// Note that the two following functions look quite similar to the
-// LLVMGetSectionName function. Sadly, it appears that this function only
-// returns a char* pointer, which isn't guaranteed to be null-terminated. The
-// function provided by LLVM doesn't return the length, so we've created our own
-// function which returns the length as well as the data pointer.
-//
-// For an example of this not returning a null terminated string, see
-// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
-// branches explicitly creates a StringRef without a null terminator, and then
-// that's returned.
-
-inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
- return reinterpret_cast<section_iterator *>(SI);
-}
-
-extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI,
- const char **Ptr) {
- auto NameOrErr = (*unwrap(SI))->getName();
- if (!NameOrErr)
- report_fatal_error(NameOrErr.takeError());
- *Ptr = NameOrErr->data();
- return NameOrErr->size();
-}
-
// LLVMArrayType function does not support 64-bit ElementCount
extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
uint64_t ElementCount) {
use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
metadata_loader: &'a MetadataLoaderDyn,
local_crate_name: &str,
) -> Self {
- let local_crate_stable_id =
- StableCrateId::new(local_crate_name, sess.local_crate_disambiguator());
let mut stable_crate_ids = FxHashMap::default();
- stable_crate_ids.insert(local_crate_stable_id, LOCAL_CRATE);
+ stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
CrateLoader {
sess,
fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
// Check for (potential) conflicts with the local crate
- if self.local_crate_name == root.name()
- && self.sess.local_crate_disambiguator() == root.disambiguator()
- {
+ if self.sess.local_stable_crate_id() == root.stable_crate_id() {
return Err(CrateError::SymbolConflictsCurrent(root.name()));
}
// Check for conflicts with any crate loaded so far
let mut res = Ok(());
self.cstore.iter_crate_data(|_, other| {
- if other.name() == root.name() && // same crate-name
- other.disambiguator() == root.disambiguator() && // same crate-disambiguator
+ if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id
other.hash() != root.hash()
{
// but different SVH
None => (&source, &crate_root),
};
let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
- Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
+ Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
} else {
None
};
fn dlsym_proc_macros(
&self,
path: &Path,
- disambiguator: CrateDisambiguator,
+ stable_crate_id: StableCrateId,
) -> Result<&'static [ProcMacro], CrateError> {
// Make sure the path contains a / or the linker will search for it.
let path = env::current_dir().unwrap().join(path);
Err(s) => return Err(CrateError::DlOpen(s)),
};
- let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
+ let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
let decls = unsafe {
let sym = match lib.symbol(&sym) {
Ok(f) => f,
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(proc_macro_internals)]
#![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
#![feature(never_type)]
#![recursion_limit = "256"]
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::CanonicalizedPath;
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::{Target, TargetTriple};
metadata_loader: &dyn MetadataLoader,
span: Span,
name: Symbol,
-) -> (PathBuf, CrateDisambiguator) {
+) -> (PathBuf, StableCrateId) {
match find_plugin_registrar_impl(sess, metadata_loader, name) {
Ok(res) => res,
// `core` is always available if we got as far as loading plugins.
sess: &'a Session,
metadata_loader: &dyn MetadataLoader,
name: Symbol,
-) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
+) -> Result<(PathBuf, StableCrateId), CrateError> {
info!("find plugin registrar `{}`", name);
let mut locator = CrateLocator::new(
sess,
match locator.maybe_load_library_crate()? {
Some(library) => match library.source.dylib {
- Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
+ Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())),
None => Err(CrateError::NonDylibPlugin(name)),
},
None => Err(locator.into_error()),
{
let tcx = self.tcx();
- let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+ let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
return Ok(ty);
self.name
}
- crate fn disambiguator(&self) -> CrateDisambiguator {
- self.disambiguator
- }
-
crate fn hash(&self) -> Svh {
self.hash
}
self.root.name
}
- crate fn disambiguator(&self) -> CrateDisambiguator {
- self.root.disambiguator
+ crate fn stable_crate_id(&self) -> StableCrateId {
+ self.root.stable_crate_id
}
crate fn hash(&self) -> Svh {
self.root.hash
}
+ fn num_def_ids(&self) -> usize {
+ self.root.tables.def_keys.size()
+ }
+
fn local_def_id(&self, index: DefIndex) -> DefId {
DefId { krate: self.cnum, index }
}
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::utils::NativeLibKind;
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Symbol;
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
+ is_private_dep => { cdata.private_dep }
is_panic_runtime => { cdata.root.panic_runtime }
is_compiler_builtins => { cdata.root.compiler_builtins }
has_global_allocator => { cdata.root.has_global_allocator }
}
native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
foreign_modules => { cdata.get_foreign_modules(tcx) }
- crate_disambiguator => { cdata.root.disambiguator }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
- original_crate_name => { cdata.root.name }
+ crate_name => { cdata.root.name }
extra_filename => { cdata.root.extra_filename.clone() }
let r = *cdata.dep_kind.lock();
r
}
- crate_name => { cdata.root.name }
item_children => {
let mut result = SmallVec::<[_; 8]>::new();
cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
is_statically_included_foreign_item: |tcx, id| {
matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
},
+ is_private_dep: |_tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ false
+ },
native_library_kind: |tcx, id| {
tcx.native_libraries(id.krate)
.iter()
self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
}
+ /// Only public-facing way to traverse all the definitions in a non-local crate.
+ /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
+ /// See <https://github.com/rust-lang/rust/pull/85889> for context.
+ pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
+ self.get_crate_data(cnum).num_def_ids()
+ }
+
pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
}
self.get_crate_data(cnum).root.name
}
- fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
- self.get_crate_data(cnum).private_dep
- }
-
- fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
- self.get_crate_data(cnum).root.disambiguator
+ fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId {
+ self.get_crate_data(cnum).root.stable_crate_id
}
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh {
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
triple: tcx.sess.opts.target_triple.clone(),
hash: tcx.crate_hash(LOCAL_CRATE),
- disambiguator: tcx.sess.local_crate_disambiguator(),
stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
panic_strategy: tcx.sess.panic_strategy(),
edition: tcx.sess.edition(),
});
record!(self.tables.span[def_id] <- tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+ record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
}
.iter()
.map(|&cnum| {
let dep = CrateDep {
- name: self.tcx.original_crate_name(cnum),
+ name: self.tcx.crate_name(cnum),
hash: self.tcx.crate_hash(cnum),
host_hash: self.tcx.crate_host_hash(cnum),
kind: self.tcx.dep_kind(cnum),
use rustc_middle::ty::{self, ReprOptions, Ty};
use rustc_serialize::opaque::Encoder;
use rustc_session::config::SymbolManglingVersion;
-use rustc_session::CrateDisambiguator;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Ident, Symbol};
triple: TargetTriple,
extra_filename: String,
hash: Svh,
- disambiguator: CrateDisambiguator,
stable_crate_id: StableCrateId,
panic_strategy: PanicStrategy,
edition: Edition,
[] layouts: rustc_target::abi::Layout,
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef,
+ [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
[] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
[decode] mir: rustc_middle::mir::Body<$tcx>,
[] steal_promoted:
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
use crate::arena::Arena;
-use crate::hir::map::{HirOwnerData, Map};
-use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::Map;
+use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
use crate::ich::StableHashingContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
/// Source map
source_map: &'a SourceMap,
- map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+ map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
parenting: FxHashMap<LocalDefId, HirId>,
/// The parent of this node
current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
definitions,
hcx,
- map: (0..definitions.def_index_count())
- .map(|_| HirOwnerData { signature: None, with_bodies: None })
- .collect(),
+ map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
parenting: FxHashMap::default(),
};
collector.insert_entry(
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].with_bodies.as_mut().unwrap().bodies;
+ 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 }
let data = &mut self.map[id.owner];
- if data.with_bodies.is_none() {
- data.with_bodies = Some(arena.alloc(OwnerNodes {
+ if i == 0 {
+ debug_assert!(data.is_none());
+ *data = Some(arena.alloc(OwnerNodes {
hash,
nodes: IndexVec::new(),
bodies: FxHashMap::default(),
}));
- }
-
- let nodes = data.with_bodies.as_mut().unwrap();
-
- if i == 0 {
- // Overwrite the dummy hash with the real HIR owner hash.
- nodes.hash = hash;
-
- debug_assert!(data.signature.is_none());
- data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
let dk_parent = self.definitions.def_key(id.owner).parent;
if let Some(dk_parent) = dk_parent {
debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
}
} else {
- assert_eq!(entry.parent.owner, id.owner);
- insert_vec_map(
- &mut nodes.nodes,
- id.local_id,
- ParentedNode { parent: entry.parent.local_id, node: entry.node },
- );
+ debug_assert_eq!(entry.parent.owner, id.owner);
}
+
+ let data = data.as_mut().unwrap();
+
+ insert_vec_map(
+ &mut data.nodes,
+ id.local_id,
+ ParentedNode { parent: entry.parent.local_id, node: entry.node },
+ );
}
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
use self::collector::NodeCollector;
-use crate::hir::{AttributeMap, HirOwnerData, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir};
use crate::middle::cstore::CrateStore;
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
use rustc_index::vec::Idx;
+use rustc_span::def_id::StableCrateId;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident, Symbol};
.filter_map(|(def_id, hod)| {
let def_path_hash = tcx.definitions.def_path_hash(def_id);
let mut hasher = StableHasher::new();
- hod.with_bodies.as_ref()?.hash_stable(&mut hcx, &mut hasher);
+ hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
.hash_stable(&mut hcx, &mut hasher);
Some((def_path_hash, hasher.finish()))
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
- tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
+ tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher);
let crate_hash: Fingerprint = stable_hasher.finish();
Svh::new(crate_hash.to_smaller_hash())
}
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(StableCrateId, Svh)> {
let mut upstream_crates: Vec<_> = cstore
.crates_untracked()
.iter()
.map(|&cnum| {
- let name = cstore.crate_name_untracked(cnum);
- let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+ let stable_crate_id = cstore.stable_crate_id_untracked(cnum);
let hash = cstore.crate_hash_untracked(cnum);
- (name, disambiguator, hash)
+ (stable_crate_id, hash)
})
.collect();
- upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+ upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
upstream_crates
}
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
use rustc_span::DUMMY_SP;
use std::collections::BTreeMap;
-#[derive(Debug)]
-struct HirOwnerData<'hir> {
- signature: Option<&'hir Owner<'hir>>,
- with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
+/// Result of HIR indexing.
#[derive(Debug)]
pub struct IndexedHir<'hir> {
- map: IndexVec<LocalDefId, HirOwnerData<'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>,
}
-#[derive(Debug)]
+/// 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: Node<'tcx>,
}
}
}
+/// 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,
#[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>>,
}
}
}
+/// 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]>,
providers.index_hir = map::index_hir;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
- providers.hir_owner = |tcx, id| tcx.index_hir(()).map[id].signature;
- providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].with_bodies.as_deref();
+ providers.hir_owner = |tcx, id| {
+ let owner = tcx.index_hir(()).map[id].as_ref()?;
+ let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+ Some(Owner { node })
+ };
+ providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
providers.hir_owner_parent = |tcx, id| {
let index = tcx.index_hir(());
index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
};
providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
providers.all_local_trait_impls = |tcx, ()| &tcx.hir_crate(()).trait_impls;
+ providers.expn_that_defined = |tcx, id| {
+ let id = id.expect_local();
+ tcx.definitions.expansion_that_defined(id)
+ };
}
}
impl<'tcx> CanonicalVarValues<'tcx> {
+ #[inline]
pub fn len(&self) -> usize {
self.var_values.len()
}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
#![feature(never_type)]
#![feature(extern_types)]
#![feature(nll)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(min_specialization)]
#![feature(trusted_len)]
#![feature(test)]
pub mod lint;
pub mod middle;
pub mod mir;
+pub mod thir;
pub mod traits;
pub mod ty;
use std::cmp;
use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
/// The provided `Level` is the level specified on the command line.
/// (The actual level may be lower due to `--cap-lints`.)
CommandLine(Symbol, Level),
+
+ /// Lint is being forced to warn no matter what.
+ ForceWarn(Symbol),
}
impl LintLevelSource {
LintLevelSource::Default => symbol::kw::Default,
LintLevelSource::Node(name, _, _) => name,
LintLevelSource::CommandLine(name, _) => name,
+ LintLevelSource::ForceWarn(name) => name,
}
}
LintLevelSource::Default => DUMMY_SP,
LintLevelSource::Node(_, span, _) => span,
LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+ LintLevelSource::ForceWarn(_) => DUMMY_SP,
}
}
}
pub struct LintLevelSets {
pub list: Vec<LintSet>,
pub lint_cap: Level,
+ pub force_warns: FxHashSet<LintId>,
}
#[derive(Debug)]
impl LintLevelSets {
pub fn new() -> Self {
- LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+ LintLevelSets {
+ list: Vec::new(),
+ lint_cap: Level::Forbid,
+ force_warns: FxHashSet::default(),
+ }
}
pub fn get_lint_level(
aux: Option<&FxHashMap<LintId, LevelAndSource>>,
sess: &Session,
) -> LevelAndSource {
+ // Check whether we should always warn
+ if self.force_warns.contains(&LintId::of(lint)) {
+ return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
+ }
+
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
#[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let LintLevelMap { ref sets, ref id_to_set } = *self;
+ let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
id_to_set.hash_stable(hcx, hasher);
- let LintLevelSets { ref list, lint_cap } = *sets;
+ let LintLevelSets { ref list, lint_cap, .. } = *sets;
lint_cap.hash_stable(hcx, hasher);
);
}
}
+ LintLevelSource::ForceWarn(_) => {
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ "warning forced by `force-warns` commandline option",
+ );
+ }
}
err.code(DiagnosticId::Lint { name, has_future_breakage });
use rustc_macros::HashStable;
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
-use rustc_session::CrateDisambiguator;
+use rustc_session::StableCrateId;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::spec::Target;
// "queries" used in resolve that aren't tracked for incremental compilation
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
- fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
- fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
+ fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
// This is basically a 1-based range of ints, which is a little
pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
format!(
- "rust_metadata_{}_{}",
- tcx.original_crate_name(LOCAL_CRATE),
- tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
+ "rust_metadata_{}_{:08x}",
+ tcx.crate_name(LOCAL_CRATE),
+ tcx.sess.local_stable_crate_id().to_u64(),
)
}
// The constructors are all without extra; the extra gets added by a machine hook later.
impl<Tag> Allocation<Tag> {
- /// Creates a read-only allocation initialized by the given bytes
- pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
+ /// Creates an allocation initialized by the given bytes
+ pub fn from_bytes<'a>(
+ slice: impl Into<Cow<'a, [u8]>>,
+ align: Align,
+ mutability: Mutability,
+ ) -> Self {
let bytes = slice.into().into_owned();
let size = Size::from_bytes(bytes.len());
Self {
relocations: Relocations::new(),
init_mask: InitMask::new(size, true),
align,
- mutability: Mutability::Not,
+ mutability,
extra: (),
}
}
- pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
- Allocation::from_bytes(slice, Align::ONE)
+ pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
+ Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
}
pub fn uninit(size: Size, align: Align) -> Self {
}
/// A trait for machine-specific errors (or other "machine stop" conditions).
-pub trait MachineStopType: AsAny + fmt::Display + Send {}
-impl MachineStopType for String {}
+pub trait MachineStopType: AsAny + fmt::Display + Send {
+ /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
+ fn is_hard_err(&self) -> bool {
+ false
+ }
+}
impl dyn MachineStopType {
#[inline(always)]
}
impl AllocDecodingState {
+ #[inline]
pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
///
/// Terminator may not be None after construction of the basic block is complete. This accessor
/// provides a convenience way to reach the terminator.
+ #[inline]
pub fn terminator(&self) -> &Terminator<'tcx> {
self.terminator.as_ref().expect("invalid terminator state")
}
+ #[inline]
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
self.terminator.as_mut().expect("invalid terminator state")
}
/// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`.
+ #[inline]
pub fn as_local(&self) -> Option<Local> {
match *self {
PlaceRef { local, projection: [] } => Some(local),
}
}
+ #[inline]
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
if let &[ref proj_base @ .., elem] = self.projection {
Some((PlaceRef { local: self.local, projection: proj_base }, elem))
_ => None,
}
}
+ #[inline]
pub fn ty(&self) -> Ty<'tcx> {
self.literal.ty()
}
}
impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+ #[inline]
fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
Self::Ty(ct)
}
pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
crate::dep_graph::make_compile_mono_item(tcx, self)
}
+
+ /// Returns the item's `CrateNum`
+ pub fn krate(&self) -> CrateNum {
+ match self {
+ MonoItem::Fn(ref instance) => instance.def_id().krate,
+ MonoItem::Static(def_id) => def_id.krate,
+ MonoItem::GlobalAsm(..) => LOCAL_CRATE,
+ }
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
}
impl<'tcx> CodegenUnit<'tcx> {
+ #[inline]
pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
}
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
}
+ #[inline]
pub fn size_estimate(&self) -> usize {
// Should only be called if `estimate_size` has previously been called.
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
// local crate's ID. Otherwise there can be collisions between CGUs
// instantiating stuff for upstream crates.
let local_crate_id = if cnum != LOCAL_CRATE {
- let local_crate_disambiguator = format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
- format!("-in-{}.{}", tcx.crate_name(LOCAL_CRATE), &local_crate_disambiguator[0..8])
+ let local_stable_crate_id = tcx.sess.local_stable_crate_id();
+ format!(
+ "-in-{}.{:08x}",
+ tcx.crate_name(LOCAL_CRATE),
+ local_stable_crate_id.to_u64()
+ )
} else {
String::new()
};
- let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
- // Using a shortened disambiguator of about 40 bits
- format!("{}.{}{}", tcx.crate_name(cnum), &crate_disambiguator[0..8], local_crate_id)
+ let stable_crate_id = tcx.sess.local_stable_crate_id();
+ format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id.to_u64(), local_crate_id)
});
write!(cgu_name, "{}", crate_prefix).unwrap();
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
+ 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()) }
}
desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// Internal helper query. Use `tcx.expansion_that_defined` instead
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+ eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
}
desc { "checking if the crate is_panic_runtime" }
}
+ /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
+ query thir_body(key: ty::WithOptConstParam<LocalDefId>) -> (&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId) {
+ // Perf tests revealed that hashing THIR is inefficient (see #85729).
+ no_hash
+ desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
/// Set of all the `DefId`s in this crate that have MIR associated with
/// them. This includes all the body owners, but also things like struct
/// constructors.
desc { "computing whether impls specialize one another" }
}
query in_scope_traits_map(_: LocalDefId)
- -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
- eval_always
+ -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
desc { "traits in scope at a block" }
}
query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
desc { "looking up the derive registrar for a crate" }
}
- query crate_disambiguator(_: CrateNum) -> CrateDisambiguator {
- eval_always
- desc { "looking up the disambiguator a crate" }
- }
// The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
// Changing the name should cause a compiler error, but in case that changes, be aware.
query crate_hash(_: CrateNum) -> Svh {
eval_always
desc { "looking up the hash of a host version of a crate" }
}
- query original_crate_name(_: CrateNum) -> Symbol {
- eval_always
- desc { "looking up the original name a crate" }
- }
query extra_filename(_: CrateNum) -> String {
eval_always
desc { "looking up the extra filename for a crate" }
eval_always
desc { "generating a postorder list of CrateNums" }
}
+ /// Returns whether or not the crate with CrateNum 'cnum'
+ /// is marked as a private dependency
+ query is_private_dep(c: CrateNum) -> bool {
+ eval_always
+ desc { "check whether crate {} is a private dependency", c }
+ }
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
--- /dev/null
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::RangeEnd;
+use rustc_index::newtype_index;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::infer::canonical::Canonical;
+use rustc_middle::middle::region;
+use rustc_middle::mir::{
+ BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
+};
+use rustc_middle::ty::adjustment::PointerCast;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
+use rustc_middle::ty::{
+ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+};
+use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_target::abi::VariantIdx;
+use rustc_target::asm::InlineAsmRegOrRegClass;
+
+use std::fmt;
+use std::ops::Index;
+
+newtype_index! {
+ #[derive(HashStable)]
+ pub struct ArmId {
+ DEBUG_FORMAT = "a{}"
+ }
+}
+
+newtype_index! {
+ #[derive(HashStable)]
+ pub struct ExprId {
+ DEBUG_FORMAT = "e{}"
+ }
+}
+
+newtype_index! {
+ #[derive(HashStable)]
+ pub struct StmtId {
+ DEBUG_FORMAT = "s{}"
+ }
+}
+
+macro_rules! thir_with_elements {
+ ($($name:ident: $id:ty => $value:ty,)*) => {
+ #[derive(Debug, HashStable)]
+ pub struct Thir<'tcx> {
+ $(
+ pub $name: IndexVec<$id, $value>,
+ )*
+ }
+
+ impl<'tcx> Thir<'tcx> {
+ pub fn new() -> Thir<'tcx> {
+ Thir {
+ $(
+ $name: IndexVec::new(),
+ )*
+ }
+ }
+ }
+
+ $(
+ impl<'tcx> Index<$id> for Thir<'tcx> {
+ type Output = $value;
+ fn index(&self, index: $id) -> &Self::Output {
+ &self.$name[index]
+ }
+ }
+ )*
+ }
+}
+
+thir_with_elements! {
+ arms: ArmId => Arm<'tcx>,
+ exprs: ExprId => Expr<'tcx>,
+ stmts: StmtId => Stmt<'tcx>,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LintLevel {
+ Inherited,
+ Explicit(hir::HirId),
+}
+
+#[derive(Debug, HashStable)]
+pub struct Block {
+ pub targeted_by_break: bool,
+ pub region_scope: region::Scope,
+ pub opt_destruction_scope: Option<region::Scope>,
+ pub span: Span,
+ pub stmts: Box<[StmtId]>,
+ pub expr: Option<ExprId>,
+ pub safety_mode: BlockSafety,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum BlockSafety {
+ Safe,
+ ExplicitUnsafe(hir::HirId),
+ PushUnsafe,
+ PopUnsafe,
+}
+
+#[derive(Debug, HashStable)]
+pub struct Stmt<'tcx> {
+ pub kind: StmtKind<'tcx>,
+ pub opt_destruction_scope: Option<region::Scope>,
+}
+
+#[derive(Debug, HashStable)]
+pub enum StmtKind<'tcx> {
+ Expr {
+ /// scope for this statement; may be used as lifetime of temporaries
+ scope: region::Scope,
+
+ /// expression being evaluated in this statement
+ expr: ExprId,
+ },
+
+ Let {
+ /// scope for variables bound in this let; covers this and
+ /// remaining statements in block
+ remainder_scope: region::Scope,
+
+ /// scope for the initialization itself; might be used as
+ /// lifetime of temporaries
+ init_scope: region::Scope,
+
+ /// `let <PAT> = ...`
+ ///
+ /// if a type is included, it is added as an ascription pattern
+ pattern: Pat<'tcx>,
+
+ /// let pat: ty = <INIT> ...
+ initializer: Option<ExprId>,
+
+ /// the lint level for this let-statement
+ lint_level: LintLevel,
+ },
+}
+
+// `Expr` 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!(Expr<'_>, 144);
+
+/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
+/// into instances of this `Expr` enum. This lowering can be done
+/// basically as lazily or as eagerly as desired: every recursive
+/// reference to an expression in this enum is an `ExprId`, which
+/// may in turn be another instance of this enum (boxed), or else an
+/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
+/// short-lived. They are created by `Thir::to_expr`, analyzed and
+/// converted into MIR, and then discarded.
+///
+/// If you compare `Expr` to the full compiler AST, you will see it is
+/// a good bit simpler. In fact, a number of the more straight-forward
+/// MIR simplifications are already done in the impl of `Thir`. For
+/// example, method calls and overloaded operators are absent: they are
+/// expected to be converted into `Expr::Call` instances.
+#[derive(Debug, HashStable)]
+pub struct Expr<'tcx> {
+ /// type of this expression
+ pub ty: Ty<'tcx>,
+
+ /// lifetime of this expression if it should be spilled into a
+ /// temporary; should be None only if in a constant context
+ pub temp_lifetime: Option<region::Scope>,
+
+ /// span of the expression in the source
+ pub span: Span,
+
+ /// kind of expression
+ pub kind: ExprKind<'tcx>,
+}
+
+#[derive(Debug, HashStable)]
+pub enum ExprKind<'tcx> {
+ Scope {
+ region_scope: region::Scope,
+ lint_level: LintLevel,
+ value: ExprId,
+ },
+ Box {
+ value: ExprId,
+ },
+ If {
+ cond: ExprId,
+ then: ExprId,
+ else_opt: Option<ExprId>,
+ },
+ Call {
+ ty: Ty<'tcx>,
+ fun: ExprId,
+ args: Box<[ExprId]>,
+ /// Whether this is from a call in HIR, rather than from an overloaded
+ /// operator. `true` for overloaded function call.
+ from_hir_call: bool,
+ /// This `Span` is the span of the function, without the dot and receiver
+ /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+ fn_span: Span,
+ },
+ Deref {
+ arg: ExprId,
+ }, // NOT overloaded!
+ Binary {
+ op: BinOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ }, // NOT overloaded!
+ LogicalOp {
+ op: LogicalOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ }, // NOT overloaded!
+ // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
+ Unary {
+ op: UnOp,
+ arg: ExprId,
+ }, // NOT overloaded!
+ Cast {
+ source: ExprId,
+ },
+ Use {
+ source: ExprId,
+ }, // Use a lexpr to get a vexpr.
+ NeverToAny {
+ source: ExprId,
+ },
+ Pointer {
+ cast: PointerCast,
+ source: ExprId,
+ },
+ Loop {
+ body: ExprId,
+ },
+ Match {
+ scrutinee: ExprId,
+ arms: Box<[ArmId]>,
+ },
+ Block {
+ body: Block,
+ },
+ Assign {
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ AssignOp {
+ op: BinOp,
+ lhs: ExprId,
+ rhs: ExprId,
+ },
+ Field {
+ lhs: ExprId,
+ name: Field,
+ },
+ Index {
+ lhs: ExprId,
+ index: ExprId,
+ },
+ VarRef {
+ id: hir::HirId,
+ },
+ /// Used to represent upvars mentioned in a closure/generator
+ UpvarRef {
+ /// DefId of the closure/generator
+ closure_def_id: DefId,
+
+ /// HirId of the root variable
+ var_hir_id: hir::HirId,
+ },
+ Borrow {
+ borrow_kind: BorrowKind,
+ arg: ExprId,
+ },
+ /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
+ AddressOf {
+ mutability: hir::Mutability,
+ arg: ExprId,
+ },
+ Break {
+ label: region::Scope,
+ value: Option<ExprId>,
+ },
+ Continue {
+ label: region::Scope,
+ },
+ Return {
+ value: Option<ExprId>,
+ },
+ ConstBlock {
+ value: &'tcx Const<'tcx>,
+ },
+ Repeat {
+ value: ExprId,
+ count: &'tcx Const<'tcx>,
+ },
+ Array {
+ fields: Box<[ExprId]>,
+ },
+ Tuple {
+ fields: Box<[ExprId]>,
+ },
+ Adt {
+ adt_def: &'tcx AdtDef,
+ variant_index: VariantIdx,
+ substs: SubstsRef<'tcx>,
+
+ /// Optional user-given substs: for something like `let x =
+ /// Bar::<T> { ... }`.
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+ fields: Box<[FieldExpr]>,
+ base: Option<FruInfo<'tcx>>,
+ },
+ PlaceTypeAscription {
+ source: ExprId,
+ /// Type that the user gave to this expression
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ ValueTypeAscription {
+ source: ExprId,
+ /// Type that the user gave to this expression
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ },
+ Closure {
+ closure_id: DefId,
+ substs: UpvarSubsts<'tcx>,
+ upvars: Box<[ExprId]>,
+ movability: Option<hir::Movability>,
+ fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
+ },
+ Literal {
+ literal: &'tcx Const<'tcx>,
+ user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+ /// The `DefId` of the `const` item this literal
+ /// was produced from, if this is not a user-written
+ /// literal value.
+ const_id: Option<DefId>,
+ },
+ /// A literal containing the address of a `static`.
+ ///
+ /// This is only distinguished from `Literal` so that we can register some
+ /// info for diagnostics.
+ StaticRef {
+ literal: &'tcx Const<'tcx>,
+ def_id: DefId,
+ },
+ InlineAsm {
+ template: &'tcx [InlineAsmTemplatePiece],
+ operands: Box<[InlineAsmOperand<'tcx>]>,
+ options: InlineAsmOptions,
+ line_spans: &'tcx [Span],
+ },
+ /// An expression taking a reference to a thread local.
+ ThreadLocalRef(DefId),
+ LlvmInlineAsm {
+ asm: &'tcx hir::LlvmInlineAsmInner,
+ outputs: Box<[ExprId]>,
+ inputs: Box<[ExprId]>,
+ },
+ Yield {
+ value: ExprId,
+ },
+}
+
+#[derive(Debug, HashStable)]
+pub struct FieldExpr {
+ pub name: Field,
+ pub expr: ExprId,
+}
+
+#[derive(Debug, HashStable)]
+pub struct FruInfo<'tcx> {
+ pub base: ExprId,
+ pub field_types: Box<[Ty<'tcx>]>,
+}
+
+#[derive(Debug, HashStable)]
+pub struct Arm<'tcx> {
+ pub pattern: Pat<'tcx>,
+ pub guard: Option<Guard<'tcx>>,
+ pub body: ExprId,
+ pub lint_level: LintLevel,
+ pub scope: region::Scope,
+ pub span: Span,
+}
+
+#[derive(Debug, HashStable)]
+pub enum Guard<'tcx> {
+ If(ExprId),
+ IfLet(Pat<'tcx>, ExprId),
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LogicalOp {
+ And,
+ Or,
+}
+
+#[derive(Debug, HashStable)]
+pub enum InlineAsmOperand<'tcx> {
+ In {
+ reg: InlineAsmRegOrRegClass,
+ expr: ExprId,
+ },
+ Out {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ expr: Option<ExprId>,
+ },
+ InOut {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ expr: ExprId,
+ },
+ SplitInOut {
+ reg: InlineAsmRegOrRegClass,
+ late: bool,
+ in_expr: ExprId,
+ out_expr: Option<ExprId>,
+ },
+ Const {
+ value: &'tcx Const<'tcx>,
+ span: Span,
+ },
+ SymFn {
+ expr: ExprId,
+ },
+ SymStatic {
+ def_id: DefId,
+ },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub enum BindingMode {
+ ByValue,
+ ByRef(BorrowKind),
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub struct FieldPat<'tcx> {
+ pub field: Field,
+ pub pattern: Pat<'tcx>,
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub struct Pat<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub span: Span,
+ pub kind: Box<PatKind<'tcx>>,
+}
+
+impl<'tcx> Pat<'tcx> {
+ pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
+ Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct PatTyProj<'tcx> {
+ pub user_ty: CanonicalUserType<'tcx>,
+}
+
+impl<'tcx> PatTyProj<'tcx> {
+ pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
+ Self { user_ty: user_annotation }
+ }
+
+ pub fn user_ty(
+ self,
+ annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
+ inferred_ty: Ty<'tcx>,
+ span: Span,
+ ) -> UserTypeProjection {
+ UserTypeProjection {
+ base: annotations.push(CanonicalUserTypeAnnotation {
+ span,
+ user_ty: self.user_ty,
+ inferred_ty,
+ }),
+ projs: Vec::new(),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct Ascription<'tcx> {
+ pub user_ty: PatTyProj<'tcx>,
+ /// Variance to use when relating the type `user_ty` to the **type of the value being
+ /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+ /// have a type that is some subtype of the ascribed type.
+ ///
+ /// Note that this variance does not apply for any bindings within subpatterns. The type
+ /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+ ///
+ /// The only place where this field is not `Covariant` is when matching constants, where
+ /// we currently use `Contravariant` -- this is because the constant type just needs to
+ /// be "comparable" to the type of the input value. So, for example:
+ ///
+ /// ```text
+ /// match x { "foo" => .. }
+ /// ```
+ ///
+ /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+ /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+ /// of the old type-check for now. See #57280 for details.
+ pub variance: ty::Variance,
+ pub user_ty_span: Span,
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub enum PatKind<'tcx> {
+ Wild,
+
+ AscribeUserType {
+ ascription: Ascription<'tcx>,
+ subpattern: Pat<'tcx>,
+ },
+
+ /// `x`, `ref x`, `x @ P`, etc.
+ Binding {
+ mutability: Mutability,
+ name: Symbol,
+ mode: BindingMode,
+ var: hir::HirId,
+ ty: Ty<'tcx>,
+ subpattern: Option<Pat<'tcx>>,
+ /// Is this the leftmost occurrence of the binding, i.e., is `var` the
+ /// `HirId` of this pattern?
+ is_primary: bool,
+ },
+
+ /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
+ /// multiple variants.
+ Variant {
+ adt_def: &'tcx AdtDef,
+ substs: SubstsRef<'tcx>,
+ variant_index: VariantIdx,
+ subpatterns: Vec<FieldPat<'tcx>>,
+ },
+
+ /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
+ /// a single variant.
+ Leaf {
+ subpatterns: Vec<FieldPat<'tcx>>,
+ },
+
+ /// `box P`, `&P`, `&mut P`, etc.
+ Deref {
+ subpattern: Pat<'tcx>,
+ },
+
+ /// One of the following:
+ /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
+ /// checking will detect if you use the same string twice in different patterns.
+ /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
+ /// its own value, similar to `&str`, but these values are much simpler.
+ /// * Opaque constants, that must not be matched structurally. So anything that does not derive
+ /// `PartialEq` and `Eq`.
+ Constant {
+ value: &'tcx ty::Const<'tcx>,
+ },
+
+ Range(PatRange<'tcx>),
+
+ /// Matches against a slice, checking the length and extracting elements.
+ /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+ /// e.g., `&[ref xs @ ..]`.
+ Slice {
+ prefix: Vec<Pat<'tcx>>,
+ slice: Option<Pat<'tcx>>,
+ suffix: Vec<Pat<'tcx>>,
+ },
+
+ /// Fixed match against an array; irrefutable.
+ Array {
+ prefix: Vec<Pat<'tcx>>,
+ slice: Option<Pat<'tcx>>,
+ suffix: Vec<Pat<'tcx>>,
+ },
+
+ /// An or-pattern, e.g. `p | q`.
+ /// Invariant: `pats.len() >= 2`.
+ Or {
+ pats: Vec<Pat<'tcx>>,
+ },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct PatRange<'tcx> {
+ pub lo: &'tcx ty::Const<'tcx>,
+ pub hi: &'tcx ty::Const<'tcx>,
+ pub end: RangeEnd,
+}
+
+impl<'tcx> fmt::Display for Pat<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Printing lists is a chore.
+ let mut first = true;
+ let mut start_or_continue = |s| {
+ if first {
+ first = false;
+ ""
+ } else {
+ s
+ }
+ };
+ let mut start_or_comma = || start_or_continue(", ");
+
+ match *self.kind {
+ PatKind::Wild => write!(f, "_"),
+ PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
+ PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+ let is_mut = match mode {
+ BindingMode::ByValue => mutability == Mutability::Mut,
+ BindingMode::ByRef(bk) => {
+ write!(f, "ref ")?;
+ matches!(bk, BorrowKind::Mut { .. })
+ }
+ };
+ if is_mut {
+ write!(f, "mut ")?;
+ }
+ write!(f, "{}", name)?;
+ if let Some(ref subpattern) = *subpattern {
+ write!(f, " @ {}", subpattern)?;
+ }
+ Ok(())
+ }
+ PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
+ let variant = match *self.kind {
+ PatKind::Variant { adt_def, variant_index, .. } => {
+ Some(&adt_def.variants[variant_index])
+ }
+ _ => {
+ if let ty::Adt(adt, _) = self.ty.kind() {
+ if !adt.is_enum() {
+ Some(&adt.variants[VariantIdx::new(0)])
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+ };
+
+ if let Some(variant) = variant {
+ write!(f, "{}", variant.ident)?;
+
+ // Only for Adt we can have `S {...}`,
+ // which we handle separately here.
+ if variant.ctor_kind == CtorKind::Fictive {
+ write!(f, " {{ ")?;
+
+ let mut printed = 0;
+ for p in subpatterns {
+ if let PatKind::Wild = *p.pattern.kind {
+ continue;
+ }
+ let name = variant.fields[p.field.index()].ident;
+ write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+ printed += 1;
+ }
+
+ if printed < variant.fields.len() {
+ write!(f, "{}..", start_or_comma())?;
+ }
+
+ return write!(f, " }}");
+ }
+ }
+
+ let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+ if num_fields != 0 || variant.is_none() {
+ write!(f, "(")?;
+ for i in 0..num_fields {
+ write!(f, "{}", start_or_comma())?;
+
+ // Common case: the field is where we expect it.
+ if let Some(p) = subpatterns.get(i) {
+ if p.field.index() == i {
+ write!(f, "{}", p.pattern)?;
+ continue;
+ }
+ }
+
+ // Otherwise, we have to go looking for it.
+ if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+ write!(f, "{}", p.pattern)?;
+ } else {
+ write!(f, "_")?;
+ }
+ }
+ write!(f, ")")?;
+ }
+
+ Ok(())
+ }
+ PatKind::Deref { ref subpattern } => {
+ match self.ty.kind() {
+ ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
+ ty::Ref(_, _, mutbl) => {
+ write!(f, "&{}", mutbl.prefix_str())?;
+ }
+ _ => bug!("{} is a bad Deref pattern type", self.ty),
+ }
+ write!(f, "{}", subpattern)
+ }
+ PatKind::Constant { value } => write!(f, "{}", value),
+ PatKind::Range(PatRange { lo, hi, end }) => {
+ write!(f, "{}", lo)?;
+ write!(f, "{}", end)?;
+ write!(f, "{}", hi)
+ }
+ PatKind::Slice { ref prefix, ref slice, ref suffix }
+ | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+ write!(f, "[")?;
+ for p in prefix {
+ write!(f, "{}{}", start_or_comma(), p)?;
+ }
+ if let Some(ref slice) = *slice {
+ write!(f, "{}", start_or_comma())?;
+ match *slice.kind {
+ PatKind::Wild => {}
+ _ => write!(f, "{}", slice)?,
+ }
+ write!(f, "..")?;
+ }
+ for p in suffix {
+ write!(f, "{}{}", start_or_comma(), p)?;
+ }
+ write!(f, "]")
+ }
+ PatKind::Or { ref pats } => {
+ for pat in pats {
+ write!(f, "{}{}", start_or_continue(" | "), pat)?;
+ }
+ Ok(())
+ }
+ }
+ }
+}
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
/// Here the pointer will be dereferenced N times (where a dereference can
/// happen to raw or borrowed pointers or any smart pointer which implements
-/// Deref, including Box<_>). The types of dereferences is given by
+/// `Deref`, including `Box<_>`). The types of dereferences is given by
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
/// `false`.
/// with a thin pointer, deref a number of times, unsize the underlying data,
/// then autoref. The 'unsize' phase may change a fixed length array to a
/// dynamically sized one, a concrete object to a trait object, or statically
-/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
+/// sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
/// represented by:
///
/// ```
/// ```
///
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+/// E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
/// The autoderef and -ref are the same as in the above example, but the type
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
/// the underlying conversions from `[i32; 4]` to `[i32]`.
/// that case, we have the pointer we need coming in, so there are no
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
/// At some point, of course, `Box` should move out of the compiler, in which
-/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
-/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
+/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
+/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct Adjustment<'tcx> {
pub kind: Adjust<'tcx>,
use crate::hir::place::{
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
};
-use crate::ty;
+use crate::{mir, ty};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir as hir;
use self::BorrowKind::*;
+// Captures are represented using fields inside a structure.
+// This represents accessing self in the closure structure
+pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
+
#[derive(
Clone,
Copy,
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::thir::Thir;
use crate::traits;
use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_errors::ErrorReported;
/// Resolutions of `extern crate` items produced by resolver.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- /// Map indicating what traits are in scope for places where this
- /// is relevant; generated by resolve.
- trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
-
/// Export map produced by name resolution.
export_map: ExportMap<LocalDefId>,
/// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc.
- pub crate_name: Symbol,
+ crate_name: Symbol,
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
}
}
+ pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
+ self.arena.alloc(Steal::new(thir))
+ }
+
pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> {
self.arena.alloc(Steal::new(mir))
}
/// Allocates a read-only byte or string literal for `mir::interpret`.
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
// Create an allocation that just contains these bytes.
- let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
+ let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
let alloc = self.intern_const_alloc(alloc);
self.create_memory_alloc(alloc)
}
on_disk_cache: Option<query::OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
crate_name: &str,
- output_filenames: &OutputFilenames,
+ output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
s.fatal(&err);
let common_consts = CommonConsts::new(&interners, &common_types);
let cstore = resolutions.cstore;
- let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
- for (hir_id, v) in krate.trait_map.iter() {
- let map = trait_map.entry(hir_id.owner).or_default();
- map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
- }
-
GlobalCtxt {
sess: s,
lint_store,
consts: common_consts,
visibilities: resolutions.visibilities,
extern_crate_map: resolutions.extern_crate_map,
- trait_map,
export_map: resolutions.export_map,
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates,
stability_interner: Default::default(),
const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
- output_filenames: Arc::new(output_filenames.clone()),
+ output_filenames: Arc::new(output_filenames),
main_def: resolutions.main_def,
}
}
}
}
- /// Returns whether or not the crate with CrateNum 'cnum'
- /// is marked as a private dependency
- pub fn is_private_dep(self, cnum: CrateNum) -> bool {
- if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) }
- }
-
#[inline]
pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
if let Some(def_id) = def_id.as_local() {
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 disambiguator since this code is called from debug!()
+ // crate name and stable crate id since this code is called from debug!()
// statements within the query system and we'd run into endless
// recursion otherwise.
- let (crate_name, crate_disambiguator) = if def_id.is_local() {
- (self.crate_name, self.sess.local_crate_disambiguator())
+ let (crate_name, stable_crate_id) = if def_id.is_local() {
+ (self.crate_name, self.sess.local_stable_crate_id())
} else {
(
self.cstore.crate_name_untracked(def_id.krate),
- self.cstore.crate_disambiguator_untracked(def_id.krate),
+ self.def_path_hash(def_id.krate.as_def_id()).stable_crate_id(),
)
};
format!(
"{}[{}]{}",
crate_name,
- // Don't print the whole crate disambiguator. That's just
+ // Don't print the whole stable crate id. That's just
// annoying in debug output.
- &(crate_disambiguator.to_fingerprint().to_hex())[..4],
+ &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
self.def_path(def_id).to_string_no_crate_verbose()
)
}
struct_lint_level(self.sess, lint, level, src, None, decorate);
}
- pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
- self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id))
+ pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
+ let map = self.in_scope_traits_map(id.owner)?;
+ let candidates = map.get(&id.local_id)?;
+ Some(&*candidates)
}
pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
+ providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
}
impl<'tcx> Generics {
+ #[inline]
pub fn count(&self) -> usize {
self.parent_count + self.params.len()
}
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
}
-fn fn_can_unwind(
+pub fn fn_can_unwind(
panic_strategy: PanicStrategy,
codegen_fn_attr_flags: CodegenFnAttrFlags,
call_conv: Conv,
}
}
+pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+ use rustc_target::spec::abi::Abi::*;
+ match tcx.sess.target.adjust_abi(abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+
+ // It's the ABI's job to select this, not ours.
+ System { .. } => bug!("system abi should be selected elsewhere"),
+ EfiApi => bug!("eficall abi should be selected elsewhere"),
+
+ Stdcall { .. } => Conv::X86Stdcall,
+ Fastcall => Conv::X86Fastcall,
+ Vectorcall => Conv::X86VectorCall,
+ Thiscall { .. } => Conv::X86ThisCall,
+ C { .. } => Conv::C,
+ Unadjusted => Conv::C,
+ Win64 => Conv::X86_64Win64,
+ SysV64 => Conv::X86_64SysV,
+ Aapcs => Conv::ArmAapcs,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+ AvrInterrupt => Conv::AvrInterrupt,
+ AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+ Wasm => Conv::C,
+
+ // These API constants ought to be more specific...
+ Cdecl => Conv::C,
+ }
+}
+
+pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
+ // Assume that fn pointers may always unwind
+ CodegenFnAttrFlags::UNWIND
+}
+
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ HasParamEnv<'tcx>,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
- // Assume that fn pointers may always unwind
- let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
-
- call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
+ call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
- use rustc_target::spec::abi::Abi::*;
- let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
-
- // It's the ABI's job to select this, not ours.
- System { .. } => bug!("system abi should be selected elsewhere"),
- EfiApi => bug!("eficall abi should be selected elsewhere"),
-
- Stdcall { .. } => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
- Thiscall { .. } => Conv::X86ThisCall,
- C { .. } => Conv::C,
- Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
- CCmseNonSecureCall => Conv::CCmseNonSecureCall,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
- AvrInterrupt => Conv::AvrInterrupt,
- AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
- Wasm => Conv::C,
-
- // These API constants ought to be more specific...
- Cdecl => Conv::C,
- };
+ let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
let mut inputs = sig.inputs();
let extra_args = if sig.abi == RustCall {
target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
let linux_powerpc_gnu_like =
target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+ use SpecAbi::*;
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
// Handle safe Rust thin and fat pointers.
unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *const List<T> as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&*(ptr as *const List<T>)
}
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
use rustc_hir::{Constness, Node};
use rustc_macros::HashStable;
-use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct CReaderCacheKey {
- pub cnum: CrateNum,
+ pub cnum: Option<CrateNum>,
pub pos: usize,
}
unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
const BITS: usize = 1;
+ #[inline]
fn into_usize(self) -> usize {
match self {
traits::Reveal::UserFacing => 0,
traits::Reveal::All => 1,
}
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
match ptr {
0 => traits::Reveal::UserFacing,
}
/// Returns this same environment but with no caller bounds.
+ #[inline]
pub fn without_caller_bounds(self) -> Self {
Self::new(List::empty(), self.reveal())
}
fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
if def_id.index == CRATE_DEF_INDEX {
- Some(self.original_crate_name(def_id.krate))
+ Some(self.crate_name(def_id.krate))
} else {
let def_key = self.def_key(def_id);
match def_key.disambiguated_data.data {
&& use_name
.span
.ctxt()
- .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
- }
-
- pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
- match scope.as_local() {
- // Parsing and expansion aren't incremental, so we don't
- // need to go through a query for the same-crate case.
- Some(scope) => self.hir().definitions().expansion_that_defined(scope),
- None => self.expn_that_defined(scope),
- }
+ .hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id))
}
pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
- ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope));
+ ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
ident
}
block: hir::HirId,
) -> (Ident, DefId) {
let scope =
- match ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope))
- {
+ match ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope)) {
Some(actual_expansion) => {
self.hir().definitions().parent_module_of_macro_def(actual_expansion)
}
}
// Re-exported `extern crate` (#43189).
DefPathData::CrateRoot => {
- data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate));
+ data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
}
_ => {}
}
use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput};
use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
use crate::mir::mono::CodegenUnit;
+use crate::thir;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::stable_hasher::StableVec;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_serialize::opaque;
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind;
-use rustc_session::CrateDisambiguator;
use rustc_target::spec::PanicStrategy;
use rustc_ast as ast;
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
Decodable, Decoder, Encodable, Encoder,
};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
use rustc_span::hygiene::{
ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
SyntaxContext, SyntaxContextData,
// session.
current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+ prev_cnums: Vec<(u32, StableCrateId)>,
cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
source_map: &'sess SourceMap,
#[derive(Encodable, Decodable)]
struct Footer {
file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+ prev_cnums: Vec<(u32, StableCrateId)>,
query_result_index: EncodedQueryResultIndex,
diagnostics_index: EncodedQueryResultIndex,
// The location of all allocations.
let prev_cnums: Vec<_> = sorted_cnums
.iter()
.map(|&cnum| {
- let crate_name = tcx.original_crate_name(cnum).to_string();
- let crate_disambiguator = tcx.crate_disambiguator(cnum);
- (cnum.as_u32(), crate_name, crate_disambiguator)
+ let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+ (cnum.as_u32(), stable_crate_id)
})
.collect();
// maps to None.
fn compute_cnum_map(
tcx: TyCtxt<'_>,
- prev_cnums: &[(u32, String, CrateDisambiguator)],
+ prev_cnums: &[(u32, StableCrateId)],
) -> IndexVec<CrateNum, Option<CrateNum>> {
tcx.dep_graph.with_ignore(|| {
let current_cnums = tcx
.all_crate_nums(())
.iter()
.map(|&cnum| {
- let crate_name = tcx.original_crate_name(cnum).to_string();
- let crate_disambiguator = tcx.crate_disambiguator(cnum);
- ((crate_name, crate_disambiguator), cnum)
+ let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+ (stable_crate_id, cnum)
})
.collect::<FxHashMap<_, _>>();
let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
let mut map = IndexVec::from_elem_n(None, map_size as usize);
- for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
- let key = (crate_name.clone(), crate_disambiguator);
- map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
+ for &(prev_cnum, stable_crate_id) in prev_cnums {
+ map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&stable_crate_id).cloned();
}
map[LOCAL_CRATE] = Some(LOCAL_CRATE);
{
let tcx = self.tcx();
- let cache_key =
- ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+ let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
return Ok(ty);
}
}
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, HashStable)]
pub enum UpvarSubsts<'tcx> {
Closure(SubstsRef<'tcx>),
Generator(SubstsRef<'tcx>),
#[inline]
pub fn is_enum(&self) -> bool {
- match self.kind() {
- Adt(adt_def, _) => adt_def.is_enum(),
- _ => false,
- }
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
+ }
+
+ #[inline]
+ pub fn is_union(&self) -> bool {
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
}
#[inline]
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
- #[inline]
- pub fn is_machine(&self) -> bool {
- matches!(self.kind(), Int(..) | Uint(..) | Float(..))
- }
-
#[inline]
pub fn has_concrete_skeleton(&self) -> bool {
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
/// Interpret these substitutions as the substitutions of a generator type.
- /// Closure substitutions have a particular structure controlled by the
+ /// Generator substitutions have a particular structure controlled by the
/// compiler that encodes information like the signature and generator kind;
/// see `ty::GeneratorSubsts` struct for more comments.
pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
-use rustc_index::vec::Idx;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
- FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
bug!("temporary or return pointer with a name")
}
LocalKind::Var => "local variable ",
- LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => {
+ LocalKind::Arg
+ if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
+ {
"variable captured by `move` "
}
LocalKind::Arg => "function parameter ",
use rustc_hir as hir;
use rustc_hir::Node;
-use rustc_index::vec::Idx;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
}
}
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
- if the_place_err.local == Local::new(1)
+ if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
item_msg = format!("`{}`", access_place_desc.unwrap());
- debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+ debug_assert!(
+ self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
+ );
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
}
}
- PlaceRef {
- local,
- projection: [ProjectionElem::Deref],
- // FIXME document what is this 1 magic number about
- } if local == Local::new(1) && !self.upvars.is_empty() => {
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
+ {
self.expected_fn_found_fn_mut_call(&mut err, span, act);
}
// no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case.
let tcx = this.infcx.tcx;
- if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
- if def.is_union() {
- if this.move_data.path_map[mpi].iter().any(|moi| {
- this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
- }) {
- return;
- }
+ if base.ty(this.body(), tcx).ty.is_union() {
+ if this.move_data.path_map[mpi].iter().any(|moi| {
+ this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
+ }) {
+ return;
}
}
Overlap::EqualOrDisjoint
} else {
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
- match ty.kind() {
- ty::Adt(def, _) if def.is_union() => {
- // Different fields of a union, we are basically stuck.
- debug!("place_element_conflict: STUCK-UNION");
- Overlap::Arbitrary
- }
- _ => {
- // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
- debug!("place_element_conflict: DISJOINT-FIELD");
- Overlap::Disjoint
- }
+ if ty.is_union() {
+ // Different fields of a union, we are basically stuck.
+ debug!("place_element_conflict: STUCK-UNION");
+ Overlap::Arbitrary
+ } else {
+ // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
+ debug!("place_element_conflict: DISJOINT-FIELD");
+ Overlap::Disjoint
}
}
}
use super::InterpCx;
use crate::interpret::{
- struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
+ struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
};
/// The CTFE machine has some custom error kinds.
Abort(String),
}
+impl MachineStopType for ConstEvalErrKind {
+ fn is_hard_err(&self) -> bool {
+ match self {
+ Self::Panic { .. } => true,
+ _ => false,
+ }
+ }
+}
+
// The errors become `MachineStop` with plain strings when being raised.
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
// handle these.
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
fn into(self) -> InterpErrorInfo<'tcx> {
- err_machine_stop!(self.to_string()).into()
+ err_machine_stop!(self).into()
}
}
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
- lint_root: Option<hir::HirId>,
+ mut lint_root: Option<hir::HirId>,
) -> ErrorHandled {
- let must_error = match self.error {
- err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
- return ErrorHandled::TooGeneric;
- }
- err_inval!(AlreadyReported(error_reported)) => {
- return ErrorHandled::Reported(error_reported);
- }
- // We must *always* hard error on these, even if the caller wants just a lint.
- err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
- _ => false,
- };
- trace!("reporting const eval failure at {:?}", self.span);
-
- let err_msg = match &self.error {
- InterpError::MachineStop(msg) => {
- // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
- // Should be turned into a string by now.
- msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
- }
- err => err.to_string(),
- };
-
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
+ trace!("reporting const eval failure at {:?}", self.span);
if let Some(span_msg) = span_msg {
err.span_label(self.span, span_msg);
}
emit(err)
};
- if must_error {
- // The `message` makes little sense here, this is a more serious error than the
- // caller thinks anyway.
- // See <https://github.com/rust-lang/rust/pull/63152>.
- finish(struct_error(tcx, &err_msg), None);
- ErrorHandled::Reported(ErrorReported)
- } else {
- // Regular case.
- if let Some(lint_root) = lint_root {
- // Report as lint.
- let hir_id = self
- .stacktrace
- .iter()
- .rev()
- .find_map(|frame| frame.lint_root)
- .unwrap_or(lint_root);
- tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::CONST_ERR,
- hir_id,
- tcx.span,
- |lint| finish(lint.build(message), Some(err_msg)),
- );
- ErrorHandled::Linted
- } else {
- // Report as hard error.
- finish(struct_error(tcx, message), Some(err_msg));
- ErrorHandled::Reported(ErrorReported)
+ // Special handling for certain errors
+ match &self.error {
+ // Don't emit a new diagnostic for these errors
+ err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+ return ErrorHandled::TooGeneric;
+ }
+ err_inval!(AlreadyReported(error_reported)) => {
+ return ErrorHandled::Reported(*error_reported);
+ }
+ err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
+ // We must *always* hard error on these, even if the caller wants just a lint.
+ // The `message` makes little sense here, this is a more serious error than the
+ // caller thinks anyway.
+ // See <https://github.com/rust-lang/rust/pull/63152>.
+ finish(struct_error(tcx, &self.error.to_string()), None);
+ return ErrorHandled::Reported(ErrorReported);
}
+ _ => {}
+ };
+
+ // If we have a 'hard error', then set `lint_root` to `None` so that we don't
+ // emit a lint.
+ if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) {
+ lint_root = None;
+ }
+
+ let err_msg = self.error.to_string();
+
+ // Regular case - emit a lint.
+ if let Some(lint_root) = lint_root {
+ // Report as lint.
+ let hir_id =
+ self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
+ tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::CONST_ERR,
+ hir_id,
+ tcx.span,
+ |lint| finish(lint.build(message), Some(err_msg)),
+ );
+ ErrorHandled::Linted
+ } else {
+ // Report as hard error.
+ finish(struct_error(tcx, message), Some(err_msg));
+ ErrorHandled::Reported(ErrorReported)
}
}
}
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::{Abi, LayoutOf};
+use std::borrow::Cow;
use std::convert::TryInto;
pub fn note_on_undefined_behavior_error() -> &'static str {
(ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes())
}
Scalar::Int { .. } => (
- ecx.tcx
- .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])),
+ ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
+ b"" as &[u8],
+ )),
0,
),
};
))
} else {
let msg = if is_static {
- "could not evaluate static initializer"
+ Cow::from("could not evaluate static initializer")
} else {
- "evaluation of constant value failed"
+ // If the current item has generics, we'd like to enrich the message with the
+ // instance and its substs: to show the actual compile-time values, in addition to
+ // the expression, leading to the const eval error.
+ let instance = &key.value.instance;
+ if !instance.substs.is_empty() {
+ let instance = with_no_trimmed_paths(|| instance.to_string());
+ let msg = format!("evaluation of `{}` failed", instance);
+ Cow::from(msg)
+ } else {
+ Cow::from("evaluation of constant value failed")
+ }
};
- Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
+
+ Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg))
}
}
Ok(mplace) => {
use crate::interpret::{
self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory,
- OpTy, PlaceTy, Pointer, Scalar,
+ OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
};
use super::error::*;
_abi: Abi,
args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
+ _unwind: StackPopUnwind, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
debug!("find_mir_or_eval_fn: {:?}", instance);
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, ret)? {
// Check if we are assigning into a field of a union, if so, lookup the place
// of the union so it is marked as initialized again.
if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
- if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
- if def.is_union() {
- place = place_base;
- }
+ if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() {
+ place = place_base;
}
}
pub lint_root: Option<hir::HirId>,
}
-#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
+/// Unwind information.
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
+pub enum StackPopUnwind {
+ /// The cleanup block.
+ Cleanup(mir::BasicBlock),
+ /// No cleanup needs to be done.
+ Skip,
+ /// Unwinding is not allowed (UB).
+ NotAllowed,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
pub enum StackPopCleanup {
/// Jump to the next block in the caller, or cause UB if None (that's a function
/// that may never return). Also store layout of return place so
/// we can validate it at that layout.
/// `ret` stores the block we jump to on a normal return, while `unwind`
/// stores the block used for cleanup during unwinding.
- Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> },
+ Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
/// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
/// `cleanup` says whether locals are deallocated. Static computation
/// wants them leaked to intern what they need (and just throw away
/// *Unwind* to the given `target` basic block.
/// Do *not* use for returning! Use `return_to_block` instead.
///
- /// If `target` is `None`, that indicates the function does not need cleanup during
- /// unwinding, and we will just keep propagating that upwards.
- pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
+ /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
+ /// during unwinding, and we will just keep propagating that upwards.
+ ///
+ /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
+ /// unwinding, and doing so is UB.
+ pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
self.frame_mut().loc = match target {
- Some(block) => Ok(mir::Location { block, statement_index: 0 }),
- None => Err(self.frame_mut().body.span),
+ StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
+ StackPopUnwind::Skip => Err(self.frame_mut().body.span),
+ StackPopUnwind::NotAllowed => {
+ throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
+ }
};
+ Ok(())
}
/// Pops the current frame from the stack, deallocating the
}
}
+ let return_to_block = frame.return_to_block;
+
// Now where do we jump next?
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
// In that case, we return early. We also avoid validation in that case,
// because this is CTFE and the final value will be thoroughly validated anyway.
- let (cleanup, next_block) = match frame.return_to_block {
- StackPopCleanup::Goto { ret, unwind } => {
- (true, Some(if unwinding { unwind } else { ret }))
- }
- StackPopCleanup::None { cleanup, .. } => (cleanup, None),
+ let cleanup = match return_to_block {
+ StackPopCleanup::Goto { .. } => true,
+ StackPopCleanup::None { cleanup, .. } => cleanup,
};
if !cleanup {
assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
- assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
assert!(!unwinding, "tried to skip cleanup during unwinding");
// Leak the locals, skip validation, skip machine hook.
return Ok(());
// Normal return, figure out where to jump.
if unwinding {
// Follow the unwind edge.
- let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!");
- self.unwind_to_block(unwind);
+ let unwind = match return_to_block {
+ StackPopCleanup::Goto { unwind, .. } => unwind,
+ StackPopCleanup::None { .. } => {
+ panic!("Encountered StackPopCleanup::None when unwinding!")
+ }
+ };
+ self.unwind_to_block(unwind)
} else {
// Follow the normal return edge.
- if let Some(ret) = next_block {
- self.return_to_block(ret)?;
+ match return_to_block {
+ StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+ StackPopCleanup::None { .. } => Ok(()),
}
}
-
- Ok(())
}
/// Mark a storage as live, killing the previous content.
use std::convert::TryFrom;
+use rustc_ast::Mutability;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::TerminatorKind;
use rustc_middle::ty::subst::Subst;
line: u32,
col: u32,
) -> MPlaceTy<'tcx, M::PointerTag> {
- let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation);
+ let file =
+ self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
let line = Scalar::from_u32(line);
let col = Scalar::from_u32(col);
use rustc_hir::def_id::CrateNum;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_hir::definitions::DisambiguatedDefPathData;
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::ty::{
self,
}
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+ self.path.push_str(&self.tcx.crate_name(cnum).as_str());
Ok(self)
}
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- // Skip `::{{constructor}}` on tuple/unit structs.
- if disambiguated_data.data == DefPathData::Ctor {
- return Ok(self);
- }
-
write!(self.path, "::{}", disambiguated_data.data).unwrap();
Ok(self)
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
- let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
+ let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
tcx.intern_const_alloc(alloc)
}
use super::{
AllocId, Allocation, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, LocalValue,
- MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+ MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
};
/// Data returned by Machine::stack_pop,
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx>;
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx>;
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
_abi: Abi,
_args: &[OpTy<$tcx>],
_ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<$tcx> {
match fn_val {}
}
pub fn allocate_bytes(
&mut self,
bytes: &[u8],
+ align: Align,
kind: MemoryKind<M::MemoryKind>,
+ mutability: Mutability,
) -> Pointer<M::PointerTag> {
- let alloc = Allocation::from_byte_aligned_bytes(bytes);
+ let alloc = Allocation::from_bytes(bytes, align, mutability);
self.allocate_with(alloc, kind)
}
}
};
+ if alloc.mutability == Mutability::Not {
+ throw_ub_format!("deallocating immutable allocation {}", ptr.alloc_id);
+ }
if alloc_kind != kind {
throw_ub_format!(
"deallocating {}, which is {} memory, using {} deallocation operation",
// Need to make a copy, even if `get_global_alloc` is able
// to give us a cheap reference.
let alloc = Self::get_global_alloc(memory_extra, tcx, id, /*is_write*/ true)?;
- if alloc.mutability == Mutability::Not {
- throw_ub!(WriteToReadOnly(id))
- }
let kind = M::GLOBAL_KIND.expect(
"I got a global allocation that I have to copy but the machine does \
not expect that to happen",
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
-pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
+pub use self::eval_context::{
+ Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
+};
pub use self::intern::{intern_const_alloc_recursive, InternKind};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
use std::fmt::Debug;
use std::hash::Hash;
+use rustc_ast::Mutability;
use rustc_macros::HashStable;
use rustc_middle::mir;
use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
- alloc_range, mir_assign_valid_types, AllocId, AllocMap, AllocRef, AllocRefMut, Allocation,
- ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy,
- Operand, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit,
+ alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, ConstAlloc, ImmTy, Immediate,
+ InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
+ PointerArithmetic, Scalar, ScalarMaybeUninit,
};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
Tag: Debug + Copy + Eq + Hash + 'static,
M: Machine<'mir, 'tcx, PointerTag = Tag>,
- // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
- M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
{
/// Take a value, which represents a (thin or wide) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
MPlaceTy::from_aligned_ptr(ptr, layout)
}
- /// Returns a wide MPlace.
+ /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation.
pub fn allocate_str(
&mut self,
str: &str,
kind: MemoryKind<M::MemoryKind>,
+ mutbl: Mutability,
) -> MPlaceTy<'tcx, M::PointerTag> {
- let ptr = self.memory.allocate_bytes(str.as_bytes(), kind);
+ let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl);
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
let mplace =
MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
- let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
+ let ty = self.tcx.mk_ref(
+ self.tcx.lifetimes.re_static,
+ ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
+ );
+ let layout = self.layout_of(ty).unwrap();
MPlaceTy { mplace, layout }
}
use std::borrow::Cow;
use std::convert::TryFrom;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::ty::layout::{self, TyAndLayout};
use rustc_middle::ty::Instance;
use rustc_middle::{
mir,
use super::{
FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup,
+ StackPopUnwind,
};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+ fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
+ layout::fn_can_unwind(
+ self.tcx.sess.panic_strategy(),
+ attrs,
+ layout::conv_from_spec_abi(*self.tcx, abi),
+ abi,
+ )
+ }
+
pub(super) fn eval_terminator(
&mut self,
terminator: &mir::Terminator<'tcx>,
let old_stack = self.frame_idx();
let old_loc = self.frame().loc;
let func = self.eval_operand(func, None)?;
- let (fn_val, abi) = match *func.layout.ty.kind() {
+ let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() {
ty::FnPtr(sig) => {
let caller_abi = sig.abi();
let fn_ptr = self.read_scalar(&func)?.check_init()?;
let fn_val = self.memory.get_fn(fn_ptr)?;
- (fn_val, caller_abi)
+ (
+ fn_val,
+ caller_abi,
+ self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+ )
}
ty::FnDef(def_id, substs) => {
let sig = func.layout.ty.fn_sig(*self.tcx);
self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
),
sig.abi(),
+ self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()),
)
}
_ => span_bug!(
}
None => None,
};
- self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
+ self.eval_fn_call(
+ fn_val,
+ abi,
+ &args[..],
+ ret,
+ match (cleanup, caller_can_unwind) {
+ (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
+ (None, true) => StackPopUnwind::Skip,
+ (_, false) => StackPopUnwind::NotAllowed,
+ },
+ )?;
// Sanity-check that `eval_fn_call` either pushed a new frame or
// did a jump to another block.
if self.frame_idx() == old_stack && self.frame().loc == old_loc {
caller_abi: Abi,
args: &[OpTy<'tcx, M::PointerTag>],
ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ mut unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
trace!("eval_fn_call: {:#?}", fn_val);
}
};
+ let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
+ ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
+ ty::Closure(..) => Abi::RustCall,
+ ty::Generator(..) => Abi::Rust,
+ _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
+ };
+
// ABI check
- let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
- if M::enforce_abi(this) {
- let callee_abi = match instance_ty.kind() {
- ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
- ty::Closure(..) => Abi::RustCall,
- ty::Generator(..) => Abi::Rust,
- _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
- };
- let normalize_abi = |abi| match abi {
- Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
- // These are all the same ABI, really.
- {
- Abi::Rust
- }
- abi => abi,
- };
- if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
- throw_ub_format!(
- "calling a function with ABI {} using caller ABI {}",
- callee_abi.name(),
- caller_abi.name()
- )
+ let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
+ let normalize_abi = |abi| match abi {
+ Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
+ // These are all the same ABI, really.
+ {
+ Abi::Rust
}
+ abi => abi,
+ };
+ if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
+ throw_ub_format!(
+ "calling a function with ABI {} using caller ABI {}",
+ callee_abi.name(),
+ caller_abi.name()
+ )
}
Ok(())
};
match instance.def {
ty::InstanceDef::Intrinsic(..) => {
- check_abi(self, instance.ty(*self.tcx, self.param_env))?;
+ if M::enforce_abi(self) {
+ check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
+ }
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
M::call_intrinsic(self, instance, args, ret, unwind)
}
// Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
// these can differ when `find_mir_or_eval_fn` does something clever like resolve
// exported symbol names).
- check_abi(self, self.tcx.type_of(body.source.def_id()))?;
+ let callee_def_id = body.source.def_id();
+ let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
+
+ if M::enforce_abi(self) {
+ check_abi(callee_abi)?;
+ }
+
+ if !matches!(unwind, StackPopUnwind::NotAllowed)
+ && !self
+ .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi)
+ {
+ // The callee cannot unwind.
+ unwind = StackPopUnwind::NotAllowed;
+ }
self.push_stack_frame(
instance,
Abi::Rust,
&[arg.into()],
Some((&dest.into(), target)),
- unwind,
+ match unwind {
+ Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+ None => StackPopUnwind::Skip,
+ },
)
}
}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
-#![feature(exhaustive_patterns)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
-#![feature(slice_ptr_len)]
#![feature(slice_ptr_get)]
#![feature(trusted_len)]
#![feature(try_blocks)]
#![feature(stmt_expr_attributes)]
#![feature(trait_alias)]
#![feature(option_get_or_insert_default)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(once_cell)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
use rustc_errors::{ErrorReported, FatalError};
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Local, Location};
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
.collect()
}
-// Collect all monomorphized items reachable from `starting_point`
+/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
+/// post-monorphization error is encountered during a collection step.
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
starting_point: Spanned<MonoItem<'tcx>>,
let mut neighbors = Vec::new();
let recursion_depth_reset;
+ //
+ // Post-monomorphization errors MVP
+ //
+ // We can encounter errors while monomorphizing an item, but we don't have a good way of
+ // showing a complete stack of spans ultimately leading to collecting the erroneous one yet.
+ // (It's also currently unclear exactly which diagnostics and information would be interesting
+ // to report in such cases)
+ //
+ // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be
+ // shown with just a spanned piece of code causing the error, without information on where
+ // it was called from. This is especially obscure if the erroneous mono item is in a
+ // dependency. See for example issue #85155, where, before minimization, a PME happened two
+ // crates downstream from libcore's stdarch, without a way to know which dependency was the
+ // cause.
+ //
+ // If such an error occurs in the current crate, its span will be enough to locate the
+ // source. If the cause is in another crate, the goal here is to quickly locate which mono
+ // item in the current crate is ultimately responsible for causing the error.
+ //
+ // To give at least _some_ context to the user: while collecting mono items, we check the
+ // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the
+ // current step of mono items collection.
+ //
+ let error_count = tcx.sess.diagnostic().err_count();
+
match starting_point.node {
MonoItem::Static(def_id) => {
let instance = Instance::mono(tcx, def_id);
}
}
+ // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
+ // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones
+ // 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
+ {
+ let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
+ tcx.sess.span_note_without_error(
+ starting_point.span,
+ &format!("the above error was encountered while instantiating `{}`", formatted_item),
+ );
+ }
+
record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
for neighbour in neighbors {
}
fn check_static(&mut self, def_id: DefId, span: Span) {
- assert!(
- !self.tcx.is_thread_local_static(def_id),
- "tls access is checked in `Rvalue::ThreadLocalRef"
- );
+ if self.tcx.is_thread_local_static(def_id) {
+ self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
+ }
self.check_op_spanned(ops::StaticAccess, span)
}
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- match base_ty.ty_adt_def() {
- Some(def) if def.is_union() => {
- self.check_op(ops::UnionAccess);
- }
-
- _ => {}
+ if base_ty.is_union() {
+ self.check_op(ops::UnionAccess);
}
}
}
}
let base_ty = base.ty(self.body, self.tcx).ty;
- if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+ if base_ty.is_union() {
// If we did not hit a `Deref` yet and the overall place use is an assignment, the
// rules are different.
let assign_to_field = !saw_deref
/// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
/// the called function has target features the calling function hasn't.
fn check_target_features(&mut self, func_did: DefId) {
+ // Unsafety isn't required on wasm targets. For more information see
+ // the corresponding check in typeck/src/collect.rs
+ if self.tcx.sess.target.options.is_like_wasm {
+ return;
+ }
+
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
simplify_locals(body, tcx);
}
}
self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy,
Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
+ StackPopUnwind,
};
use crate::transform::MirPass;
_abi: Abi,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
- _unwind: Option<BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
Ok(None)
}
_instance: ty::Instance<'tcx>,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
- _unwind: Option<BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
}
use crate::util::spanview::{self, SpanViewable};
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
use rustc_middle::ty::TyCtxt;
if has_opts_to_apply {
let mut opt_applier = OptApplier { tcx, duplicates };
opt_applier.visit_body(body);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::TyCtxt;
// Empirical measurements have resulted in some observations:
// - Running on a body with a single block and 500 locals takes barely any time
// Handle the "subtle case" described above by rejecting any `dest` that is or
// projects through a union.
- let is_union = |ty: Ty<'_>| {
- if let ty::Adt(def, _) = ty.kind() {
- if def.is_union() {
- return true;
- }
- }
-
- false
- };
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return;
}
for elem in dest.projection {
}
place_ty = place_ty.projection_ty(self.tcx, elem);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return;
}
}
// Since this optimization adds new basic blocks and invalidates others,
// clean up the cfg to make it nicer for other passes
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
// Make sure we remove dead blocks to remove
// unrelated code from the resume part of the function
- simplify::remove_dead_blocks(&mut body);
+ simplify::remove_dead_blocks(tcx, &mut body);
dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
// Make sure we remove dead blocks to remove
// unrelated code from the drop part of the function
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
}
if inline(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
}
}
}
}
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
}
- simplify::remove_dead_blocks(body)
+ simplify::remove_dead_blocks(tcx, body)
}
}
ProjectionElem::Field(..) => {
let base_ty = place_base.ty(self.body, self.tcx).ty;
- if let Some(def) = base_ty.ty_adt_def() {
+ if base_ty.is_union() {
// No promotion of union field accesses.
- if def.is_union() {
- return Err(Unpromotable);
- }
+ return Err(Unpromotable);
}
}
}
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
tcx: TyCtxt<'tcx>,
) -> bool {
let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return true;
}
for elem in place.projection {
place_ty = place_ty.projection_ty(tcx, elem);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return true;
}
}
return false;
}
-
-fn is_union(ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Adt(def, _) if def.is_union() => true,
- _ => false,
- }
-}
use crate::transform::MirPass;
use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
}
}
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
// FIXME: Should probably be moved into some kind of pass manager
body.basic_blocks_mut().raw.shrink_to_fit();
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
let reachable = traversal::reachable_as_bitset(body);
let num_blocks = body.basic_blocks().len();
if num_blocks == reachable.count() {
}
used_blocks += 1;
}
+
+ if tcx.sess.instrument_coverage() {
+ save_unreachable_coverage(basic_blocks, used_blocks);
+ }
+
basic_blocks.raw.truncate(used_blocks);
for block in basic_blocks {
}
}
+/// Some MIR transforms can determine at compile time that a sequences of
+/// statements will never be executed, so they can be dropped from the MIR.
+/// For example, an `if` or `else` block that is guaranteed to never be executed
+/// because its condition can be evaluated at compile time, such as by const
+/// evaluation: `if false { ... }`.
+///
+/// Those statements are bypassed by redirecting paths in the CFG around the
+/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// include `Coverage` statements representing the Rust source code regions to
+/// be counted at runtime. Without these `Coverage` statements, the regions are
+/// lost, and the Rust source code will show no coverage information.
+///
+/// What we want to show in a coverage report is the dead code with coverage
+/// counts of `0`. To do this, we need to save the code regions, by injecting
+/// `Unreachable` coverage statements. These are non-executable statements whose
+/// code regions are still recorded in the coverage map, representing regions
+/// with `0` executions.
+fn save_unreachable_coverage(
+ basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+ first_dead_block: usize,
+) {
+ let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
+ live_block.statements.iter().any(|statement| {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ matches!(coverage.kind, CoverageKind::Counter { .. })
+ } else {
+ false
+ }
+ })
+ });
+ if !has_live_counters {
+ // If there are no live `Counter` `Coverage` statements anymore, don't
+ // move dead coverage to the `START_BLOCK`. Just allow the dead
+ // `Coverage` statements to be dropped with the dead blocks.
+ //
+ // The `generator::StateTransform` MIR pass can create atypical
+ // conditions, where all live `Counter`s are dropped from the MIR.
+ //
+ // At least one Counter per function is required by LLVM (and necessary,
+ // to add the `function_hash` to the counter's call to the LLVM
+ // intrinsic `instrprof.increment()`).
+ return;
+ }
+
+ // Retain coverage info for dead blocks, so coverage reports will still
+ // report `0` executions for the uncovered code regions.
+ let mut dropped_coverage = Vec::new();
+ for dead_block in basic_blocks.raw[first_dead_block..].iter() {
+ for statement in dead_block.statements.iter() {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ if let Some(code_region) = &coverage.code_region {
+ dropped_coverage.push((statement.source_info, code_region.clone()));
+ }
+ }
+ }
+ }
+
+ let start_block = &mut basic_blocks[START_BLOCK];
+ for (source_info, code_region) in dropped_coverage {
+ start_block.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Coverage(box Coverage {
+ kind: CoverageKind::Unreachable,
+ code_region: Some(code_region),
+ }),
+ })
+ }
+}
+
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
if did_remove_blocks {
// We have dead blocks now, so remove those.
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
}
if replaced {
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
- Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind,
+ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
+ PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ TerminatorKind,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
self.super_operand(operand, location);
}
+ fn visit_projection_elem(
+ &mut self,
+ local: Local,
+ proj_base: &[PlaceElem<'tcx>],
+ elem: PlaceElem<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ if let ProjectionElem::Index(index) = elem {
+ let index_ty = self.body.local_decls[index].ty;
+ if index_ty != self.tcx.types.usize {
+ self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+ }
+ }
+ self.super_projection_elem(local, proj_base, elem, context, location);
+ }
+
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match &statement.kind {
StatementKind::Assign(box (dest, rvalue)) => {
use gsgdt::{Edge, Graph, Node, NodeStyle};
use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::thir::*;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level;
use rustc_span::Span;
//! See docs in build/expr/mod.rs
use crate::build::Builder;
-use crate::thir::*;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'a, 'tcx> Builder<'a, 'tcx> {
use crate::build::expr::category::Category;
use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Returns an operand suitable for use until the end of the current
use crate::build::expr::category::Category;
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind::BoundsCheck;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty::AdtDef;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
use rustc_span::Span;
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
- // Captures are represented using fields inside a structure.
- // This represents accessing self in the closure structure
- let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
+ let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
match closure_kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
// match x { _ => () } // fake read of `x`
// };
// ```
+ //
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
} => {
// Not in a closure
debug_assert!(
- local == Local::new(1),
+ local == ty::CAPTURE_STRUCT_LOCAL,
"Expected local to be Local(1), found {:?}",
local
);
use crate::build::scope::DropKind;
use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building
-use crate::thir::*;
+use rustc_middle::thir::*;
#[derive(Debug, PartialEq)]
crate enum Category {
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::thir::*;
use rustc_ast::InlineAsmOptions;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
use std::iter;
block.unit()
}
ExprKind::InlineAsm { template, ref operands, options, line_spans } => {
- use crate::thir;
- use rustc_middle::mir;
+ use rustc_middle::{mir, thir};
let operands = operands
.into_iter()
.map(|op| match *op {
use crate::build::scope::BreakableTarget;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Builds a block of MIR statements to evaluate the THIR `expr`.
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
-use crate::thir::{self, *};
use rustc_data_structures::{
fx::{FxHashSet, FxIndexMap},
stack::ensure_sufficient_stack,
use rustc_index::bit_set::BitSet;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
..
},
ascription:
- thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
+ thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
} => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
PatKind::AscribeUserType {
ref subpattern,
- ascription: thir::pattern::Ascription { ref user_ty, user_ty_span, variance: _ },
+ ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
} => {
// This corresponds to something like
//
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
-use crate::thir::{self, *};
use rustc_hir::RangeEnd;
+use rustc_middle::thir::{self, *};
use rustc_middle::ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_target::abi::{Integer, Size};
match *match_pair.pattern.kind {
PatKind::AscribeUserType {
ref subpattern,
- ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
+ ascription: thir::Ascription { variance, user_ty, user_ty_span },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
candidate.ascriptions.push(Ascription {
use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
use crate::build::Builder;
use crate::thir::pattern::compare_const_vals;
-use crate::thir::*;
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{LangItem, RangeEnd};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty::subst::{GenericArg, Subst};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
-use crate::thir::*;
use rustc_middle::mir::*;
+use rustc_middle::thir::*;
use rustc_middle::ty;
use smallvec::SmallVec;
use std::convert::TryInto;
use crate::build;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
-use crate::thir::{build_thir, BindingMode, Expr, ExprId, LintLevel, Pat, PatKind, Thir};
+use crate::thir::pattern::pat_from_hir;
use rustc_attr::{self as attr, UnwindAttr};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
use rustc_span::symbol::{kw, sym};
let body_owner_kind = tcx.hir().body_owner_kind(id);
let typeck_results = tcx.typeck_opt_const_arg(def);
+ // Ensure unsafeck is ran before we steal the THIR.
+ match def {
+ ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
+ tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did))
+ }
+ ty::WithOptConstParam { did, const_param_did: None } => {
+ tcx.ensure().thir_check_unsafety(did)
+ }
+ }
+
// Figure out what primary body this item has.
let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
};
let body = tcx.hir().body(body_id);
- let (thir, expr) = build_thir(tcx, def, &body.value);
+ let (thir, expr) = tcx.thir_body(def);
+ // We ran all queries that depended on THIR at the beginning
+ // of `mir_build`, so now we can steal it
+ let thir = thir.steal();
let ty = tcx.type_of(fn_def_id);
let mut abi = fn_sig.abi;
let implicit_argument = match ty.kind() {
let return_ty = typeck_results.node_type(id);
- let ast_expr = &tcx.hir().body(body_id).value;
- let (thir, expr) = build_thir(tcx, def, ast_expr);
+ let (thir, expr) = tcx.thir_body(def);
+ // We ran all queries that depended on THIR at the beginning
+ // of `mir_build`, so now we can steal it
+ let thir = thir.steal();
build::construct_const(&thir, &infcx, expr, def, id, return_ty, return_ty_span)
};
// the given closure and use the necessary information to create upvar
// debuginfo and to fill `self.upvar_mutbls`.
if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
- let closure_env_arg = Local::new(1);
let mut closure_env_projs = vec![];
- let mut closure_ty = self.local_decls[closure_env_arg].ty;
+ let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
if let ty::Ref(_, ty, _) = closure_ty.kind() {
closure_env_projs.push(ProjectionElem::Deref);
closure_ty = ty;
name,
source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
value: VarDebugInfoContents::Place(Place {
- local: closure_env_arg,
+ local: ty::CAPTURE_STRUCT_LOCAL,
projection: tcx.intern_place_elems(&projs),
}),
});
Node::Pat(pat) | Node::Binding(pat) => pat,
node => bug!("pattern became {:?}", node),
};
- let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat);
+ let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
let original_source_scope = self.source_scope;
let span = pattern.span;
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
*/
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::thir::{Expr, LintLevel};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
+use rustc_middle::thir::{Expr, LintLevel};
+
use rustc_span::{Span, DUMMY_SP};
#[derive(Debug)]
use crate::thir::visit::{self, Visitor};
-use crate::thir::*;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_middle::thir::*;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
self.warn_unused_unsafe(
hir_id,
block_span,
- Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
+ Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
);
f(self);
} else {
f(self);
if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
- self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
+ self.warn_unused_unsafe(
+ hir_id,
+ span,
+ if self.unsafe_op_in_unsafe_fn_allowed() {
+ self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+ } else {
+ None
+ },
+ );
}
self.safety_context = prev_context;
return;
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
SafetyContext::UnsafeFn => {
// unsafe_op_in_unsafe_fn is disallowed
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.struct_span_lint_hir(
+ UNSAFE_OP_IN_UNSAFE_FN,
+ self.hir_context,
span,
- E0133,
- "{} is unsafe and requires unsafe block",
- description,
+ |lint| {
+ lint.build(&format!(
+ "{} is unsafe and requires unsafe block (error E0133)",
+ description,
+ ))
+ .span_label(span, description)
+ .note(note)
+ .emit();
+ },
)
- .span_label(span, description)
- .note(note)
- .emit();
}
SafetyContext::Safe => {
let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
&self,
hir_id: hir::HirId,
block_span: Span,
- enclosing_span: Option<Span>,
+ enclosing_unsafe: Option<(Span, &'static str)>,
) {
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
let msg = "unnecessary `unsafe` block";
let mut db = lint.build(msg);
db.span_label(block_span, msg);
- if let Some(enclosing_span) = enclosing_span {
- db.span_label(
- enclosing_span,
- format!("because it's nested under this `unsafe` block"),
- );
+ if let Some((span, kind)) = enclosing_unsafe {
+ db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
}
db.emit();
});
self.requires_unsafe(expr.span, CallToUnsafeFunction);
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
// If the called function has target features the calling function hasn't,
- // the call requires `unsafe`.
- if !self
- .tcx
- .codegen_fn_attrs(func_did)
- .target_features
- .iter()
- .all(|feature| self.body_target_features.contains(feature))
+ // the call requires `unsafe`. Don't check this on wasm
+ // targets, though. For more information on wasm see the
+ // is_like_wasm check in typeck/src/collect.rs
+ if !self.tcx.sess.target.options.is_like_wasm
+ && !self
+ .tcx
+ .codegen_fn_attrs(func_did)
+ .target_features
+ .iter()
+ .all(|feature| self.body_target_features.contains(feature))
{
self.requires_unsafe(expr.span, CallToFunctionWith);
}
self.requires_unsafe(expr.span, CastOfPointerToInt);
}
}
+ ExprKind::Closure {
+ closure_id,
+ substs: _,
+ upvars: _,
+ movability: _,
+ fake_reads: _,
+ } => {
+ let closure_id = closure_id.expect_local();
+ let closure_def = if let Some((did, const_param_id)) =
+ ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
+ {
+ ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
+ } else {
+ ty::WithOptConstParam::unknown(closure_id)
+ };
+ let (closure_thir, expr) = self.tcx.thir_body(closure_def);
+ let closure_thir = &closure_thir.borrow();
+ let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
+ let mut closure_visitor =
+ UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
+ closure_visitor.visit_expr(&closure_thir[expr]);
+ // Unsafe blocks can be used in closures, make sure to take it into account
+ self.safety_context = closure_visitor.safety_context;
+ }
_ => {}
}
),
DerefOfRawPointer => (
"dereference of raw pointer",
- "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+ "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AssignToDroppingUnionField => (
}
}
-// FIXME: checking unsafety for closures should be handled by their parent body,
-// as they inherit their "safety context" from their declaration site.
-pub fn check_unsafety<'tcx>(
- tcx: TyCtxt<'tcx>,
- thir: &Thir<'tcx>,
- expr: ExprId,
- def_id: LocalDefId,
- hir_id: hir::HirId,
-) {
+pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
+ // THIR unsafeck is gated under `-Z thir-unsafeck`
+ if !tcx.sess.opts.debugging_opts.thir_unsafeck {
+ return;
+ }
+
+ // Closures are handled by their parent function
+ if tcx.is_closure(def.did.to_def_id()) {
+ tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id_to_hir_id(def.did).owner);
+ return;
+ }
+
+ let (thir, expr) = tcx.thir_body(def);
+ let thir = &thir.borrow();
+ // If `thir` is empty, a type error occured, skip this body.
+ if thir.exprs.is_empty() {
+ return;
+ }
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
BodyUnsafety::Unsafe(fn_sig.span)
BodyUnsafety::Safe
}
});
- let body_target_features = &tcx.codegen_fn_attrs(def_id).target_features;
+ let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let is_const = match tcx.hir().body_owner_kind(hir_id) {
hir::BodyOwnerKind::Closure => false,
- hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def_id.to_def_id()),
+ hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
};
let mut visitor = UnsafetyVisitor {
visitor.visit_expr(&thir[expr]);
}
-crate fn thir_check_unsafety_inner<'tcx>(
- tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
-) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- let body_id = tcx.hir().body_owned_by(hir_id);
- let body = tcx.hir().body(body_id);
- let (thir, expr) = cx::build_thir(tcx, def, &body.value);
- check_unsafety(tcx, &thir, expr, def.did, hir_id);
-}
-
crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
tcx.thir_check_unsafety_for_const_arg(def)
} else {
- thir_check_unsafety_inner(tcx, ty::WithOptConstParam::unknown(def_id))
+ check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id))
}
}
tcx: TyCtxt<'tcx>,
(did, param_did): (LocalDefId, DefId),
) {
- thir_check_unsafety_inner(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
+ check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
}
//! Construction of MIR from HIR.
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
-#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
#![feature(iter_zip)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
providers.mir_built = build::mir_built;
providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
+ providers.thir_body = thir::cx::thir_body;
}
let lit = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
- let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
+ let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
- let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
+ let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
use crate::thir::cx::Cx;
-use crate::thir::{self, *};
use rustc_hir as hir;
use rustc_middle::middle::region;
+use rustc_middle::thir::*;
use rustc_middle::ty;
use rustc_index::vec::Idx;
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatKind::AscribeUserType {
- ascription: thir::pattern::Ascription {
+ ascription: Ascription {
user_ty: PatTyProj::from_user_type(user_ty),
user_ty_span: ty.span,
variance: ty::Variance::Covariant,
use crate::thir::cx::Cx;
use crate::thir::util::UserAnnotatedTyHelpers;
-use crate::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
+use rustc_middle::middle::region;
use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::BorrowKind;
+use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
};
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, AdtKind, Ty};
+use rustc_middle::ty::{self, AdtKind, Ty, UpvarSubsts, UserType};
+use rustc_span::def_id::DefId;
use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
impl<'tcx> Cx<'tcx> {
crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
//! etc., and instead goes through the `Cx` for most of its work.
+use crate::thir::pattern::pat_from_hir;
use crate::thir::util::UserAnnotatedTyHelpers;
-use crate::thir::*;
use rustc_ast as ast;
+use rustc_data_structures::steal::Steal;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
-pub fn build_thir<'tcx>(
+crate fn thir_body<'tcx>(
tcx: TyCtxt<'tcx>,
owner_def: ty::WithOptConstParam<LocalDefId>,
- expr: &'tcx hir::Expr<'tcx>,
-) -> (Thir<'tcx>, ExprId) {
+) -> (&'tcx Steal<Thir<'tcx>>, ExprId) {
+ let hir = tcx.hir();
+ let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did)));
let mut cx = Cx::new(tcx, owner_def);
- let expr = cx.mirror_expr(expr);
- (cx.thir, expr)
+ if cx.typeck_results.tainted_by_errors.is_some() {
+ return (tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0));
+ }
+ let expr = cx.mirror_expr(&body.value);
+ (tcx.alloc_steal_thir(cx.thir), expr)
}
struct Cx<'tcx> {
Node::Pat(p) | Node::Binding(p) => p,
node => bug!("pattern became {:?}", node),
};
- Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
+ pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
}
}
//! unit-tested and separated from the Rust source and compiler data
//! structures.
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_index::newtype_index;
-use rustc_index::vec::IndexVec;
-use rustc_middle::infer::canonical::Canonical;
-use rustc_middle::middle::region;
-use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
-use rustc_middle::ty::adjustment::PointerCast;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
-use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
-use rustc_target::asm::InlineAsmRegOrRegClass;
-
-use std::ops::Index;
-
crate mod constant;
crate mod cx;
-pub use cx::build_thir;
crate mod pattern;
-pub use self::pattern::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
mod util;
pub mod visit;
-
-newtype_index! {
- pub struct ArmId {
- DEBUG_FORMAT = "a{}"
- }
-}
-
-newtype_index! {
- pub struct ExprId {
- DEBUG_FORMAT = "e{}"
- }
-}
-
-newtype_index! {
- pub struct StmtId {
- DEBUG_FORMAT = "s{}"
- }
-}
-
-macro_rules! thir_with_elements {
- ($($name:ident: $id:ty => $value:ty,)*) => {
- pub struct Thir<'tcx> {
- $(
- $name: IndexVec<$id, $value>,
- )*
- }
-
- impl<'tcx> Thir<'tcx> {
- fn new() -> Thir<'tcx> {
- Thir {
- $(
- $name: IndexVec::new(),
- )*
- }
- }
- }
-
- $(
- impl<'tcx> Index<$id> for Thir<'tcx> {
- type Output = $value;
- fn index(&self, index: $id) -> &Self::Output {
- &self.$name[index]
- }
- }
- )*
- }
-}
-
-thir_with_elements! {
- arms: ArmId => Arm<'tcx>,
- exprs: ExprId => Expr<'tcx>,
- stmts: StmtId => Stmt<'tcx>,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum LintLevel {
- Inherited,
- Explicit(hir::HirId),
-}
-
-#[derive(Debug)]
-pub struct Block {
- pub targeted_by_break: bool,
- pub region_scope: region::Scope,
- pub opt_destruction_scope: Option<region::Scope>,
- pub span: Span,
- pub stmts: Box<[StmtId]>,
- pub expr: Option<ExprId>,
- pub safety_mode: BlockSafety,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum BlockSafety {
- Safe,
- ExplicitUnsafe(hir::HirId),
- PushUnsafe,
- PopUnsafe,
-}
-
-#[derive(Debug)]
-pub struct Stmt<'tcx> {
- pub kind: StmtKind<'tcx>,
- pub opt_destruction_scope: Option<region::Scope>,
-}
-
-#[derive(Debug)]
-pub enum StmtKind<'tcx> {
- Expr {
- /// scope for this statement; may be used as lifetime of temporaries
- scope: region::Scope,
-
- /// expression being evaluated in this statement
- expr: ExprId,
- },
-
- Let {
- /// scope for variables bound in this let; covers this and
- /// remaining statements in block
- remainder_scope: region::Scope,
-
- /// scope for the initialization itself; might be used as
- /// lifetime of temporaries
- init_scope: region::Scope,
-
- /// `let <PAT> = ...`
- ///
- /// if a type is included, it is added as an ascription pattern
- pattern: Pat<'tcx>,
-
- /// let pat: ty = <INIT> ...
- initializer: Option<ExprId>,
-
- /// the lint level for this let-statement
- lint_level: LintLevel,
- },
-}
-
-// `Expr` 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!(Expr<'_>, 144);
-
-/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
-/// into instances of this `Expr` enum. This lowering can be done
-/// basically as lazily or as eagerly as desired: every recursive
-/// reference to an expression in this enum is an `ExprId`, which
-/// may in turn be another instance of this enum (boxed), or else an
-/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
-/// short-lived. They are created by `Thir::to_expr`, analyzed and
-/// converted into MIR, and then discarded.
-///
-/// If you compare `Expr` to the full compiler AST, you will see it is
-/// a good bit simpler. In fact, a number of the more straight-forward
-/// MIR simplifications are already done in the impl of `Thir`. For
-/// example, method calls and overloaded operators are absent: they are
-/// expected to be converted into `Expr::Call` instances.
-#[derive(Debug)]
-pub struct Expr<'tcx> {
- /// type of this expression
- pub ty: Ty<'tcx>,
-
- /// lifetime of this expression if it should be spilled into a
- /// temporary; should be None only if in a constant context
- pub temp_lifetime: Option<region::Scope>,
-
- /// span of the expression in the source
- pub span: Span,
-
- /// kind of expression
- pub kind: ExprKind<'tcx>,
-}
-
-#[derive(Debug)]
-pub enum ExprKind<'tcx> {
- Scope {
- region_scope: region::Scope,
- lint_level: LintLevel,
- value: ExprId,
- },
- Box {
- value: ExprId,
- },
- If {
- cond: ExprId,
- then: ExprId,
- else_opt: Option<ExprId>,
- },
- Call {
- ty: Ty<'tcx>,
- fun: ExprId,
- args: Box<[ExprId]>,
- /// Whether this is from a call in HIR, rather than from an overloaded
- /// operator. `true` for overloaded function call.
- from_hir_call: bool,
- /// This `Span` is the span of the function, without the dot and receiver
- /// (e.g. `foo(a, b)` in `x.foo(a, b)`
- fn_span: Span,
- },
- Deref {
- arg: ExprId,
- }, // NOT overloaded!
- Binary {
- op: BinOp,
- lhs: ExprId,
- rhs: ExprId,
- }, // NOT overloaded!
- LogicalOp {
- op: LogicalOp,
- lhs: ExprId,
- rhs: ExprId,
- }, // NOT overloaded!
- // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
- Unary {
- op: UnOp,
- arg: ExprId,
- }, // NOT overloaded!
- Cast {
- source: ExprId,
- },
- Use {
- source: ExprId,
- }, // Use a lexpr to get a vexpr.
- NeverToAny {
- source: ExprId,
- },
- Pointer {
- cast: PointerCast,
- source: ExprId,
- },
- Loop {
- body: ExprId,
- },
- Match {
- scrutinee: ExprId,
- arms: Box<[ArmId]>,
- },
- Block {
- body: Block,
- },
- Assign {
- lhs: ExprId,
- rhs: ExprId,
- },
- AssignOp {
- op: BinOp,
- lhs: ExprId,
- rhs: ExprId,
- },
- Field {
- lhs: ExprId,
- name: Field,
- },
- Index {
- lhs: ExprId,
- index: ExprId,
- },
- VarRef {
- id: hir::HirId,
- },
- /// Used to represent upvars mentioned in a closure/generator
- UpvarRef {
- /// DefId of the closure/generator
- closure_def_id: DefId,
-
- /// HirId of the root variable
- var_hir_id: hir::HirId,
- },
- Borrow {
- borrow_kind: BorrowKind,
- arg: ExprId,
- },
- /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
- AddressOf {
- mutability: hir::Mutability,
- arg: ExprId,
- },
- Break {
- label: region::Scope,
- value: Option<ExprId>,
- },
- Continue {
- label: region::Scope,
- },
- Return {
- value: Option<ExprId>,
- },
- ConstBlock {
- value: &'tcx Const<'tcx>,
- },
- Repeat {
- value: ExprId,
- count: &'tcx Const<'tcx>,
- },
- Array {
- fields: Box<[ExprId]>,
- },
- Tuple {
- fields: Box<[ExprId]>,
- },
- Adt {
- adt_def: &'tcx AdtDef,
- variant_index: VariantIdx,
- substs: SubstsRef<'tcx>,
-
- /// Optional user-given substs: for something like `let x =
- /// Bar::<T> { ... }`.
- user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-
- fields: Box<[FieldExpr]>,
- base: Option<FruInfo<'tcx>>,
- },
- PlaceTypeAscription {
- source: ExprId,
- /// Type that the user gave to this expression
- user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
- },
- ValueTypeAscription {
- source: ExprId,
- /// Type that the user gave to this expression
- user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
- },
- Closure {
- closure_id: DefId,
- substs: UpvarSubsts<'tcx>,
- upvars: Box<[ExprId]>,
- movability: Option<hir::Movability>,
- fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
- },
- Literal {
- literal: &'tcx Const<'tcx>,
- user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
- /// The `DefId` of the `const` item this literal
- /// was produced from, if this is not a user-written
- /// literal value.
- const_id: Option<DefId>,
- },
- /// A literal containing the address of a `static`.
- ///
- /// This is only distinguished from `Literal` so that we can register some
- /// info for diagnostics.
- StaticRef {
- literal: &'tcx Const<'tcx>,
- def_id: DefId,
- },
- InlineAsm {
- template: &'tcx [InlineAsmTemplatePiece],
- operands: Box<[InlineAsmOperand<'tcx>]>,
- options: InlineAsmOptions,
- line_spans: &'tcx [Span],
- },
- /// An expression taking a reference to a thread local.
- ThreadLocalRef(DefId),
- LlvmInlineAsm {
- asm: &'tcx hir::LlvmInlineAsmInner,
- outputs: Box<[ExprId]>,
- inputs: Box<[ExprId]>,
- },
- Yield {
- value: ExprId,
- },
-}
-
-#[derive(Debug)]
-pub struct FieldExpr {
- pub name: Field,
- pub expr: ExprId,
-}
-
-#[derive(Debug)]
-pub struct FruInfo<'tcx> {
- pub base: ExprId,
- pub field_types: Box<[Ty<'tcx>]>,
-}
-
-#[derive(Debug)]
-pub struct Arm<'tcx> {
- pub pattern: Pat<'tcx>,
- pub guard: Option<Guard<'tcx>>,
- pub body: ExprId,
- pub lint_level: LintLevel,
- pub scope: region::Scope,
- pub span: Span,
-}
-
-#[derive(Debug)]
-pub enum Guard<'tcx> {
- If(ExprId),
- IfLet(Pat<'tcx>, ExprId),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum LogicalOp {
- And,
- Or,
-}
-
-#[derive(Debug)]
-pub enum InlineAsmOperand<'tcx> {
- In {
- reg: InlineAsmRegOrRegClass,
- expr: ExprId,
- },
- Out {
- reg: InlineAsmRegOrRegClass,
- late: bool,
- expr: Option<ExprId>,
- },
- InOut {
- reg: InlineAsmRegOrRegClass,
- late: bool,
- expr: ExprId,
- },
- SplitInOut {
- reg: InlineAsmRegOrRegClass,
- late: bool,
- in_expr: ExprId,
- out_expr: Option<ExprId>,
- },
- Const {
- value: &'tcx Const<'tcx>,
- span: Span,
- },
- SymFn {
- expr: ExprId,
- },
- SymStatic {
- def_id: DefId,
- },
-}
use super::usefulness::{
- compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability,
+ compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability,
UsefulnessReport,
};
-use super::{PatCtxt, PatKind, PatternError};
+use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat};
+use rustc_middle::thir::PatKind;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
/// Checks for common cases of "catchall" patterns that may not be intended as such.
fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
- use super::PatKind::*;
+ use PatKind::*;
match &*pat.kind {
Binding { subpattern: None, .. } => true,
Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
&& !is_empty_match
&& witnesses.len() == 1
- && witnesses[0].is_wildcard()
+ && is_wildcard(&witnesses[0])
{
err.note(&format!(
"`{}` does not have a fixed maximum value, \
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::Field;
+use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_session::lint;
use std::cell::Cell;
-use super::{FieldPat, Pat, PatCtxt, PatKind};
+use super::PatCtxt;
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts an evaluated constant to a pattern (if possible).
use self::SliceKind::*;
use super::compare_const_vals;
-use super::usefulness::{MatchCheckCtxt, PatCtxt};
-use super::{FieldPat, Pat, PatKind, PatRange};
+use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_hir::{HirId, RangeEnd};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::Field;
+use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_session::lint;
// of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
// This is incorrect if the size is not known, since `[_, ..]` captures
// arrays of lengths `>= 1` whereas `[..]` captures any length.
- while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
+ while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
prefix.pop();
}
}
let suffix: Vec<_> = if slice.array_len.is_some() {
// Same as above.
- subpatterns.skip_while(Pat::is_wildcard).collect()
+ subpatterns.skip_while(is_wildcard).collect()
} else {
subpatterns.collect()
};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
use rustc_index::vec::Idx;
use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
use rustc_middle::mir::UserTypeProjection;
use rustc_middle::mir::{BorrowKind, Field, Mutability};
+use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
-use rustc_middle::ty::{
- CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-};
-use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_target::abi::VariantIdx;
+use rustc_span::{Span, Symbol};
use std::cmp::Ordering;
-use std::fmt;
#[derive(Clone, Debug)]
crate enum PatternError {
NonConstPath(Span),
}
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum BindingMode {
- ByValue,
- ByRef(BorrowKind),
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct FieldPat<'tcx> {
- pub field: Field,
- pub pattern: Pat<'tcx>,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct Pat<'tcx> {
- pub ty: Ty<'tcx>,
- pub span: Span,
- pub kind: Box<PatKind<'tcx>>,
-}
-
-impl<'tcx> Pat<'tcx> {
- pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
- Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatTyProj<'tcx> {
- pub user_ty: CanonicalUserType<'tcx>,
-}
-
-impl<'tcx> PatTyProj<'tcx> {
- pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
- Self { user_ty: user_annotation }
- }
-
- pub(crate) fn user_ty(
- self,
- annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
- inferred_ty: Ty<'tcx>,
- span: Span,
- ) -> UserTypeProjection {
- UserTypeProjection {
- base: annotations.push(CanonicalUserTypeAnnotation {
- span,
- user_ty: self.user_ty,
- inferred_ty,
- }),
- projs: Vec::new(),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct Ascription<'tcx> {
- pub user_ty: PatTyProj<'tcx>,
- /// Variance to use when relating the type `user_ty` to the **type of the value being
- /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
- /// have a type that is some subtype of the ascribed type.
- ///
- /// Note that this variance does not apply for any bindings within subpatterns. The type
- /// assigned to those bindings must be exactly equal to the `user_ty` given here.
- ///
- /// The only place where this field is not `Covariant` is when matching constants, where
- /// we currently use `Contravariant` -- this is because the constant type just needs to
- /// be "comparable" to the type of the input value. So, for example:
- ///
- /// ```text
- /// match x { "foo" => .. }
- /// ```
- ///
- /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
- /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
- /// of the old type-check for now. See #57280 for details.
- pub variance: ty::Variance,
- pub user_ty_span: Span,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum PatKind<'tcx> {
- Wild,
-
- AscribeUserType {
- ascription: Ascription<'tcx>,
- subpattern: Pat<'tcx>,
- },
-
- /// `x`, `ref x`, `x @ P`, etc.
- Binding {
- mutability: Mutability,
- name: Symbol,
- mode: BindingMode,
- var: hir::HirId,
- ty: Ty<'tcx>,
- subpattern: Option<Pat<'tcx>>,
- /// Is this the leftmost occurrence of the binding, i.e., is `var` the
- /// `HirId` of this pattern?
- is_primary: bool,
- },
-
- /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
- /// multiple variants.
- Variant {
- adt_def: &'tcx AdtDef,
- substs: SubstsRef<'tcx>,
- variant_index: VariantIdx,
- subpatterns: Vec<FieldPat<'tcx>>,
- },
-
- /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
- /// a single variant.
- Leaf {
- subpatterns: Vec<FieldPat<'tcx>>,
- },
-
- /// `box P`, `&P`, `&mut P`, etc.
- Deref {
- subpattern: Pat<'tcx>,
- },
-
- /// One of the following:
- /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
- /// checking will detect if you use the same string twice in different patterns.
- /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
- /// its own value, similar to `&str`, but these values are much simpler.
- /// * Opaque constants, that must not be matched structurally. So anything that does not derive
- /// `PartialEq` and `Eq`.
- Constant {
- value: &'tcx ty::Const<'tcx>,
- },
-
- Range(PatRange<'tcx>),
-
- /// Matches against a slice, checking the length and extracting elements.
- /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
- /// e.g., `&[ref xs @ ..]`.
- Slice {
- prefix: Vec<Pat<'tcx>>,
- slice: Option<Pat<'tcx>>,
- suffix: Vec<Pat<'tcx>>,
- },
-
- /// Fixed match against an array; irrefutable.
- Array {
- prefix: Vec<Pat<'tcx>>,
- slice: Option<Pat<'tcx>>,
- suffix: Vec<Pat<'tcx>>,
- },
-
- /// An or-pattern, e.g. `p | q`.
- /// Invariant: `pats.len() >= 2`.
- Or {
- pats: Vec<Pat<'tcx>>,
- },
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatRange<'tcx> {
- pub lo: &'tcx ty::Const<'tcx>,
- pub hi: &'tcx ty::Const<'tcx>,
- pub end: RangeEnd,
-}
-
-impl<'tcx> fmt::Display for Pat<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // Printing lists is a chore.
- let mut first = true;
- let mut start_or_continue = |s| {
- if first {
- first = false;
- ""
- } else {
- s
- }
- };
- let mut start_or_comma = || start_or_continue(", ");
-
- match *self.kind {
- PatKind::Wild => write!(f, "_"),
- PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
- PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
- let is_mut = match mode {
- BindingMode::ByValue => mutability == Mutability::Mut,
- BindingMode::ByRef(bk) => {
- write!(f, "ref ")?;
- matches!(bk, BorrowKind::Mut { .. })
- }
- };
- if is_mut {
- write!(f, "mut ")?;
- }
- write!(f, "{}", name)?;
- if let Some(ref subpattern) = *subpattern {
- write!(f, " @ {}", subpattern)?;
- }
- Ok(())
- }
- PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
- let variant = match *self.kind {
- PatKind::Variant { adt_def, variant_index, .. } => {
- Some(&adt_def.variants[variant_index])
- }
- _ => {
- if let ty::Adt(adt, _) = self.ty.kind() {
- if !adt.is_enum() {
- Some(&adt.variants[VariantIdx::new(0)])
- } else {
- None
- }
- } else {
- None
- }
- }
- };
-
- if let Some(variant) = variant {
- write!(f, "{}", variant.ident)?;
-
- // Only for Adt we can have `S {...}`,
- // which we handle separately here.
- if variant.ctor_kind == CtorKind::Fictive {
- write!(f, " {{ ")?;
-
- let mut printed = 0;
- for p in subpatterns {
- if let PatKind::Wild = *p.pattern.kind {
- continue;
- }
- let name = variant.fields[p.field.index()].ident;
- write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
- printed += 1;
- }
-
- if printed < variant.fields.len() {
- write!(f, "{}..", start_or_comma())?;
- }
-
- return write!(f, " }}");
- }
- }
-
- let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
- if num_fields != 0 || variant.is_none() {
- write!(f, "(")?;
- for i in 0..num_fields {
- write!(f, "{}", start_or_comma())?;
-
- // Common case: the field is where we expect it.
- if let Some(p) = subpatterns.get(i) {
- if p.field.index() == i {
- write!(f, "{}", p.pattern)?;
- continue;
- }
- }
-
- // Otherwise, we have to go looking for it.
- if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
- write!(f, "{}", p.pattern)?;
- } else {
- write!(f, "_")?;
- }
- }
- write!(f, ")")?;
- }
-
- Ok(())
- }
- PatKind::Deref { ref subpattern } => {
- match self.ty.kind() {
- ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
- ty::Ref(_, _, mutbl) => {
- write!(f, "&{}", mutbl.prefix_str())?;
- }
- _ => bug!("{} is a bad Deref pattern type", self.ty),
- }
- write!(f, "{}", subpattern)
- }
- PatKind::Constant { value } => write!(f, "{}", value),
- PatKind::Range(PatRange { lo, hi, end }) => {
- write!(f, "{}", lo)?;
- write!(f, "{}", end)?;
- write!(f, "{}", hi)
- }
- PatKind::Slice { ref prefix, ref slice, ref suffix }
- | PatKind::Array { ref prefix, ref slice, ref suffix } => {
- write!(f, "[")?;
- for p in prefix {
- write!(f, "{}{}", start_or_comma(), p)?;
- }
- if let Some(ref slice) = *slice {
- write!(f, "{}", start_or_comma())?;
- match *slice.kind {
- PatKind::Wild => {}
- _ => write!(f, "{}", slice)?,
- }
- write!(f, "..")?;
- }
- for p in suffix {
- write!(f, "{}{}", start_or_comma(), p)?;
- }
- write!(f, "]")
- }
- PatKind::Or { ref pats } => {
- for pat in pats {
- write!(f, "{}{}", start_or_continue(" | "), pat)?;
- }
- Ok(())
- }
- }
- }
-}
-
crate struct PatCtxt<'a, 'tcx> {
crate tcx: TyCtxt<'tcx>,
crate param_env: ty::ParamEnv<'tcx>,
include_lint_checks: bool,
}
-impl<'a, 'tcx> Pat<'tcx> {
- crate fn from_hir(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- typeck_results: &'a ty::TypeckResults<'tcx>,
- pat: &'tcx hir::Pat<'tcx>,
- ) -> Self {
- let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
- let result = pcx.lower_pattern(pat);
- if !pcx.errors.is_empty() {
- let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
- tcx.sess.delay_span_bug(pat.span, &msg);
- }
- debug!("Pat::from_hir({:?}) = {:?}", pat, result);
- result
- }
+crate fn pat_from_hir<'a, 'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
+ pat: &'tcx hir::Pat<'tcx>,
+) -> Pat<'tcx> {
+ let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
+ let result = pcx.lower_pattern(pat);
+ if !pcx.errors.is_empty() {
+ let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
+ tcx.sess.delay_span_bug(pat.span, &msg);
+ }
+ debug!("pat_from_hir({:?}) = {:?}", pat, result);
+ result
}
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
use self::WitnessPreference::*;
use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
-use super::{Pat, PatKind};
use super::{PatternFoldable, PatternFolder};
use rustc_data_structures::captures::Captures;
use rustc_arena::TypedArena;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
+use rustc_middle::thir::{Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
}
}
-impl<'tcx> Pat<'tcx> {
- pub(super) fn is_wildcard(&self) -> bool {
- matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
- }
+pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool {
+ matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+}
- fn is_or_pat(&self) -> bool {
- matches!(*self.kind, PatKind::Or { .. })
- }
+fn is_or_pat(pat: &Pat<'_>) -> bool {
+ matches!(*pat.kind, PatKind::Or { .. })
+}
- /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
- fn expand_or_pat(&self) -> Vec<&Self> {
- fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
- if let PatKind::Or { pats } = pat.kind.as_ref() {
- for pat in pats {
- expand(pat, vec);
- }
- } else {
- vec.push(pat)
+/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
+fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
+ fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
+ if let PatKind::Or { pats } = pat.kind.as_ref() {
+ for pat in pats {
+ expand(pat, vec);
}
+ } else {
+ vec.push(pat)
}
-
- let mut pats = Vec::new();
- expand(self, &mut pats);
- pats
}
+
+ let mut pats = Vec::new();
+ expand(pat, &mut pats);
+ pats
}
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
// Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
// or-pattern. Panics if `self` is empty.
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
- self.head().expand_or_pat().into_iter().map(move |pat| {
+ expand_or_pat(self.head()).into_iter().map(move |pat| {
let mut new_patstack = PatStack::from_pattern(pat);
new_patstack.pats.extend_from_slice(&self.pats[1..]);
new_patstack
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
- if !row.is_empty() && row.head().is_or_pat() {
+ if !row.is_empty() && is_or_pat(row.head()) {
for row in row.expand_or_pat() {
self.patterns.push(row);
}
}
}
SubPatSet::Alt { subpats, pat, alt_count, .. } => {
- let expanded = pat.expand_or_pat();
+ let expanded = expand_or_pat(pat);
for i in 0..*alt_count {
let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
if sub_set.is_empty() {
let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
// If the first pattern is an or-pattern, expand it.
- let ret = if v.head().is_or_pat() {
+ let ret = if is_or_pat(v.head()) {
debug!("expanding or-pattern");
let v_head = v.head();
let vs: Vec<_> = v.expand_or_pat().collect();
#[derive(Clone, Copy)]
crate struct MatchArm<'p, 'tcx> {
/// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
- crate pat: &'p super::Pat<'tcx>,
+ crate pat: &'p Pat<'tcx>,
crate hir_id: HirId,
crate has_guard: bool,
}
crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
/// exhaustiveness.
- crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
+ crate non_exhaustiveness_witnesses: Vec<Pat<'tcx>>,
}
/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
})
.collect();
- let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
+ let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty));
let v = PatStack::from_pattern(wild_pattern);
let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
let non_exhaustiveness_witnesses = match usefulness {
-use crate::thir::*;
+use rustc_middle::thir::*;
+use rustc_middle::ty::Const;
pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn thir(&self) -> &'a Thir<'tcx>;
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
#![feature(bindings_after_at)]
-#![feature(iter_order_by)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
} else {
let err = if self.check_fn_front_matter(false) {
- let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
+ // We use `parse_fn` to get a span for the function
+ if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+ db.delay_as_bug();
+ }
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
&format!("functions are not allowed in {} definitions", adt_ty),
test(attr(deny(warnings)))
)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(bool_to_option)]
pub use Alignment::*;
let mut is_valid = true;
if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) {
- for meta in list {
+ for meta in &list {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
sym::alias
| sym::html_no_source
| sym::html_playground_url
| sym::html_root_url
- | sym::include
| sym::inline
| sym::issue_tracker_base_url
| sym::keyword
);
diag.note("`doc(spotlight)` is now a no-op");
}
+ if i_meta.has_name(sym::include) {
+ if let Some(value) = i_meta.value_str() {
+ // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
+ let applicability = if list.len() == 1 {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ };
+ let inner = if attr.style == AttrStyle::Inner {
+ "!"
+ } else {
+ ""
+ };
+ diag.span_suggestion(
+ attr.meta().unwrap().span,
+ "use `doc = include_str!` instead",
+ format!(
+ "#{}[doc = include_str!(\"{}\")]",
+ inner, value
+ ),
+ applicability,
+ );
+ }
+ }
diag.emit();
},
);
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(control_flow_enum)]
#![feature(try_blocks)]
#![feature(associated_type_defaults)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(in_band_lifetimes)]
-#![feature(exhaustive_patterns)]
#![feature(nll)]
#![feature(min_specialization)]
-#![feature(crate_visibility_modifier)]
-#![feature(once_cell)]
#![feature(rustc_attrs)]
-#![feature(never_type)]
#![recursion_limit = "256"]
#[macro_use]
use rustc_middle::ty::query::{Providers, QueryEngine};
use rustc_middle::ty::{self, TyCtxt};
use rustc_serialize::opaque;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
#[macro_use]
mod plumbing;
//! manage the caches, and so forth.
use super::queries;
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::query::on_disk_cache;
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
use rustc_serialize::opaque;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
#[derive(Copy, Clone)]
pub struct QueryCtxt<'tcx> {
impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
type Target = TyCtxt<'tcx>;
+ #[inline]
fn deref(&self) -> &Self::Target {
&self.tcx
}
}
impl QueryContext for QueryCtxt<'tcx> {
- fn def_path_str(&self, def_id: DefId) -> String {
- self.tcx.def_path_str(def_id)
- }
-
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
tls::with_related_context(**self, |icx| icx.query)
}
}
fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
- // FIXME: This match is just a workaround for incremental bugs and should
- // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
- // bug that must be fixed before removing this.
- match dep_node.kind {
- DepKind::hir_owner | DepKind::hir_owner_nodes => {
- if let Some(def_id) = dep_node.extract_def_id(**self) {
- let def_id = def_id.expect_local();
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- if def_id != hir_id.owner {
- // This `DefPath` does not have a
- // corresponding `DepNode` (e.g. a
- // struct field), and the ` DefPath`
- // collided with the `DefPath` of a
- // proper item that existed in the
- // previous compilation session.
- //
- // Since the given `DefPath` does not
- // denote the item that previously
- // existed, we just fail to mark green.
- return false;
- }
- } else {
- // If the node does not exist anymore, we
- // just fail to mark green.
- return false;
- }
- }
- _ => {
- // For other kinds of nodes it's OK to be
- // forced.
- }
- }
-
debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
// We must avoid ever having to call `force_from_dep_node()` for a
}
fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
- if is_anon {
- return false;
- }
-
- if !can_reconstruct_query_key() {
- return false;
- }
-
- if let Some(key) = recover(*tcx, dep_node) {
- force_query::<queries::$name<'_>, _>(tcx, key, DUMMY_SP, *dep_node);
- return true;
- }
-
- false
+ force_query::<queries::$name<'_>, _>(tcx, dep_node)
}
fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
match def_key.disambiguated_data.data {
DefPathData::CrateRoot => {
- crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
+ crate_name = self.tcx.crate_name(def_id.krate).as_str();
name = &*crate_name;
dis = "";
end_index = 3;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;
-use super::prev::PreviousDepGraph;
use super::query::DepGraphQuery;
-use super::serialized::{GraphEncoder, SerializedDepNodeIndex};
+use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
use crate::query::QueryContext;
impl DepNodeIndex {
pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
+ pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
}
impl std::convert::From<DepNodeIndex> for QueryInvocationId {
/// The dep-graph from the previous compilation session. It contains all
/// nodes and edges as well as all fingerprints of nodes that have them.
- previous: PreviousDepGraph<K>,
+ previous: SerializedDepGraph<K>,
colors: DepNodeColorMap,
impl<K: DepKind> DepGraph<K> {
pub fn new(
- prev_graph: PreviousDepGraph<K>,
+ profiler: &SelfProfilerRef,
+ prev_graph: SerializedDepGraph<K>,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
encoder: FileEncoder,
record_graph: bool,
) -> DepGraph<K> {
let prev_graph_node_count = prev_graph.node_count();
+ let current =
+ CurrentDepGraph::new(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(
+ profiler,
+ DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
+ smallvec![],
+ Fingerprint::ZERO,
+ );
+ debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
dep_node_debug: Default::default(),
- current: CurrentDepGraph::new(
- prev_graph_node_count,
- encoder,
- record_graph,
- record_stats,
- ),
+ current,
emitting_diagnostics: Default::default(),
emitting_diagnostics_cond_var: Condvar::new(),
previous: prev_graph,
let task_deps = Lock::new(TaskDeps::default());
let result = K::with_deps(Some(&task_deps), op);
let task_deps = task_deps.into_inner();
+ let task_deps = task_deps.reads;
+
+ let dep_node_index = match task_deps.len() {
+ 0 => {
+ // Because the dep-node id of anon nodes is computed from the sets of its
+ // dependencies we already know what the ID of this dependency-less node is
+ // going to be (i.e. equal to the precomputed
+ // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
+ // a `StableHasher` and sending the node through interning.
+ DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
+ }
+ 1 => {
+ // When there is only one dependency, don't bother creating a node.
+ task_deps[0]
+ }
+ _ => {
+ // The dep node indices are hashed here instead of hashing the dep nodes of the
+ // dependencies. These indices may refer to different nodes per session, but this isn't
+ // a problem here because we that ensure the final dep node hash is per session only by
+ // combining it with the per session random number `anon_id_seed`. This hash only need
+ // to map the dependencies to a single value on a per session basis.
+ let mut hasher = StableHasher::new();
+ task_deps.hash(&mut hasher);
+
+ let target_dep_node = DepNode {
+ kind: dep_kind,
+ // Fingerprint::combine() is faster than sending Fingerprint
+ // through the StableHasher (at least as long as StableHasher
+ // is so slow).
+ hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+ };
- // The dep node indices are hashed here instead of hashing the dep nodes of the
- // dependencies. These indices may refer to different nodes per session, but this isn't
- // a problem here because we that ensure the final dep node hash is per session only by
- // combining it with the per session random number `anon_id_seed`. This hash only need
- // to map the dependencies to a single value on a per session basis.
- let mut hasher = StableHasher::new();
- task_deps.reads.hash(&mut hasher);
-
- let target_dep_node = DepNode {
- kind: dep_kind,
- // Fingerprint::combine() is faster than sending Fingerprint
- // through the StableHasher (at least as long as StableHasher
- // is so slow).
- hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+ data.current.intern_new_node(
+ cx.profiler(),
+ target_dep_node,
+ task_deps,
+ Fingerprint::ZERO,
+ )
+ }
};
- let dep_node_index = data.current.intern_new_node(
- cx.profiler(),
- target_dep_node,
- task_deps.reads,
- Fingerprint::ZERO,
- );
-
(result, dep_node_index)
} else {
(op(), self.next_virtual_depnode_index())
}
}
+ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+ &self,
+ tcx: Ctxt,
+ data: &DepGraphData<K>,
+ parent_dep_node_index: SerializedDepNodeIndex,
+ dep_node: &DepNode<K>,
+ ) -> Option<()> {
+ let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+ let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index);
+
+ match dep_dep_node_color {
+ Some(DepNodeColor::Green(_)) => {
+ // This dependency has been marked as green before, we are
+ // still fine and can continue with checking the other
+ // dependencies.
+ debug!(
+ "try_mark_previous_green({:?}) --- found dependency {:?} to \
+ be immediately green",
+ dep_node, dep_dep_node,
+ );
+ return Some(());
+ }
+ Some(DepNodeColor::Red) => {
+ // We found a dependency the value of which has changed
+ // compared to the previous compilation session. We cannot
+ // mark the DepNode as green and also don't need to bother
+ // with checking any of the other dependencies.
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
+ dep_node, dep_dep_node,
+ );
+ return None;
+ }
+ None => {}
+ }
+
+ // 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() {
+ debug!(
+ "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
+ is unknown, trying to mark it green",
+ dep_node, dep_dep_node, dep_dep_node.hash,
+ );
+
+ let node_index =
+ self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+ if node_index.is_some() {
+ debug!(
+ "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
+ dep_node, dep_dep_node
+ );
+ return Some(());
+ }
+ }
+
+ // We failed to mark it green, so we try to force the query.
+ debug!(
+ "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
+ dep_node, dep_dep_node
+ );
+ if !tcx.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",
+ dep_node, dep_dep_node
+ );
+ return None;
+ }
+
+ let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+
+ match dep_dep_node_color {
+ Some(DepNodeColor::Green(_)) => {
+ debug!(
+ "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
+ dep_node, dep_dep_node
+ );
+ return Some(());
+ }
+ Some(DepNodeColor::Red) => {
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
+ dep_node, dep_dep_node
+ );
+ return None;
+ }
+ None => {}
+ }
+
+ if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+ panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
+ }
+
+ // If the query we just forced has resulted in
+ // some kind of compilation error, we cannot rely on
+ // the dep-node color having been properly updated.
+ // This means that the query system has reached an
+ // invalid state. We let the compiler continue (by
+ // returning `None`) so it can emit error messages
+ // and wind down, but rely on the fact that this
+ // invalid state will not be persisted to the
+ // incremental compilation cache because of
+ // compilation errors being present.
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error",
+ dep_node, dep_dep_node
+ );
+ return None;
+ }
+
/// Try to mark a dep-node which existed in the previous compilation session as green.
fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
&self,
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
for &dep_dep_node_index in prev_deps {
- let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
- match dep_dep_node_color {
- Some(DepNodeColor::Green(_)) => {
- // This dependency has been marked as green before, we are
- // still fine and can continue with checking the other
- // dependencies.
- debug!(
- "try_mark_previous_green({:?}) --- found dependency {:?} to \
- be immediately green",
- dep_node,
- data.previous.index_to_node(dep_dep_node_index)
- );
- }
- Some(DepNodeColor::Red) => {
- // We found a dependency the value of which has changed
- // compared to the previous compilation session. We cannot
- // mark the DepNode as green and also don't need to bother
- // with checking any of the other dependencies.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} was \
- immediately red",
- dep_node,
- data.previous.index_to_node(dep_dep_node_index)
- );
- return None;
- }
- None => {
- let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
-
- // 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() {
- debug!(
- "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
- is unknown, trying to mark it green",
- dep_node, dep_dep_node, dep_dep_node.hash,
- );
-
- let node_index = self.try_mark_previous_green(
- tcx,
- data,
- dep_dep_node_index,
- dep_dep_node,
- );
- if node_index.is_some() {
- debug!(
- "try_mark_previous_green({:?}) --- managed to MARK \
- dependency {:?} as green",
- dep_node, dep_dep_node
- );
- continue;
- }
- }
-
- // We failed to mark it green, so we try to force the query.
- debug!(
- "try_mark_previous_green({:?}) --- trying to force \
- dependency {:?}",
- dep_node, dep_dep_node
- );
- if tcx.try_force_from_dep_node(dep_dep_node) {
- let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
- match dep_dep_node_color {
- Some(DepNodeColor::Green(_)) => {
- debug!(
- "try_mark_previous_green({:?}) --- managed to \
- FORCE dependency {:?} to green",
- dep_node, dep_dep_node
- );
- }
- Some(DepNodeColor::Red) => {
- debug!(
- "try_mark_previous_green({:?}) - END - \
- dependency {:?} was red after forcing",
- dep_node, dep_dep_node
- );
- return None;
- }
- None => {
- if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
- panic!(
- "try_mark_previous_green() - Forcing the DepNode \
- should have set its color"
- )
- } else {
- // If the query we just forced has resulted in
- // some kind of compilation error, we cannot rely on
- // the dep-node color having been properly updated.
- // This means that the query system has reached an
- // invalid state. We let the compiler continue (by
- // returning `None`) so it can emit error messages
- // and wind down, but rely on the fact that this
- // invalid state will not be persisted to the
- // incremental compilation cache because of
- // compilation errors being present.
- debug!(
- "try_mark_previous_green({:?}) - END - \
- dependency {:?} resulted in compilation error",
- dep_node, dep_dep_node
- );
- return None;
- }
- }
- }
- } else {
- // The DepNode could not be forced.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} \
- could not be forced",
- dep_node, dep_dep_node
- );
- return None;
- }
- }
- }
+ self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
}
// If we got here without hitting a `return` that means that all
}
}
- fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+ pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
DepNodeIndex::from_u32(index)
}
/// For this reason, we avoid storing `DepNode`s more than once as map
/// keys. The `new_node_to_index` map only contains nodes not in the previous
/// graph, and we map nodes in the previous graph to indices via a two-step
-/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
/// and the `prev_index_to_index` vector (which is more compact and faster than
/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
///
fn intern_node(
&self,
profiler: &SelfProfilerRef,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
key: DepNode<K>,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
fn promote_node_and_deps_to_current(
&self,
profiler: &SelfProfilerRef,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
prev_index: SerializedDepNodeIndex,
) -> DepNodeIndex {
self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
#[inline]
fn debug_assert_not_in_new_nodes(
&self,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
prev_index: SerializedDepNodeIndex,
) {
let node = &prev_graph.index_to_node(prev_index);
pub mod debug;
mod dep_node;
mod graph;
-mod prev;
mod query;
mod serialized;
pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
-pub use prev::PreviousDepGraph;
pub use query::DepGraphQuery;
pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+++ /dev/null
-use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
-use super::{DepKind, DepNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-
-#[derive(Debug)]
-pub struct PreviousDepGraph<K: DepKind> {
- data: SerializedDepGraph<K>,
- index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
-}
-
-impl<K: DepKind> Default for PreviousDepGraph<K> {
- fn default() -> Self {
- PreviousDepGraph { data: Default::default(), index: Default::default() }
- }
-}
-
-impl<K: DepKind> PreviousDepGraph<K> {
- pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
- let index: FxHashMap<_, _> =
- data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
- PreviousDepGraph { data, index }
- }
-
- #[inline]
- pub fn edge_targets_from(
- &self,
- dep_node_index: SerializedDepNodeIndex,
- ) -> &[SerializedDepNodeIndex] {
- self.data.edge_targets_from(dep_node_index)
- }
-
- #[inline]
- pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
- self.data.nodes[dep_node_index]
- }
-
- #[inline]
- pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
- self.index.get(dep_node).cloned()
- }
-
- #[inline]
- pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
- self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
- }
-
- #[inline]
- pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
- self.data.fingerprints[dep_node_index]
- }
-
- pub fn node_count(&self) -> usize {
- self.index.len()
- }
-}
#[derive(Debug)]
pub struct SerializedDepGraph<K: DepKind> {
/// The set of all DepNodes in the graph
- pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
+ nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// the DepNode at the same index in the nodes vector.
- pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
+ fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
- pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
+ edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
/// A flattened list of all edge targets in the graph. Edge sources are
/// implicit in edge_list_indices.
- pub edge_list_data: Vec<SerializedDepNodeIndex>,
+ edge_list_data: Vec<SerializedDepNodeIndex>,
+ /// Reciprocal map to `nodes`.
+ index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
}
impl<K: DepKind> Default for SerializedDepGraph<K> {
fingerprints: Default::default(),
edge_list_indices: Default::default(),
edge_list_data: Default::default(),
+ index: Default::default(),
}
}
}
let targets = self.edge_list_indices[source];
&self.edge_list_data[targets.0 as usize..targets.1 as usize]
}
+
+ #[inline]
+ pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+ self.nodes[dep_node_index]
+ }
+
+ #[inline]
+ pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
+ self.index.get(dep_node).cloned()
+ }
+
+ #[inline]
+ pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
+ self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index])
+ }
+
+ #[inline]
+ pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
+ self.fingerprints[dep_node_index]
+ }
+
+ pub fn node_count(&self) -> usize {
+ self.index.len()
+ }
}
impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
})?;
}
- Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data })
+ let index: FxHashMap<_, _> =
+ nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
+
+ Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index })
}
}
#![feature(bool_to_option)]
-#![feature(const_panic)]
#![feature(core_intrinsics)]
-#![feature(drain_filter)]
#![feature(hash_raw_entry)]
#![feature(iter_zip)]
#![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
#[macro_use]
extern crate tracing;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefId;
use rustc_span::Span;
/// Description of a frame in the query stack.
}
pub trait QueryContext: HasDepContext {
- /// Get string representation from DefPath.
- fn def_path_str(&self, def_id: DefId) -> String;
-
/// Get the query information from the TLS context.
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
//! 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};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams};
use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
use crate::query::caches::QueryCache;
use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
#[cfg(not(parallel_compiler))]
use rustc_errors::DiagnosticBuilder;
use rustc_errors::{Diagnostic, FatalError};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
) -> C::Stored
where
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
}
};
- // Fast path for when incr. comp. is off. `to_dep_node` is
- // expensive for some `DepKind`s.
- if !tcx.dep_context().dep_graph().is_fully_enabled() {
- let null_dep_node = DepNode::new_no_params(DepKind::NULL);
- return force_query_with_job(tcx, key, job, null_dep_node, query).0;
+ let dep_graph = tcx.dep_context().dep_graph();
+
+ // 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, || query.compute(tcx, key));
+ let dep_node_index = dep_graph.next_virtual_depnode_index();
+ prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+ return job.complete(result, dep_node_index);
}
if query.anon {
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
tcx.start_query(job.id, diagnostics, || {
- tcx.dep_context().dep_graph().with_anon_task(
- *tcx.dep_context(),
- query.dep_kind,
- || query.compute(tcx, key),
- )
+ dep_graph
+ .with_anon_task(*tcx.dep_context(), query.dep_kind, || query.compute(tcx, key))
})
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
- tcx.dep_context().dep_graph().read_index(dep_node_index);
+ dep_graph.read_index(dep_node_index);
if unlikely!(!diagnostics.is_empty()) {
tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
// promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
let loaded = tcx.start_query(job.id, None, || {
- let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node);
+ let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node);
marked.map(|(prev_dep_node_index, dep_node_index)| {
(
load_from_disk_and_cache_in_memory(
}
let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query);
- tcx.dep_context().dep_graph().read_index(dep_node_index);
+ dep_graph.read_index(dep_node_index);
result
}
where
CTX: QueryContext,
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
{
try_execute_query(tcx, state, cache, span, key, lookup, query)
}
tcx: CTX,
state: &QueryState<CTX::DepKind, C::Key>,
cache: &QueryCacheStore<C>,
- key: C::Key,
- span: Span,
dep_node: DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, C::Key, C::Value>,
-) where
+) -> bool
+where
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
+ debug_assert!(!query.anon);
+
+ if !<C::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
+ return false;
+ }
+
+ let key = if let Some(key) =
+ <C::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
+ {
+ key
+ } else {
+ return false;
+ };
+
// 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| {
});
let lookup = match cached {
- Ok(()) => return,
+ Ok(()) => return true,
Err(lookup) => lookup,
};
tcx,
state,
cache,
- span,
+ DUMMY_SP,
key.clone(),
lookup,
query,
) {
TryGetJob::NotYetStarted(job) => job,
- TryGetJob::Cycle(_) => return,
+ TryGetJob::Cycle(_) => return true,
#[cfg(parallel_compiler)]
- TryGetJob::JobCompleted(_) => return,
+ TryGetJob::JobCompleted(_) => return true,
};
+
force_query_with_job(tcx, key, job, dep_node, query);
+
+ true
}
pub enum QueryMode {
) -> Option<Q::Stored>
where
Q: QueryDescription<CTX>,
- Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
let query = &Q::VTABLE;
Some(value)
}
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
where
Q: QueryDescription<CTX>,
- Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE)
+ if Q::ANON {
+ return false;
+ }
+
+ force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), *dep_node, &Q::VTABLE)
}
}
err
}
- ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
- let res = binding.res();
- let shadows_what = res.descr();
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr,
+ name,
+ participle,
+ article,
+ shadowed_binding_descr,
+ shadowed_binding_span,
+ } => {
let mut err = struct_span_err!(
self.session,
span,
E0530,
"{}s cannot shadow {}s",
- what_binding,
- shadows_what
+ shadowing_binding_descr,
+ shadowed_binding_descr,
);
err.span_label(
span,
- format!("cannot be named the same as {} {}", res.article(), shadows_what),
+ format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
);
- let participle = if binding.is_import() { "imported" } else { "defined" };
- let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
- err.span_label(binding.span, msg);
+ let msg =
+ format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
+ err.span_label(shadowed_binding_span, msg);
err
}
- ResolutionError::ForwardDeclaredTyParam => {
+ ResolutionError::ForwardDeclaredGenericParam => {
let mut err = struct_span_err!(
self.session,
span,
// to something unusable as a pattern (e.g., constructor function),
// but we still conservatively report an error, see
// issues/33118#issuecomment-233962221 for one reason why.
+ let binding = binding.expect("no binding for a ctor or static");
self.report_error(
ident.span,
- ResolutionError::BindingShadowsSomethingUnacceptable(
- pat_src.descr(),
- ident.name,
- binding.expect("no binding for a ctor or static"),
- ),
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: pat_src.descr(),
+ name: ident.name,
+ participle: if binding.is_import() { "imported" } else { "defined" },
+ article: binding.res().article(),
+ shadowed_binding_descr: binding.res().descr(),
+ shadowed_binding_span: binding.span,
+ },
+ );
+ None
+ }
+ Res::Def(DefKind::ConstParam, def_id) => {
+ // Same as for DefKind::Const above, but here, `binding` is `None`, so we
+ // have to construct the error differently
+ self.report_error(
+ ident.span,
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: pat_src.descr(),
+ name: ident.name,
+ participle: "defined",
+ article: res.article(),
+ shadowed_binding_descr: res.descr(),
+ shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
+ }
);
None
}
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
let traits = self.traits_in_scope(item_name, ns);
- self.r.trait_map.insert(id, traits);
+ self.r.trait_map.as_mut().unwrap().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.insert(expr.id, traits);
+ self.r.trait_map.as_mut().unwrap().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.insert(expr.id, traits);
+ self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
}
_ => {
// Nothing to do.
#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
/* current */ &'static str,
),
/// Error E0530: `X` bindings cannot shadow `Y`s.
- BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
+ BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: &'static str,
+ name: Symbol,
+ participle: &'static str,
+ article: &'static str,
+ shadowed_binding_descr: &'static str,
+ shadowed_binding_span: Span,
+ },
/// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
- ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
+ ForwardDeclaredGenericParam,
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol),
/// generic parameters must not be used inside const evaluations.
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
export_map: ExportMap<LocalDefId>,
- trait_map: NodeMap<Vec<TraitCandidate>>,
+ trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
/// A map from nodes to anonymous modules.
/// Anonymous modules are pseudo-modules that are implicitly created around items
self.next_node_id()
}
- fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
- &self.trait_map
+ fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
+ std::mem::replace(&mut self.trait_map, None).unwrap()
}
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
let mut module_map = FxHashMap::default();
module_map.insert(root_local_def_id, graph_root);
- let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
+ let definitions = Definitions::new(session.local_stable_crate_id());
let root = definitions.get_root_def();
let mut visibilities = FxHashMap::default();
label_res_map: Default::default(),
extern_crate_map: Default::default(),
export_map: FxHashMap::default(),
- trait_map: Default::default(),
+ trait_map: Some(NodeMap::default()),
underscore_disambiguator: 0,
empty_module,
module_map,
let res_error = if rib_ident.name == kw::SelfUpper {
ResolutionError::SelfInTyParamDefault
} else {
- ResolutionError::ForwardDeclaredTyParam
+ ResolutionError::ForwardDeclaredGenericParam
};
self.report_error(span, res_error);
}
let data = CratePreludeData {
crate_id: GlobalCrateId {
name: name.into(),
- disambiguator: self
- .tcx
- .sess
- .local_crate_disambiguator()
- .to_fingerprint()
- .as_value(),
+ disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0),
},
crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
external_crates: self.save_ctxt.get_external_crates(),
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
mod dump_visitor;
num: n.as_u32(),
id: GlobalCrateId {
name: self.tcx.crate_name(n).to_string(),
- disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(),
+ disambiguator: (
+ self.tcx.def_path_hash(n.as_def_id()).stable_crate_id().to_u64(),
+ 0,
+ ),
},
});
}
// FIXME: Should save-analysis beautify doc strings itself or leave it to users?
result.push_str(&beautify_doc_string(val).as_str());
result.push('\n');
- } else if self.tcx.sess.check_name(attr, sym::doc) {
- if let Some(meta_list) = attr.meta_item_list() {
- meta_list
- .into_iter()
- .filter(|it| it.has_name(sym::include))
- .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
- .flat_map(|it| it)
- .filter(|meta| meta.has_name(sym::contents))
- .filter_map(|meta| meta.value_str())
- .for_each(|val| {
- result.push_str(&val.as_str());
- result.push('\n');
- });
- }
}
}
#![feature(nll)]
#![feature(associated_type_bounds)]
#![feature(min_specialization)]
-#![feature(vec_spare_capacity)]
#![feature(core_intrinsics)]
-#![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_slice)]
#![feature(new_uninit)]
#![cfg_attr(test, feature(test))]
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
lint_opts: Vec::new(),
+ force_warns: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: OutputTypes(BTreeMap::new()),
level",
"LEVEL",
),
+ opt::multi_s(
+ "",
+ "force-warns",
+ "Specifiy lints that should warn even if \
+ they are allowed somewhere else",
+ "LINT",
+ ),
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag_s("V", "version", "Print version info and exit"),
opt::flag_s("v", "verbose", "Use verbose output"),
pub fn get_cmd_lint_options(
matches: &getopts::Matches,
error_format: ErrorOutputType,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
+ debugging_opts: &DebuggingOptions,
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
lint::Level::from_str(&cap)
.unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
});
- (lint_opts, describe_lints, lint_cap)
+
+ if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to enable \
+ the flag `--force-warns=lints`",
+ );
+ }
+
+ let force_warns = matches.opt_strs("force-warns");
+
+ (lint_opts, describe_lints, lint_cap, force_warns)
}
/// Parses the `--color` flag.
prints
}
-fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
+pub fn parse_target_triple(
+ matches: &getopts::Matches,
+ error_format: ErrorOutputType,
+) -> TargetTriple {
match matches.opt_str("target") {
Some(target) if target.ends_with(".json") => {
let path = Path::new(&target);
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e[..]));
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, force_warns) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
+
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
if !debugging_opts.unstable_options && json_unused_externs {
optimize: opt_level,
debuginfo,
lint_opts,
+ force_warns,
lint_cap,
describe_lints,
output_types,
)+};
}
- macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
- ($($t:ty),+ $(,)?) => {$(
- impl DepTrackingHash for Vec<$t> {
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
- let mut elems: Vec<&$t> = self.iter().collect();
- elems.sort();
- Hash::hash(&elems.len(), hasher);
- for (index, elem) in elems.iter().enumerate() {
- Hash::hash(&index, hasher);
- DepTrackingHash::hash(*elem, hasher, error_format);
- }
+ impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
+ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ match self {
+ Some(x) => {
+ Hash::hash(&1, hasher);
+ DepTrackingHash::hash(x, hasher, error_format);
}
+ None => Hash::hash(&0, hasher),
}
- )+};
+ }
}
impl_dep_tracking_hash_via_hash!(
bool,
usize,
+ NonZeroUsize,
u64,
String,
PathBuf,
lint::Level,
- Option<bool>,
- Option<u32>,
- Option<usize>,
- Option<NonZeroUsize>,
- Option<String>,
- Option<(String, u64)>,
- Option<Vec<String>>,
- Option<MergeFunctions>,
- Option<RelocModel>,
- Option<CodeModel>,
- Option<TlsModel>,
- Option<WasiExecModel>,
- Option<PanicStrategy>,
- Option<RelroLevel>,
- Option<InstrumentCoverage>,
- Option<lint::Level>,
- Option<PathBuf>,
+ WasiExecModel,
+ u32,
+ RelocModel,
+ CodeModel,
+ TlsModel,
+ InstrumentCoverage,
CrateType,
MergeFunctions,
PanicStrategy,
TargetTriple,
Edition,
LinkerPluginLto,
- Option<SplitDebuginfo>,
+ SplitDebuginfo,
SwitchWithOptPath,
- Option<SymbolManglingVersion>,
- Option<SourceFileHashAlgorithm>,
+ SymbolManglingVersion,
+ SourceFileHashAlgorithm,
TrimmedDefPaths,
);
- impl_dep_tracking_hash_for_sortable_vec_of!(
- String,
- PathBuf,
- (PathBuf, PathBuf),
- CrateType,
- NativeLib,
- (String, lint::Level),
- (String, u64)
- );
-
impl<T1, T2> DepTrackingHash for (T1, T2)
where
T1: DepTrackingHash,
}
}
+ impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
+ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ Hash::hash(&self.len(), hasher);
+ for (index, elem) in self.iter().enumerate() {
+ Hash::hash(&index, hasher);
+ DepTrackingHash::hash(elem, hasher, error_format);
+ }
+ }
+ }
+
// This is a stable hash because BTreeMap is a sorted container
crate fn stable_hash(
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
#![feature(crate_visibility_modifier)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
#[macro_use]
debuginfo: DebugInfo [TRACKED],
lint_opts: Vec<(String, lint::Level)> [TRACKED],
lint_cap: Option<lint::Level> [TRACKED],
+ force_warns: Vec<String> [TRACKED],
describe_lints: bool [UNTRACKED],
output_types: OutputTypes [TRACKED],
search_paths: Vec<SearchPath> [UNTRACKED],
pub const parse_target_feature: &str = parse_string;
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
pub const parse_split_debuginfo: &str =
- "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+ "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
}
mod parse {
crate_name: &str,
outputs: &OutputFilenames,
) -> PathBuf {
+ // If the command-line specified the path, use that directly.
+ if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
+ return out_filename.clone();
+ }
+
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
let out_filename = outputs
use rustc_errors::registry::Registry;
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_lint_defs::FutureBreakage;
-pub use rustc_span::crate_disambiguator::CrateDisambiguator;
+pub use rustc_span::def_id::StableCrateId;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{edition::Edition, RealFileName};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
/// in order to avoid redundantly verbose output (Issue #24690, #44953).
pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
crate_types: OnceCell<Vec<CrateType>>,
- /// The `crate_disambiguator` is constructed out of all the `-C metadata`
- /// arguments passed to the compiler. Its value together with the crate-name
- /// forms a unique global identifier for the crate. It is used to allow
- /// multiple crates with the same name to coexist. See the
+ /// The `stable_crate_id` is constructed out of the crate name and all the
+ /// `-C metadata` arguments passed to the compiler. Its value forms a unique
+ /// global identifier for the crate. It is used to allow multiple crates
+ /// with the same name to coexist. See the
/// `rustc_codegen_llvm::back::symbol_names` module for more information.
- pub crate_disambiguator: OnceCell<CrateDisambiguator>,
+ pub stable_crate_id: OnceCell<StableCrateId>,
features: OnceCell<rustc_feature::Features>,
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage);
}
- pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
- self.crate_disambiguator.get().copied().unwrap()
+ pub fn local_stable_crate_id(&self) -> StableCrateId {
+ self.stable_crate_id.get().copied().unwrap()
}
pub fn crate_types(&self) -> &[CrateType] {
pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) {
err.into_diagnostic(self).emit()
}
+ #[inline]
pub fn err_count(&self) -> usize {
self.diagnostic().err_count()
}
self.diagnostic().struct_note_without_error(msg)
}
+ #[inline]
pub fn diagnostic(&self) -> &rustc_errors::Handler {
&self.parse_sess.span_diagnostic
}
/// Returns the symbol name for the registrar function,
/// given the crate `Svh` and the function `DefIndex`.
- pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
- format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex())
+ pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String {
+ format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64())
}
- pub fn generate_proc_macro_decls_symbol(&self, disambiguator: CrateDisambiguator) -> String {
- format!("__rustc_proc_macro_decls_{}__", disambiguator.to_fingerprint().to_hex())
+ pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
+ format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
}
pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
working_dir,
one_time_diagnostics: Default::default(),
crate_types: OnceCell::new(),
- crate_disambiguator: OnceCell::new(),
+ stable_crate_id: OnceCell::new(),
features: OnceCell::new(),
lint_store: OnceCell::new(),
recursion_limit: OnceCell::new(),
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
sess.err(&format!("`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", first, second));
}
+
+ // Cannot enable crt-static with sanitizers on Linux
+ if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
+ sess.err(
+ "Sanitizer is incompatible with statically linked libc, \
+ disable it using `-C target-feature=-crt-static`",
+ );
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
+++ /dev/null
-// This is here because `rustc_session` wants to refer to it,
-// and so does `rustc_hir`, but `rustc_hir` shouldn't refer to `rustc_session`.
-
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::{base_n, impl_stable_hash_via_hash};
-
-use std::fmt;
-
-/// Hash value constructed out of all the `-C metadata` arguments passed to the
-/// compiler. Together with the crate-name forms a unique global identifier for
-/// the crate.
-#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)]
-pub struct CrateDisambiguator(Fingerprint);
-
-impl CrateDisambiguator {
- pub fn to_fingerprint(self) -> Fingerprint {
- self.0
- }
-}
-
-impl fmt::Display for CrateDisambiguator {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- let (a, b) = self.0.as_value();
- let as_u128 = a as u128 | ((b as u128) << 64);
- f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
- }
-}
-
-impl From<Fingerprint> for CrateDisambiguator {
- fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
- CrateDisambiguator(fingerprint)
- }
-}
-
-impl_stable_hash_via_hash!(CrateDisambiguator);
-use crate::crate_disambiguator::CrateDisambiguator;
use crate::HashStableContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use std::fmt;
rustc_index::newtype_index! {
- pub struct CrateId {
+ pub struct CrateNum {
ENCODABLE = custom
+ DEBUG_FORMAT = "crate{}"
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum CrateNum {
- /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from
- /// the incr. comp. cache.
- ReservedForIncrCompCache,
- Index(CrateId),
-}
-
/// Item definitions in the currently-compiled crate would have the `CrateNum`
/// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32(0));
-
-impl Idx for CrateNum {
- #[inline]
- fn new(value: usize) -> Self {
- CrateNum::Index(Idx::new(value))
- }
-
- #[inline]
- fn index(self) -> usize {
- match self {
- CrateNum::Index(idx) => Idx::index(idx),
- _ => panic!("Tried to get crate index of {:?}", self),
- }
- }
-}
+pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
impl CrateNum {
+ #[inline]
pub fn new(x: usize) -> CrateNum {
CrateNum::from_usize(x)
}
- pub fn from_usize(x: usize) -> CrateNum {
- CrateNum::Index(CrateId::from_usize(x))
- }
-
- pub fn from_u32(x: u32) -> CrateNum {
- CrateNum::Index(CrateId::from_u32(x))
- }
-
- pub fn as_usize(self) -> usize {
- match self {
- CrateNum::Index(id) => id.as_usize(),
- _ => panic!("tried to get index of non-standard crate {:?}", self),
- }
- }
-
- pub fn as_u32(self) -> u32 {
- match self {
- CrateNum::Index(id) => id.as_u32(),
- _ => panic!("tried to get index of non-standard crate {:?}", self),
- }
- }
-
+ #[inline]
pub fn as_def_id(&self) -> DefId {
DefId { krate: *self, index: CRATE_DEF_INDEX }
}
impl fmt::Display for CrateNum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
- CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
- }
+ fmt::Display::fmt(&self.private, f)
}
}
}
}
-impl ::std::fmt::Debug for CrateNum {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
- match self {
- CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
- CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
- }
- }
-}
-
/// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
/// stable across crate and compilation session boundaries. It consists of two
/// separate 64-bit hashes. The first uniquely identifies the crate this
}
}
-/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It
-/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across
-/// compilation sessions.
+/// A [StableCrateId] is a 64 bit hash of the crate name combined with all
+/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to
+/// [DefId]. It is stable across compilation sessions.
///
/// Since the ID is a hash value there is a (very small) chance that two crates
/// end up with the same [StableCrateId]. The compiler will check for such
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)]
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
pub struct StableCrateId(u64);
impl StableCrateId {
+ pub fn to_u64(self) -> u64 {
+ self.0
+ }
+
/// Computes the stable ID for a crate with the given name and
- /// disambiguator.
- pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId {
+ /// `-Cmetadata` arguments.
+ pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
use std::hash::Hash;
+ use std::hash::Hasher;
let mut hasher = StableHasher::new();
crate_name.hash(&mut hasher);
- crate_disambiguator.hash(&mut hasher);
+
+ // We don't want the stable crate id to dependent on the order
+ // -C metadata arguments, so sort them:
+ metadata.sort();
+ // Every distinct -C metadata value is only incorporated once:
+ metadata.dedup();
+
+ hasher.write(b"metadata");
+ for s in &metadata {
+ // Also incorporate the length of a metadata string, so that we generate
+ // different values for `-Cmetadata=ab -Cmetadata=c` and
+ // `-Cmetadata=a -Cmetadata=bc`
+ hasher.write_usize(s.len());
+ hasher.write(s.as_bytes());
+ }
+
+ // Also incorporate crate type, so that we don't get symbol conflicts when
+ // linking against a library of the same name, if this is an executable.
+ hasher.write(if is_exe { b"exe" } else { b"lib" });
+
StableCrateId(hasher.finish())
}
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
-pub mod crate_disambiguator;
-
pub mod symbol;
pub use symbol::{sym, Symbol};
substs.hash_stable(&mut hcx, &mut hasher);
if let Some(instantiating_crate) = instantiating_crate {
- tcx.original_crate_name(instantiating_crate)
- .as_str()
+ tcx.def_path_hash(instantiating_crate.as_def_id())
+ .stable_crate_id()
.hash_stable(&mut hcx, &mut hasher);
- tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher);
}
// We want to avoid accidental collision between different types of instances.
}
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+ self.write_str(&self.tcx.crate_name(cnum).as_str())?;
Ok(self)
}
fn path_qualified(
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(never_type)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(in_band_lifetimes)]
#![recursion_limit = "256"]
// FIXME(eddyb) Precompute a custom symbol name based on attributes.
let is_foreign = if let Some(def_id) = def_id.as_local() {
if tcx.plugin_registrar_fn(()) == Some(def_id) {
- let disambiguator = tcx.sess.local_crate_disambiguator();
- return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
+ let stable_crate_id = tcx.sess.local_stable_crate_id();
+ return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id);
}
if tcx.proc_macro_decls_static(()) == Some(def_id) {
- let disambiguator = tcx.sess.local_crate_disambiguator();
- return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
+ let stable_crate_id = tcx.sess.local_stable_crate_id();
+ return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
matches!(tcx.hir().get(hir_id), Node::ForeignItem(_))
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.push("C");
- let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
- self.push_disambiguator(fingerprint.to_smaller_hash());
- let name = self.tcx.original_crate_name(cnum).as_str();
+ let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+ self.push_disambiguator(stable_crate_id.to_u64());
+ let name = self.tcx.crate_name(cnum).as_str();
self.push_ident(&name);
Ok(self)
}
}
impl HasDataLayout for TargetDataLayout {
+ #[inline]
fn data_layout(&self) -> &TargetDataLayout {
self
}
impl Abi {
/// Returns `true` if the layout corresponds to an unsized type.
+ #[inline]
pub fn is_unsized(&self) -> bool {
match *self {
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
}
/// Returns `true` if this is an uninhabited type
+ #[inline]
pub fn is_uninhabited(&self) -> bool {
matches!(*self, Abi::Uninhabited)
}
/// Returns `true` is this is a scalar type
+ #[inline]
pub fn is_scalar(&self) -> bool {
matches!(*self, Abi::Scalar(_))
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
-#![feature(const_panic)]
#![feature(nll)]
#![feature(never_type)]
#![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)]
+#![feature(min_specialization)]
use std::path::{Path, PathBuf};
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a12".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
families: vec!["unix".to_string()],
is_like_osx: true,
dwarf_version: Some(2),
+ eliminate_frame_pointer: false,
has_rpath: true,
dll_suffix: ".dylib".to_string(),
archive_format: "darwin".to_string(),
executables: true,
link_env_remove: link_env_remove(arch),
has_elf_tls: false,
- eliminate_frame_pointer: false,
..super::apple_base::opts(os)
}
}
}
impl HasTargetSpec for Target {
+ #[inline]
fn target_spec(&self) -> &Target {
self
}
// dependency on this specific gcc.
asm_args: vec!["-mcpu=msp430".to_string()],
linker: Some("msp430-elf-gcc".to_string()),
+ linker_is_gnu: false,
// There are no atomic CAS instructions available in the MSP430
// instruction set, and the LLVM backend doesn't currently support
linker: Some("rust-lld".to_owned()),
lld_flavor: LldFlavor::Wasm,
- // No need for indirection here, simd types can always be passed by
- // value as the whole module either has simd or not, which is different
- // from x86 (for example) where programs can have functions that don't
- // enable simd features.
- simd_types_indirect: false,
-
pre_link_args,
crt_objects_fallback: Some(CrtObjectsFallback::Wasm),
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::DiagnosticMessageId;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span;
#[derive(Copy, Clone, Debug)]
.span_label(span, "deref recursion limit reached")
.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
- suggested_limit, tcx.crate_name,
+ suggested_limit,
+ tcx.crate_name(LOCAL_CRATE),
))
.emit();
}
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] // For rustdoc
first_own_region_index: usize,
);
- /*private*/
- fn member_constraint_feature_gate(
- &self,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
- conflict1: ty::Region<'tcx>,
- conflict2: ty::Region<'tcx>,
- ) -> bool;
-
fn infer_opaque_definition_from_instantiation(
&self,
def_id: DefId,
// ['a, 'b, 'c]`, where `'a..'c` are the
// regions that appear in the impl trait.
- // For now, enforce a feature gate outside of async functions.
- self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region);
-
return self.generate_member_constraint(
concrete_ty,
opaque_defn,
});
}
- /// Member constraints are presently feature-gated except for
- /// async-await. We expect to lift this once we've had a bit more
- /// time.
- fn member_constraint_feature_gate(
- &self,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
- conflict1: ty::Region<'tcx>,
- conflict2: ty::Region<'tcx>,
- ) -> bool {
- // If we have `#![feature(member_constraints)]`, no problems.
- if self.tcx.features().member_constraints {
- return false;
- }
-
- let span = self.tcx.def_span(opaque_type_def_id);
-
- // Without a feature-gate, we only generate member-constraints for async-await.
- let context_name = match opaque_defn.origin {
- // No feature-gate required for `async fn`.
- hir::OpaqueTyOrigin::AsyncFn => return false,
-
- // Otherwise, generate the label we'll use in the error message.
- hir::OpaqueTyOrigin::Binding
- | hir::OpaqueTyOrigin::FnReturn
- | hir::OpaqueTyOrigin::TyAlias
- | hir::OpaqueTyOrigin::Misc => "impl Trait",
- };
- let msg = format!("ambiguous lifetime bound in `{}`", context_name);
- let mut err = self.tcx.sess.struct_span_err(span, &msg);
-
- let conflict1_name = conflict1.to_string();
- let conflict2_name = conflict2.to_string();
- let label_owned;
- let label = match (&*conflict1_name, &*conflict2_name) {
- ("'_", "'_") => "the elided lifetimes here do not outlive one another",
- _ => {
- label_owned = format!(
- "neither `{}` nor `{}` outlives the other",
- conflict1_name, conflict2_name,
- );
- &label_owned
- }
- };
- err.span_label(span, label);
-
- if self.tcx.sess.is_nightly_build() {
- err.help("add #![feature(member_constraints)] to the crate attributes to enable");
- }
-
- err.emit();
- true
- }
-
/// 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
hir::intravisit::NestedVisitorMap::None
}
+ fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+ // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+ }
+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
};
let name = param.name;
flags.push((name, Some(value)));
+
+ if let GenericParamDefKind::Type { .. } = param.kind {
+ let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+ if let Some(def) = param_ty.ty_adt_def() {
+ // We also want to be able to select the parameter's
+ // original signature with no type arguments resolved
+ flags.push((name, Some(self.tcx.type_of(def.did).to_string())));
+ }
+ }
}
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
let suggested_limit = current_limit * 2;
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
- suggested_limit, self.tcx.crate_name,
+ suggested_limit,
+ self.tcx.crate_name(LOCAL_CRATE),
));
}
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- ProcessResult::Unchanged
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ ProcessResult::Unchanged
+ } else {
+ // Two different constants using generic parameters ~> error.
+ let expected_found = ExpectedFound::new(true, c1, c2);
+ ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+ expected_found,
+ TypeError::ConstMismatch(expected_found),
+ ))
+ }
}
}
}
ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
+ if self.tcx().features().const_evaluatable_checked {
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.val, c2.val)
+ {
+ if self
+ .tcx()
+ .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
+ {
+ return Ok(EvaluatedToOk);
+ }
+ }
+ }
+
let evaluate = |c: &'tcx ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
self.infcx
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- Ok(EvaluatedToAmbig)
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ Ok(EvaluatedToAmbig)
+ } else {
+ // Two different constants using generic parameters ~> error.
+ Ok(EvaluatedToErr)
+ }
}
}
}
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+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,
};
-use rustc_session::CrateDisambiguator;
-use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_trait_selection::traits;
tcx.param_env(def_id).with_reveal_all_normalized(tcx)
}
-fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
- assert_eq!(crate_num, LOCAL_CRATE);
- tcx.sess.local_crate_disambiguator()
-}
-
-fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
- assert_eq!(crate_num, LOCAL_CRATE);
- tcx.crate_name
-}
-
fn instance_def_size_estimate<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceDef<'tcx>,
param_env,
param_env_reveal_all_normalized,
trait_of_item,
- crate_disambiguator,
- original_crate_name,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
+#![feature(min_specialization)]
+
#[macro_use]
extern crate bitflags;
#[macro_use]
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
+use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
fcx.ty_to_string(self.cast_ty)
);
let mut sugg = None;
+ let mut sugg_mutref = false;
if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
- if fcx
- .try_coerce(
- self.expr,
- fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
- self.cast_ty,
- AllowTwoPhase::No,
- )
- .is_ok()
+ if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
+ if fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(
+ &ty::RegionKind::ReErased,
+ TypeAndMut { ty: expr_ty, mutbl },
+ ),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg = Some(format!("&{}*", mutbl.prefix_str()));
+ }
+ } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
+ if expr_mutbl == Mutability::Not
+ && mutbl == Mutability::Mut
+ && fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(
+ expr_reg,
+ TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
+ ),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg_mutref = true;
+ }
+ }
+
+ if !sugg_mutref
+ && sugg == None
+ && fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
{
sugg = Some(format!("&{}", mutbl.prefix_str()));
}
sugg = Some(format!("&{}", mutbl.prefix_str()));
}
}
- if let Some(sugg) = sugg {
+ if sugg_mutref {
+ err.span_label(self.span, "invalid cast");
+ err.span_note(self.expr.span, "this reference is immutable");
+ err.span_note(self.cast_span, "trying to cast to a mutable reference type");
+ } else if let Some(sugg) = sugg {
err.span_label(self.span, "invalid cast");
err.span_suggestion_verbose(
self.expr.span.shrink_to_lo(),
- "borrow the value for the cast to be valid",
+ "consider borrowing the value",
sugg,
Applicability::MachineApplicable,
);
}
}
+ // Check that we use types valid for use in the lanes of a SIMD "vector register"
+ // These are scalar types which directly match a "machine" type
+ // Yes: Integers, floats, "thin" pointers
+ // No: char, "fat" pointers, compound types
match e.kind() {
- ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
- _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
- ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
+ ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+ ty::Array(t, _clen)
+ if matches!(
+ t.kind(),
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
+ ) =>
+ { /* struct([f32; 4]) is ok */ }
_ => {
struct_span_err!(
tcx.sess,
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
+use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
use super::method::probe;
use std::fmt;
+use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn emit_coerce_suggestions(
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(Span, &'static str, String, Applicability)> {
- let sm = self.sess().source_map();
+ let sess = self.sess();
let sp = expr.span;
- if sm.is_imported(sp) {
- // Ignore if span is from within a macro #41858, #58298. We previously used the macro
- // call span, but that breaks down when the type error comes from multiple calls down.
+
+ // If the span is from an external macro, there's no suggestion we can make.
+ if in_external_macro(sess, sp) {
return None;
}
+ let sm = sess.source_map();
+
let replace_prefix = |s: &str, old: &str, new: &str| {
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
};
let is_struct_pat_shorthand_field =
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
- // If the span is from a macro, then it's hard to extract the text
- // and make a good suggestion, so don't bother.
- let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none();
-
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
let expr = expr.peel_drop_temps();
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
_,
&ty::Ref(_, checked, _),
- ) if {
- self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro
- } =>
- {
+ ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
- if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = src.strip_prefix('&') {
+ // Go through the spans from which this span was expanded,
+ // and find the one that's pointing inside `sp`.
+ //
+ // E.g. for `&format!("")`, where we want the span to the
+ // `format!()` invocation instead of its expansion.
+ if let Some(call_span) =
+ iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
+ {
+ if let Ok(code) = sm.span_to_snippet(call_span) {
return Some((
sp,
"consider removing the borrow",
- src.to_string(),
+ code,
Applicability::MachineApplicable,
));
}
}
return None;
}
- if let Ok(code) = sm.span_to_snippet(expr.span) {
- return Some((
- sp,
- "consider removing the borrow",
- code,
- Applicability::MachineApplicable,
- ));
+ if sp.contains(expr.span) {
+ if let Ok(code) = sm.span_to_snippet(expr.span) {
+ return Some((
+ sp,
+ "consider removing the borrow",
+ code,
+ Applicability::MachineApplicable,
+ ));
+ }
}
}
(
}
}
}
- _ if sp == expr.span && !is_macro => {
+ _ if sp == expr.span => {
if let Some(steps) = self.deref_steps(checked_ty, expected) {
let expr = expr.peel_blocks();
return None;
} else {
span = item_name.span;
+
+ // Don't show generic arguments when the method can't be found in any implementation (#81576).
+ let mut ty_str_reported = ty_str.clone();
+ if let ty::Adt(_, ref generics) = actual.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, actual);
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(ref adt_deref, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_deref.did)
+ .iter()
+ .filter_map(|def_id| {
+ self.associated_item(
+ *def_id,
+ item_name,
+ Namespace::ValueNS,
+ )
+ })
+ .count()
+ >= 1
+ } else {
+ false
+ }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found
+ && !has_deref
+ && unsatisfied_predicates.is_empty()
+ {
+ if let Some((path_string, _)) = ty_str.split_once('<') {
+ ty_str_reported = path_string.to_string();
+ }
+ }
+ }
+ }
+
let mut err = struct_span_err!(
tcx.sess,
span,
item_kind,
item_name,
actual.prefix_string(self.tcx),
- ty_str,
+ ty_str_reported,
);
if let Mode::MethodCall = mode {
if let SelfSource::MethodCall(call) = source {
let mut label_span_not_found = || {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
+ let mut inherent_impls_candidate = self
+ .tcx
+ .inherent_impls(adt.did)
+ .iter()
+ .copied()
+ .filter(|def_id| {
+ if let Some(assoc) =
+ self.associated_item(*def_id, item_name, Namespace::ValueNS)
+ {
+ // Check for both mode is the same so we avoid suggesting
+ // incorrect associated item.
+ match (mode, assoc.fn_has_self_parameter, source) {
+ (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+ // We check that the suggest type is actually
+ // different from the received one
+ // So we avoid suggestion method with Box<Self>
+ // for instance
+ self.tcx.at(span).type_of(*def_id) != actual
+ && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ }
+ (Mode::Path, false, _) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ if inherent_impls_candidate.len() > 0 {
+ inherent_impls_candidate.sort();
+ inherent_impls_candidate.dedup();
+
+ // number of type to shows at most.
+ let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+ let type_candidates = inherent_impls_candidate
+ .iter()
+ .take(limit)
+ .map(|impl_item| {
+ format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+ })
+ .collect::<Vec<_>>()
+ .join("\n");
+ let additional_types = if inherent_impls_candidate.len() > limit {
+ format!(
+ "\nand {} more types",
+ inherent_impls_candidate.len() - limit
+ )
+ } else {
+ "".to_string()
+ };
+ err.note(&format!(
+ "the {item_kind} was found for\n{}{}",
+ type_candidates, additional_types
+ ));
+ }
+ }
} else {
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
}
// Clear previous flag; after a pointer indirection it does not apply any more.
inside_union = false;
}
- if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+ if source.is_union() {
inside_union = true;
}
// Fix up the autoderefs. Autorefs can only occur immediately preceding
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
if let PlaceBase::Upvar(_) = place.base {
+ // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+ // such as deref of a raw pointer.
+ let place = restrict_capture_precision(place);
+ let place =
+ restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
self.fake_reads.push((place, cause, diag_expr_id));
}
}
}
} else if tcx.sess.check_name(attr, sym::target_feature) {
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
- if !tcx.features().target_feature_11 {
+ if tcx.sess.target.is_like_wasm {
+ // The `#[target_feature]` attribute is allowed on
+ // WebAssembly targets on all functions, including safe
+ // ones. Other targets require that `#[target_feature]` is
+ // only applied to unsafe funtions (pending the
+ // `target_feature_11` feature) because on most targets
+ // execution of instructions that are not supported is
+ // considered undefined behavior. For WebAssembly which is a
+ // 100% safe target at execution time it's not possible to
+ // execute undefined instructions, and even if a future
+ // feature was added in some form for this it would be a
+ // deterministic trap. There is no undefined behavior when
+ // executing WebAssembly so `#[target_feature]` is allowed
+ // on safe functions (but again, only for WebAssembly)
+ } else if !tcx.features().target_feature_11 {
let mut err = feature_err(
&tcx.sess.parse_sess,
sym::target_feature_11,
#![feature(is_sorted)]
#![feature(iter_zip)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(try_blocks)]
#![feature(never_type)]
#![feature(slice_partition_dedup)]
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
- let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
- let span_lo_redundant_lt_args =
- self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
- let span_hi_redundant_lt_args = self.gen_args.args
- [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
- .span()
- .shrink_to_hi();
- let eat_comma =
- idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();
-
- let span_redundant_lt_args = if eat_comma {
- let span_hi = self.gen_args.args
- [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
- .span()
- .shrink_to_hi();
- span_lo_redundant_lt_args.to(span_hi)
- } else {
- span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
- };
+ let mut lt_arg_spans = Vec::new();
+ let mut found_redundant = false;
+ for arg in self.gen_args.args {
+ if let hir::GenericArg::Lifetime(_) = arg {
+ lt_arg_spans.push(arg.span());
+ if lt_arg_spans.len() > self.num_expected_lifetime_args() {
+ found_redundant = true;
+ }
+ } else if found_redundant {
+ // Argument which is redundant and separated like this `'c`
+ // is not included to avoid including `Bar` in span.
+ // ```
+ // type Foo<'a, T> = &'a T;
+ // let _: Foo<'a, 'b, Bar, 'c>;
+ // ```
+ break;
+ }
+ }
+
+ let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
+ let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
+
+ let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
+ let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
let msg_lifetimes = format!(
"remove {} {} argument{}",
- if num_redundant_args == 1 { "this" } else { "these" },
+ if num_redundant_lt_args == 1 { "this" } else { "these" },
"lifetime",
pluralize!(num_redundant_lt_args),
);
};
let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
- let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
- + num_redundant_lt_args
- + self.num_expected_type_or_const_args();
+ let mut gen_arg_spans = Vec::new();
+ let mut found_redundant = false;
+ for arg in self.gen_args.args {
+ match arg {
+ hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+ gen_arg_spans.push(arg.span());
+ if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
+ found_redundant = true;
+ }
+ }
+ _ if found_redundant => break,
+ _ => {}
+ }
+ }
let span_lo_redundant_type_or_const_args =
- self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();
-
- let span_hi_redundant_type_or_const_args = self.gen_args.args
- [idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
- .span()
- .shrink_to_hi();
+ gen_arg_spans[self.num_expected_type_or_const_args()];
+ let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
let span_redundant_type_or_const_args =
span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
-
debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
+ let num_redundant_gen_args =
+ gen_arg_spans.len() - self.num_expected_type_or_const_args();
let msg_types_or_consts = format!(
"remove {} {} argument{}",
- if num_redundant_args == 1 { "this" } else { "these" },
+ if num_redundant_gen_args == 1 { "this" } else { "these" },
"generic",
pluralize!(num_redundant_type_or_const_args),
);
# Use LLVM libunwind as the implementation for Rust's unwinder.
# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
+# This option only applies for Linux and Fuchsia targets.
+# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
+# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
+# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
+# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both
+# means static link to the in-tree build of llvm libunwind, and 'system' means
+# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
+# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
#llvm-libunwind = 'no'
# Enable Windows Control Flow Guard checks in the standard library.
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Iter").field(&self.len).finish()
+ f.debug_tuple("Iter")
+ .field(&*mem::ManuallyDrop::new(LinkedList {
+ head: self.head,
+ tail: self.tail,
+ len: self.len,
+ marker: PhantomData,
+ }))
+ .field(&self.len)
+ .finish()
}
}
/// documentation for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
- // We do *not* exclusively own the entire list here, references to node's `element`
- // have been handed out by the iterator! So be careful when using this; the methods
- // called must be aware that there can be aliasing pointers to `element`.
- list: &'a mut LinkedList<T>,
head: Option<NonNull<Node<T>>>,
tail: Option<NonNull<Node<T>>>,
len: usize,
+ marker: PhantomData<&'a mut Node<T>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("IterMut").field(&self.list).field(&self.len).finish()
+ f.debug_tuple("IterMut")
+ .field(&*mem::ManuallyDrop::new(LinkedList {
+ head: self.head,
+ tail: self.tail,
+ len: self.len,
+ marker: PhantomData,
+ }))
+ .field(&self.len)
+ .finish()
}
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
- IterMut { head: self.head, tail: self.tail, len: self.len, list: self }
+ IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }
}
/// Provides a cursor at the front element.
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// sort order:
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// deque.insert(idx, num);
/// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
#[inline]
pub fn binary_search(&self, x: &T) -> Result<usize, usize>
where
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// let r = deque.binary_search_by(|x| x.cmp(&1));
/// assert!(matches!(r, Ok(1..=4)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
where
F: FnMut(&'a T) -> Ordering,
/// fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
/// let r = deque.binary_search_by_key(&1, |&(a, b)| b);
/// assert!(matches!(r, Ok(1..=4)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
#[inline]
pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
where
/// # Examples
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
/// assert!(deque.iter().take(i).all(|&x| x < 5));
/// assert!(deque.iter().skip(i).all(|&x| !(x < 5)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
pub fn partition_point<P>(&self, mut pred: P) -> usize
where
P: FnMut(&T) -> bool,
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
-#![cfg_attr(bootstrap, feature(const_fn))]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
#![feature(cow_is_borrowed)]
#![feature(const_cow_is_borrowed)]
#![feature(destructuring_assignment)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(auto_traits)]
#![feature(option_result_unwrap_unchecked)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
#![feature(decl_macro)]
+#![feature(bindings_after_at)]
// Allow testing this library
#[cfg(test)]
B: ToOwned + ?Sized,
Rc<B>: From<&'a B> + From<B::Owned>,
{
+ /// Create a reference-counted pointer from
+ /// a clone-on-write pointer by copying its content.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::rc::Rc;
+ /// # use std::borrow::Cow;
+ /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+ /// let shared: Rc<str> = Rc::from(cow);
+ /// assert_eq!("eggplant", &shared[..]);
+ /// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Rc<B> {
match cow {
}
#[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
self.vec.extend_from_slice(string.as_bytes())
}
+ /// Copies elements from `src` range to the end of the string.
+ ///
+ /// ## Panics
+ ///
+ /// Panics if the starting point or end point do not lie on a [`char`]
+ /// boundary, or if they're out of bounds.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// #![feature(string_extend_from_within)]
+ /// let mut string = String::from("abcde");
+ ///
+ /// string.extend_from_within(2..);
+ /// assert_eq!(string, "abcdecde");
+ ///
+ /// string.extend_from_within(..2);
+ /// assert_eq!(string, "abcdecdeab");
+ ///
+ /// string.extend_from_within(4..8);
+ /// assert_eq!(string, "abcdecdeabecde");
+ /// ```
+ #[cfg(not(no_global_oom_handling))]
+ #[unstable(feature = "string_extend_from_within", issue = "none")]
+ pub fn extend_from_within<R>(&mut self, src: R)
+ where
+ R: RangeBounds<usize>,
+ {
+ let src @ Range { start, end } = slice::range(src, ..self.len());
+
+ assert!(self.is_char_boundary(start));
+ assert!(self.is_char_boundary(end));
+
+ self.vec.extend_from_within(src);
+ }
+
/// Returns this `String`'s capacity, in bytes.
///
/// # Examples
}
#[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
B: ToOwned + ?Sized,
Arc<B>: From<&'a B> + From<B::Owned>,
{
+ /// Create an atomically reference-counted pointer from
+ /// a clone-on-write pointer by copying its content.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::sync::Arc;
+ /// # use std::borrow::Cow;
+ /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+ /// let shared: Arc<str> = Arc::from(cow);
+ /// assert_eq!("eggplant", &shared[..]);
+ /// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Arc<B> {
match cow {
#[stable(feature = "cow_from_vec", since = "1.8.0")]
impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+ /// Creates a [`Borrowed`] variant of [`Cow`]
+ /// from a slice.
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
fn from(s: &'a [T]) -> Cow<'a, [T]> {
Cow::Borrowed(s)
}
#[stable(feature = "cow_from_vec", since = "1.8.0")]
impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+ /// Creates an [`Owned`] variant of [`Cow`]
+ /// from an owned instance of [`Vec`].
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Owned`]: crate::borrow::Cow::Owned
fn from(v: Vec<T>) -> Cow<'a, [T]> {
Cow::Owned(v)
}
#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+ /// Creates a [`Borrowed`] variant of [`Cow`]
+ /// from a reference to [`Vec`].
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
Cow::Borrowed(v.as_slice())
}
self.is_none()
}
}
+
+// `Option<num::NonZeroU32>` and similar have a representation guarantee that
+// they're the same size as the corresponding `u32` type, as well as a guarantee
+// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
+// While the documentation officially makes it UB to transmute from `None`,
+// we're the standard library so we can make extra inferences, and we know that
+// the only niche available to represent `None` is the one that's all zeros.
+
+macro_rules! impl_is_zero_option_of_nonzero {
+ ($($t:ident,)+) => {$(
+ unsafe impl IsZero for Option<core::num::$t> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.is_none()
+ }
+ }
+ )+};
+}
+
+impl_is_zero_option_of_nonzero!(
+ NonZeroU8,
+ NonZeroU16,
+ NonZeroU32,
+ NonZeroU64,
+ NonZeroU128,
+ NonZeroI8,
+ NonZeroI16,
+ NonZeroI32,
+ NonZeroI64,
+ NonZeroI128,
+ NonZeroUsize,
+ NonZeroIsize,
+);
let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
+ // Increase `gap.read` now since the drop may panic.
+ gap.read += 1;
/* We have found duplicate, drop it in-place */
ptr::drop_in_place(read_ptr);
} else {
/* We have filled that place, so go further */
gap.write += 1;
+ gap.read += 1;
}
-
- gap.read += 1;
}
/* Technically we could let `gap` clean up with its Drop, but
use core::mem::ManuallyDrop;
use core::ptr::{self};
-use core::slice::{self};
use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
/// |where I: | | |where I: |
/// | Iterator (default)----------+ | | Iterator (default) |
/// | vec::IntoIter | | | TrustedLen |
-/// | SourceIterMarker---fallback-+ | | |
-/// | slice::Iter | | |
-/// | Iterator<Item = &Clone> | +---------------------+
+/// | SourceIterMarker---fallback-+ | +---------------------+
/// +---------------------------------+
/// ```
pub(super) trait SpecFromIter<T, I> {
vec
}
}
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
- I: Iterator<Item = &'a T>,
- T: Clone,
-{
- default fn from_iter(iterator: I) -> Self {
- SpecFromIter::from_iter(iterator.cloned())
- }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
- #[cfg(not(test))]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- iterator.as_slice().to_vec()
- }
-
- // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
- // required for this method definition, is not available. Instead use the
- // `slice::to_vec` function which is only available with cfg(test)
- // NB see the slice::hack module in slice.rs for more information
- #[cfg(test)]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
- }
-}
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
+}
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
-#![feature(vecdeque_binary_search)]
#![feature(slice_group_by)]
#![feature(slice_partition_dedup)]
#![feature(vec_spare_capacity)]
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
#[test]
fn test_vec_dedup_panicking() {
#[derive(Debug)]
- struct Panic {
- drop_counter: &'static AtomicU32,
+ struct Panic<'a> {
+ drop_counter: &'a Cell<u32>,
value: bool,
index: usize,
}
- impl PartialEq for Panic {
+ impl<'a> PartialEq for Panic<'a> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
- impl Drop for Panic {
+ impl<'a> Drop for Panic<'a> {
fn drop(&mut self) {
- let x = self.drop_counter.fetch_add(1, Ordering::SeqCst);
- assert!(x != 4);
+ self.drop_counter.set(self.drop_counter.get() + 1);
+ if !std::thread::panicking() {
+ assert!(self.index != 4);
+ }
}
}
- static DROP_COUNTER: AtomicU32 = AtomicU32::new(0);
+ let drop_counter = &Cell::new(0);
let expected = [
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+ Panic { drop_counter, value: false, index: 0 },
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
];
let mut vec = vec![
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
+ Panic { drop_counter, value: false, index: 0 },
// these elements get deduplicated
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 1 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 2 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 3 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 4 },
- // here it panics
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+ Panic { drop_counter, value: false, index: 1 },
+ Panic { drop_counter, value: false, index: 2 },
+ Panic { drop_counter, value: false, index: 3 },
+ Panic { drop_counter, value: false, index: 4 },
+ // here it panics while dropping the item with index==4
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
];
- let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
- vec.dedup();
- }));
+ let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err();
+
+ assert_eq!(drop_counter.get(), 4);
let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
// SAFETY: Callers are only allowed to pass an index that is in bounds
// Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
// multiple repeated reads of the same index would be safe and the
- // values aree !Drop, thus won't suffer from double drops.
+ // values are !Drop, thus won't suffer from double drops.
unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() }
}
}
-//! Implementations of things like `Eq` for fixed-length arrays
-//! up to a certain length. Eventually, we should be able to generalize
-//! to all lengths.
+//! Helper functions and types for fixed-length arrays.
//!
//! *[See also the array primitive type](array).*
// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
// so those calls will still resolve to the slice implementation, by reference.
-#[cfg(not(bootstrap))]
#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
impl<T, const N: usize> IntoIterator for [T; N] {
type Item = T;
//
// This should never be implemented by hand.
#[doc(hidden)]
- #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605
+ #[no_coverage] // rust-lang/rust#84605
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn assert_receiver_is_total_eq(&self) {}
/// // We need to remove "-" from the number output.
/// let tmp = self.nb.abs().to_string();
///
- /// formatter.pad_integral(self.nb > 0, "Foo ", &tmp)
+ /// formatter.pad_integral(self.nb >= 0, "Foo ", &tmp)
/// }
/// }
///
/// assert_eq!(&format!("{}", Foo::new(2)), "2");
/// assert_eq!(&format!("{}", Foo::new(-1)), "-1");
+ /// assert_eq!(&format!("{}", Foo::new(0)), "0");
/// assert_eq!(&format!("{:#}", Foo::new(-1)), "-Foo 1");
/// assert_eq!(&format!("{:0>#8}", Foo::new(-1)), "00-Foo 1");
/// ```
/// `.await` the value.
///
/// [`Waker`]: crate::task::Waker
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
#[lang = "future_trait"]
/// called on `self`:
/// * `std::clone::Clone::clone()`
/// * `std::iter::Iterator::size_hint()`
-/// * `std::iter::Iterator::next_back()`
+/// * `std::iter::DoubleEndedIterator::next_back()`
/// * `std::iter::Iterator::__iterator_get_unchecked()`
/// * `std::iter::TrustedRandomAccess::size()`
///
pub use self::traits::InPlaceIterable;
#[unstable(feature = "trusted_len", issue = "37572")]
pub use self::traits::TrustedLen;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::traits::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::{
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
use crate::mem;
use crate::ops::{self, Try};
-use super::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep};
+
+// Safety: All invariants are upheld.
+macro_rules! unsafe_impl_trusted_step {
+ ($($type:ty)*) => {$(
+ #[unstable(feature = "trusted_step", issue = "85731")]
+ unsafe impl TrustedStep for $type {}
+ )*};
+}
+unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
/// Objects that have a notion of *successor* and *predecessor* operations.
///
/// The *successor* operation moves towards values that compare greater.
/// The *predecessor* operation moves towards values that compare lesser.
-///
-/// # Safety
-///
-/// This trait is `unsafe` because its implementation must be correct for
-/// the safety of `unsafe trait TrustedLen` implementations, and the results
-/// of using this trait can otherwise be trusted by `unsafe` code to be correct
-/// and fulfill the listed obligations.
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-pub unsafe trait Step: Clone + PartialOrd + Sized {
+pub trait Step: Clone + PartialOrd + Sized {
/// Returns the number of *successor* steps required to get from `start` to `end`.
///
/// Returns `None` if the number of steps would overflow `usize`
///
/// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
/// * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn forward_checked(start: Self, count: usize) -> Option<Self>;
/// Returns the value that would be obtained by taking the *successor*
/// * Corollary: `Step::forward(a, 0) == a`
/// * `Step::forward(a, n) >= a`
/// * `Step::backward(Step::forward(a, n), n) == a`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn forward(start: Self, count: usize) -> Self {
Step::forward_checked(start, count).expect("overflow in `Step::forward`")
}
/// For any `a` and `n`, where no overflow occurs:
///
/// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
Step::forward(start, count)
}
///
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
/// * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn backward_checked(start: Self, count: usize) -> Option<Self>;
/// Returns the value that would be obtained by taking the *predecessor*
/// * Corollary: `Step::backward(a, 0) == a`
/// * `Step::backward(a, n) <= a`
/// * `Step::forward(Step::backward(a, n), n) == a`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn backward(start: Self, count: usize) -> Self {
Step::backward_checked(start, count).expect("overflow in `Step::backward`")
}
/// For any `a` and `n`, where no overflow occurs:
///
/// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
Step::backward(start, count)
}
$(
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $u_narrower {
+ impl Step for $u_narrower {
step_identical_methods!();
#[inline]
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $i_narrower {
+ impl Step for $i_narrower {
step_identical_methods!();
#[inline]
$(
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $u_wider {
+ impl Step for $u_wider {
step_identical_methods!();
#[inline]
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $i_wider {
+ impl Step for $i_wider {
step_identical_methods!();
#[inline]
}
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-unsafe impl Step for char {
+impl Step for char {
#[inline]
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
let start = start as u32;
)*)
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> Iterator for ops::Range<A> {
+/// Specialization implementations for `Range`.
+trait RangeIteratorImpl {
+ type Item;
+
+ // Iterator
+ fn spec_next(&mut self) -> Option<Self::Item>;
+ fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
+
+ // DoubleEndedIterator
+ fn spec_next_back(&mut self) -> Option<Self::Item>;
+ fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
+}
+
+impl<A: Step> RangeIteratorImpl for ops::Range<A> {
type Item = A;
#[inline]
- fn next(&mut self) -> Option<A> {
+ default fn spec_next(&mut self) -> Option<A> {
if self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
Some(mem::replace(&mut self.start, n))
} else {
None
}
#[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
+ default fn spec_nth(&mut self, n: usize) -> Option<A> {
+ if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
+ if plus_n < self.end {
+ self.start =
+ Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld");
+ return Some(plus_n);
+ }
+ }
+
+ self.start = self.end.clone();
+ None
+ }
+
+ #[inline]
+ default fn spec_next_back(&mut self) -> Option<A> {
if self.start < self.end {
- let hint = Step::steps_between(&self.start, &self.end);
- (hint.unwrap_or(usize::MAX), hint)
+ self.end =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ Some(self.end.clone())
} else {
- (0, Some(0))
+ None
}
}
#[inline]
- fn nth(&mut self, n: usize) -> Option<A> {
+ default fn spec_nth_back(&mut self, n: usize) -> Option<A> {
+ if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+ if minus_n > self.start {
+ self.end =
+ Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld");
+ return Some(self.end.clone());
+ }
+ }
+
+ self.end = self.start.clone();
+ None
+ }
+}
+
+impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
+ #[inline]
+ fn spec_next(&mut self) -> Option<T> {
+ if self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ Some(mem::replace(&mut self.start, n))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn spec_nth(&mut self, n: usize) -> Option<T> {
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
if plus_n < self.end {
// SAFETY: just checked precondition
None
}
+ #[inline]
+ fn spec_next_back(&mut self) -> Option<T> {
+ if self.start < self.end {
+ // SAFETY: just checked precondition
+ self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ Some(self.end.clone())
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn spec_nth_back(&mut self, n: usize) -> Option<T> {
+ if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+ if minus_n > self.start {
+ // SAFETY: just checked precondition
+ self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
+ return Some(self.end.clone());
+ }
+ }
+
+ self.end = self.start.clone();
+ None
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Step> Iterator for ops::Range<A> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ self.spec_next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.start < self.end {
+ let hint = Step::steps_between(&self.start, &self.end);
+ (hint.unwrap_or(usize::MAX), hint)
+ } else {
+ (0, Some(0))
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<A> {
+ self.spec_nth(n)
+ }
+
#[inline]
fn last(mut self) -> Option<A> {
self.next_back()
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.start < self.end {
- // SAFETY: just checked precondition
- self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- Some(self.end.clone())
- } else {
- None
- }
+ self.spec_next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<A> {
- if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
- if minus_n > self.start {
- // SAFETY: just checked precondition
- self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
- return Some(self.end.clone());
- }
- }
-
- self.end = self.start.clone();
- None
+ self.spec_nth_back(n)
}
}
+// Safety:
+// The following invariants for `Step::steps_between` exist:
+//
+// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
+// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+// > this is the case when it would require more than `usize::MAX` steps to
+// > get to `b`
+// > * `steps_between(&a, &b) == None` if `a > b`
+//
+// The first invariant is what is generally required for `TrustedLen` to be
+// sound. The note addendum satisfies an additional `TrustedLen` invariant.
+//
+// > The upper bound must only be `None` if the actual iterator length is larger
+// > than `usize::MAX`
+//
+// The second invariant logically follows the first so long as the `PartialOrd`
+// implementation is correct; regardless it is explicitly stated. If `a < b`
+// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such
+// the second invariant is upheld.
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {}
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::Range<A> {}
}
}
+// Safety: See above implementation for `ops::Range<A>`
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
+
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
+trait RangeInclusiveIteratorImpl {
+ type Item;
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<A: Step> Iterator for ops::RangeInclusive<A> {
+ // Iterator
+ fn spec_next(&mut self) -> Option<Self::Item>;
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+
+ // DoubleEndedIterator
+ fn spec_next_back(&mut self) -> Option<Self::Item>;
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> {
type Item = A;
#[inline]
- fn next(&mut self) -> Option<A> {
+ default fn spec_next(&mut self) -> Option<A> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+ mem::replace(&mut self.start, n)
+ } else {
+ self.exhausted = true;
+ self.start.clone()
+ })
+ }
+
+ #[inline]
+ default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, A) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+ let n = mem::replace(&mut self.start, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+
+ #[inline]
+ default fn spec_next_back(&mut self) -> Option<A> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ let n =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ mem::replace(&mut self.end, n)
+ } else {
+ self.exhausted = true;
+ self.end.clone()
+ })
+ }
+
+ #[inline]
+ default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, A) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ let n =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ let n = mem::replace(&mut self.end, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+}
+
+impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
+ #[inline]
+ fn spec_next(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
})
}
+ #[inline]
+ fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, T) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ let n = mem::replace(&mut self.start, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+
+ #[inline]
+ fn spec_next_back(&mut self) -> Option<T> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ mem::replace(&mut self.end, n)
+ } else {
+ self.exhausted = true;
+ self.end.clone()
+ })
+ }
+
+ #[inline]
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, T) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ let n = mem::replace(&mut self.end, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+impl<A: Step> Iterator for ops::RangeInclusive<A> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ self.spec_next()
+ }
+
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.is_empty() {
}
#[inline]
- fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- if self.is_empty() {
- return try { init };
- }
-
- let mut accum = init;
-
- while self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
- let n = mem::replace(&mut self.start, n);
- accum = f(accum, n)?;
- }
-
- self.exhausted = true;
-
- if self.start == self.end {
- accum = f(accum, self.start.clone())?;
- }
-
- try { accum }
+ self.spec_try_fold(init, f)
}
#[inline]
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.is_empty() {
- return None;
- }
- let is_iterating = self.start < self.end;
- Some(if is_iterating {
- // SAFETY: just checked precondition
- let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- mem::replace(&mut self.end, n)
- } else {
- self.exhausted = true;
- self.end.clone()
- })
+ self.spec_next_back()
}
#[inline]
}
#[inline]
- fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- if self.is_empty() {
- return try { init };
- }
-
- let mut accum = init;
-
- while self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- let n = mem::replace(&mut self.end, n);
- accum = f(accum, n)?;
- }
-
- self.exhausted = true;
-
- if self.start == self.end {
- accum = f(accum, self.start.clone())?;
- }
-
- try { accum }
+ self.spec_try_rfold(init, f)
}
#[inline]
}
}
+// Safety: See above implementation for `ops::Range<A>`
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
/// }
/// ```
#[rustc_diagnostic_item = "IntoIterator"]
-#[cfg_attr(not(bootstrap), rustc_skip_array_during_method_dispatch)]
+#[rustc_skip_array_during_method_dispatch]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
/// The type of the elements being iterated over.
/// [impl]: crate::iter#implementing-iterator
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
- on(
- _Self = "[std::ops::Range<Idx>; 1]",
- label = "if you meant to iterate between two values, remove the square brackets",
- note = "`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
- without the brackets: `start..end`"
- ),
- on(
- _Self = "[std::ops::RangeFrom<Idx>; 1]",
- label = "if you meant to iterate from a value onwards, remove the square brackets",
- note = "`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
- `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
- unbounded iterator will run forever unless you `break` or `return` from within the \
- loop"
- ),
- on(
- _Self = "[std::ops::RangeTo<Idx>; 1]",
- label = "if you meant to iterate until a value, remove the square brackets and add a \
- starting value",
- note = "`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
- `Range` without the brackets: `0..end`"
- ),
- on(
- _Self = "[std::ops::RangeInclusive<Idx>; 1]",
- label = "if you meant to iterate between two values, remove the square brackets",
- note = "`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
- `RangeInclusive` without the brackets: `start..=end`"
- ),
- on(
- _Self = "[std::ops::RangeToInclusive<Idx>; 1]",
- label = "if you meant to iterate until a value (including it), remove the square brackets \
- and add a starting value",
- note = "`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
- bounded `RangeInclusive` without the brackets: `0..=end`"
- ),
on(
_Self = "std::ops::RangeTo<Idx>",
label = "if you meant to iterate until a value, add a starting value",
_Self = "std::string::String",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
),
- on(
- _Self = "[]",
- label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`",
- note = "see <https://github.com/rust-lang/rust/pull/65819> for more details"
- ),
on(
_Self = "{integral}",
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
label = "`{Self}` is not an iterator",
message = "`{Self}` is not an iterator"
)]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
#[rustc_diagnostic_item = "Iterator"]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait Iterator {
/// If several elements are equally maximum, the last element is
/// returned. If the iterator is empty, [`None`] is returned.
///
+ /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+ /// incomparable. You can work around this by using [`Iterator::reduce`]:
+ /// ```
+ /// assert_eq!(
+ /// vec![2.4, f32::NAN, 1.3]
+ /// .into_iter()
+ /// .reduce(f32::max)
+ /// .unwrap(),
+ /// 2.4
+ /// );
+ /// ```
+ ///
/// # Examples
///
/// Basic usage:
/// Returns the minimum element of an iterator.
///
- /// If several elements are equally minimum, the first element is
- /// returned. If the iterator is empty, [`None`] is returned.
+ /// If several elements are equally minimum, the first element is returned.
+ /// If the iterator is empty, [`None`] is returned.
+ ///
+ /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+ /// incomparable. You can work around this by using [`Iterator::reduce`]:
+ /// ```
+ /// assert_eq!(
+ /// vec![2.4, f32::NAN, 1.3]
+ /// .into_iter()
+ /// .reduce(f32::min)
+ /// .unwrap(),
+ /// 1.3
+ /// );
+ /// ```
///
/// # Examples
///
+use crate::iter::Step;
+
/// An iterator that always continues to yield `None` when exhausted.
///
/// Calling next on a fused iterator that has returned `None` once is guaranteed
#[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)]
pub unsafe trait InPlaceIterable: Iterator {}
+
+/// A type that upholds all invariants of [`Step`].
+///
+/// The invariants of [`Step::steps_between()`] are a superset of the invariants
+/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
+/// types with the same generic type argument.
+///
+/// # Safety
+///
+/// The implementation of [`Step`] for the given type must guarantee all
+/// invariants of all methods are upheld. See the [`Step`] trait's documentation
+/// for details. Consumers are free to rely on the invariants in unsafe code.
+#[unstable(feature = "trusted_step", issue = "85731")]
+#[rustc_specialization_trait]
+pub unsafe trait TrustedStep: Step {}
pub use self::iterator::Iterator;
#[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::marker::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::marker::{FusedIterator, TrustedLen};
#![cfg(not(test))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(const_refs_to_cell)]
#![feature(const_panic)]
#![feature(const_pin)]
-#![cfg_attr(bootstrap, feature(const_fn))]
#![feature(const_fn_union)]
#![feature(const_impl_trait)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn))]
#![feature(const_option)]
#![feature(const_precise_live_drops)]
#![feature(const_ptr_offset)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
-#![cfg_attr(bootstrap, feature(doc_spotlight))]
-#![cfg_attr(not(bootstrap), feature(doc_notable_trait))]
+#![feature(doc_notable_trait)]
#![feature(duration_consts_2)]
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
#![feature(extern_types)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(auto_traits)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(prelude_import)]
#![feature(ptr_metadata)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
-#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
#![feature(no_niche)] // rust-lang/rust#68303
-#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605
+#![feature(no_coverage)] // rust-lang/rust#84605
#![feature(int_error_matching)]
#![deny(unsafe_op_in_unsafe_fn)]
+#![deny(or_patterns_back_compat)]
// allow using `core::` in intra-doc links
#[allow(unused_extern_crates)]
unused_imports,
unsafe_op_in_unsafe_fn
)]
-#[cfg_attr(bootstrap, allow(rustdoc::non_autolinks))]
-#[cfg_attr(not(bootstrap), allow(rustdoc::bare_urls))]
+#[allow(rustdoc::bare_urls)]
// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
#[allow(clashing_extern_declarations)]
#[unstable(feature = "assert_matches", issue = "82775")]
#[allow_internal_unstable(core_panic)]
macro_rules! assert_matches {
- ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
+ ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
}
}
});
- ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
+ ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
macro_rules! matches {
- ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+ ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
$( $pattern )|+ $( if $guard )? => true,
_ => false
/// Indicates unimplemented code by panicking with a message of "not implemented".
///
/// This allows your code to type-check, which is useful if you are prototyping or
-/// implementing a trait that requires multiple methods which you don't plan of using all of.
+/// implementing a trait that requires multiple methods which you don't plan to use all of.
///
/// The difference between `unimplemented!` and [`todo!`] is that while `todo!`
/// conveys an intent of implementing the functionality later and the message is "not yet
///
/// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
self.to_bits().to_ne_bytes()
}
- /// Return the memory representation of this floating point number as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: f32::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- /// let num = 12.5f32;
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- /// &[0x41, 0x48, 0x00, 0x00]
- /// } else {
- /// &[0x00, 0x00, 0x48, 0x41]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; 4] {
- // SAFETY: `f32` is a plain old datatype so we can always transmute to it
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a floating point value from its representation as a byte array in big endian.
///
/// # Examples
///
/// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
self.to_bits().to_ne_bytes()
}
- /// Return the memory representation of this floating point number as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: f64::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- /// let num = 12.5f64;
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- /// &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
- /// } else {
- /// &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; 8] {
- // SAFETY: `f64` is a plain old datatype so we can always transmute to it
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a floating point value from its representation as a byte array in big endian.
///
/// # Examples
}
/// Unchecked integer addition. Computes `self + rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_add`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_sub`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_mul`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift left. Computes `self << rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shl`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shl`.
+ unsafe { intrinsics::unchecked_shl(self, rhs) }
+ }
+
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
/// larger than or equal to the number of bits in `self`.
///
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift right. Computes `self >> rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shr`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shr`.
+ unsafe { intrinsics::unchecked_shr(self, rhs) }
+ }
+
/// Checked absolute value. Computes `self.abs()`, returning `None` if
/// `self == MIN`.
///
unsafe { mem::transmute(self) }
}
- /// Return the memory representation of this integer as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: Self::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- #[doc = concat!(" &", $be_bytes)]
- /// } else {
- #[doc = concat!(" &", $le_bytes)]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create an integer value from its representation as a byte array in
/// big endian.
///
}
/// Unchecked integer addition. Computes `self + rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_add`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_sub`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_mul`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift left. Computes `self << rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shl`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shl`.
+ unsafe { intrinsics::unchecked_shl(self, rhs) }
+ }
+
/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift right. Computes `self >> rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shr`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shr`.
+ unsafe { intrinsics::unchecked_shr(self, rhs) }
+ }
+
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
/// overflow occurred.
///
unsafe { mem::transmute(self) }
}
- /// Return the memory representation of this integer as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: Self::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- #[doc = concat!(" &", $be_bytes)]
- /// } else {
- #[doc = concat!(" &", $le_bytes)]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a native endian integer value from its representation
/// as a byte array in big endian.
///
#[cfg(bootstrap)]
impl<R: ops::TryV1> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn from_try(r: R) -> Self {
+ pub(crate) fn from_try(r: R) -> Self {
match R::into_result(r) {
Ok(v) => ControlFlow::Continue(v),
Err(v) => ControlFlow::Break(R::from_error(v)),
}
/// Convert a `ControlFlow` into any type implementing `Try`;
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn into_try(self) -> R {
+ pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_ok(v),
ControlFlow::Break(v) => v,
}
}
+/// These are used only as part of implementing the iterator adapters.
+/// They have mediocre names and non-obvious semantics, so aren't
+/// currently on a path to potential stabilization.
#[cfg(not(bootstrap))]
impl<R: ops::TryV2> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn from_try(r: R) -> Self {
+ pub(crate) fn from_try(r: R) -> Self {
match R::branch(r) {
ControlFlow::Continue(v) => ControlFlow::Continue(v),
ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
}
/// Convert a `ControlFlow` into any type implementing `Try`;
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn into_try(self) -> R {
+ pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_output(v),
ControlFlow::Break(v) => v,
Unbounded,
}
-#[unstable(feature = "bound_as_ref", issue = "80996")]
impl<T> Bound<T> {
/// Converts from `&Bound<T>` to `Bound<&T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_ref(&self) -> Bound<&T> {
match *self {
Included(ref x) => Included(x),
/// Converts from `&mut Bound<T>` to `Bound<&T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_mut(&mut self) -> Bound<&mut T> {
match *self {
Included(ref mut x) => Included(x),
Unbounded => Unbounded,
}
}
+
+ /// Maps a `Bound<T>` to a `Bound<U>` by applying a function to the contained value (including
+ /// both `Included` and `Excluded`), returning a `Bound` of the same kind.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound::*;
+ ///
+ /// let bound_string = Included("Hello, World!");
+ ///
+ /// assert_eq!(bound_string.map(|s| s.len()), Included(13));
+ /// ```
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound;
+ /// use Bound::*;
+ ///
+ /// let unbounded_string: Bound<String> = Unbounded;
+ ///
+ /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded);
+ /// ```
+ #[inline]
+ #[unstable(feature = "bound_map", issue = "86026")]
+ pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Bound<U> {
+ match self {
+ Unbounded => Unbounded,
+ Included(x) => Included(f(x)),
+ Excluded(x) => Excluded(f(x)),
+ }
+ }
}
impl<T: Clone> Bound<&T> {
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
enclosing_scope = "this function returns a `Result`"
),
+ on(
+ all(
+ from_method = "from_residual",
+ from_desugaring = "QuestionMark",
+ _Self = "std::option::Option<T>",
+ R = "std::result::Result<T, E>",
+ ),
+ message = "the `?` operator can only be used on `Option`s, not `Result`s, \
+ in {ItemContext} that returns `Option`",
+ label = "use `.ok()?` if you want to discard the `{R}` error information",
+ enclosing_scope = "this function returns an `Option`"
+ ),
on(
all(
from_method = "from_residual",
from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::ops::ControlFlow<B, C>",
+ R = "std::ops::ControlFlow<B, C>",
),
- message = "the `?` operator can only be used on `ControlFlow<B, _>`s \
- in {ItemContext} that returns `ControlFlow<B, _>`",
+ message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
+ can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
enclosing_scope = "this function returns a `ControlFlow`",
note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
),
+ on(
+ all(
+ from_method = "from_residual",
+ from_desugaring = "QuestionMark",
+ _Self = "std::ops::ControlFlow<B, C>",
+ // `R` is not a `ControlFlow`, as that case was matched previously
+ ),
+ message = "the `?` operator can only be used on `ControlFlow`s \
+ in {ItemContext} that returns `ControlFlow`",
+ label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+ enclosing_scope = "this function returns a `ControlFlow`",
+ ),
on(
all(
from_method = "from_residual",
//! * [`ptr::NonNull<U>`]
//! * `#[repr(transparent)]` struct around one of the types in this list.
//!
+//! This is called the "null pointer optimization" or NPO.
+//!
//! It is further guaranteed that, for the cases above, one can
//! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
//! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
/// The 2015 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[unstable(feature = "prelude_2015", issue = "85684")]
pub mod rust_2015 {
- #[unstable(feature = "prelude_2015", issue = "none")]
+ #[unstable(feature = "prelude_2015", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2018 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[unstable(feature = "prelude_2018", issue = "85684")]
pub mod rust_2018 {
- #[unstable(feature = "prelude_2018", issue = "none")]
+ #[unstable(feature = "prelude_2018", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2021 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[unstable(feature = "prelude_2021", issue = "85684")]
pub mod rust_2021 {
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[unstable(feature = "prelude_2021", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
- // FIXME: Add more things.
+ #[unstable(feature = "prelude_2021", issue = "85684")]
+ #[doc(no_inline)]
+ pub use crate::iter::FromIterator;
+
+ #[unstable(feature = "prelude_2021", issue = "85684")]
+ #[doc(no_inline)]
+ pub use crate::convert::{TryFrom, TryInto};
}
// SAFETY: the conditions for `ptr::copy` have all been checked above,
// as have those for `ptr::add`.
unsafe {
- ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
+ // Derive both `src_ptr` and `dest_ptr` from the same loan
+ let ptr = self.as_mut_ptr();
+ let src_ptr = ptr.add(src_start);
+ let dest_ptr = ptr.add(dest);
+ ptr::copy(src_ptr, dest_ptr, count);
}
}
fn is_any<T: Any + ?Sized>() {}
is_any::<[i32]>();
}
+
+#[test]
+fn distinct_type_names() {
+ // https://github.com/rust-lang/rust/issues/84666
+
+ struct Velocity(f32, f32);
+
+ fn type_name_of_val<T>(_: T) -> &'static str {
+ type_name::<T>()
+ }
+
+ assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
+}
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(step_trait)]
-#![feature(step_trait_ext)]
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
#![no_std]
#![unstable(feature = "panic_abort", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(nll)]
data: *mut T,
len: usize,
capacity: usize,
- extend_from_slice: extern "C" fn(Buffer<T>, Slice<'_, T>) -> Buffer<T>,
+ reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
drop: extern "C" fn(Buffer<T>),
}
mem::take(self)
}
+ // We have the array method separate from extending from a slice. This is
+ // because in the case of small arrays, codegen can be more efficient
+ // (avoiding a memmove call). With extend_from_slice, LLVM at least
+ // currently is not able to make that optimization.
+ pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
+ if xs.len() > (self.capacity - self.len) {
+ let b = self.take();
+ *self = (b.reserve)(b, xs.len());
+ }
+ unsafe {
+ xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+ self.len += xs.len();
+ }
+ }
+
pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
- // Fast path to avoid going through an FFI call.
- if let Some(final_len) = self.len.checked_add(xs.len()) {
- if final_len <= self.capacity {
- let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) };
- dst[self.len..][..xs.len()].copy_from_slice(xs);
- self.len = final_len;
- return;
- }
+ if xs.len() > (self.capacity - self.len) {
+ let b = self.take();
+ *self = (b.reserve)(b, xs.len());
+ }
+ unsafe {
+ xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+ self.len += xs.len();
+ }
+ }
+
+ pub(super) fn push(&mut self, v: T) {
+ // The code here is taken from Vec::push, and we know that reserve()
+ // will panic if we're exceeding isize::MAX bytes and so there's no need
+ // to check for overflow.
+ if self.len == self.capacity {
+ let b = self.take();
+ *self = (b.reserve)(b, 1);
+ }
+ unsafe {
+ *self.data.add(self.len) = v;
+ self.len += 1;
}
- let b = self.take();
- *self = (b.extend_from_slice)(b, Slice::from(xs));
}
}
}
}
- extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<'_, T>) -> Buffer<T> {
+ extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
let mut v = to_vec(b);
- v.extend_from_slice(&xs);
+ v.reserve(additional);
Buffer::from(v)
}
mem::drop(to_vec(b));
}
- Buffer { data, len, capacity, extend_from_slice, drop }
+ Buffer { data, len, capacity, reserve, drop }
}
}
(le $ty:ty) => {
impl<S> Encode<S> for $ty {
fn encode(self, w: &mut Writer, _: &mut S) {
- w.write_all(&self.to_le_bytes()).unwrap();
+ w.extend_from_array(&self.to_le_bytes());
}
}
impl<S> Encode<S> for u8 {
fn encode(self, w: &mut Writer, _: &mut S) {
- w.write_all(&[self]).unwrap();
+ w.push(self);
}
}
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
#![deny(missing_docs)]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(rustc_allow_const_fn_unstable)]
#![feature(nll)]
#![feature(staged_api)]
-#![cfg_attr(bootstrap, feature(const_fn))]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(allow_internal_unstable)]
#![feature(decl_macro)]
compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
[build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.43" }
+compiler_builtins = { version = "0.1.44" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
}
/// Bypass "move out of struct which implements [`Drop`] trait" restriction.
+ #[inline]
fn into_inner(self) -> Box<[u8]> {
// Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
// so we use `ManuallyDrop` to ensure `self` is not dropped.
/// [`std::io`]: self
/// [`File`]: crate::fs::File
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
pub trait Read {
/// Pull some bytes from this source into the specified buffer, returning
/// how many bytes were read.
///
/// [`write_all`]: Write::write_all
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
pub trait Write {
/// Write a buffer into this writer, returning how many bytes were written.
///
/// move || println!("This is a: {}", text)
/// }
///
-/// let fn_plain = create_fn();
+/// let fn_plain = create_fn();
///
-/// fn_plain();
+/// fn_plain();
/// ```
///
/// `move` is often used when [threads] are involved.
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(doc_cfg)]
#![feature(doc_keyword)]
#![feature(doc_masked)]
-#![cfg_attr(bootstrap, feature(doc_spotlight))]
-#![cfg_attr(not(bootstrap), feature(doc_notable_trait))]
+#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
#![feature(duration_constants)]
#![feature(edition_panic)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(once_cell)]
#![feature(auto_traits)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(panic_info_message)]
#![feature(panic_internals)]
#![feature(panic_unwind)]
-#![unstable(
- feature = "ip",
- reason = "extra functionality has not been \
- scrutinized to the level that it should \
- be to be stable",
- issue = "27709"
-)]
-
// Tests for this module
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
#[allow(missing_docs)]
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
pub enum Ipv6MulticastScope {
InterfaceLocal,
LinkLocal,
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
match self {
/// );
/// ```
#[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_documentation(&self) -> bool {
match self {
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
/// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_shared(&self) -> bool {
self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
/// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_ietf_protocol_assignment(&self) -> bool {
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
/// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_reserved(&self) -> bool {
self.octets()[0] & 240 == 240 && !self.is_broadcast()
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
match self.multicast_scope() {
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unique_local(&self) -> bool {
(self.segments()[0] & 0xfe00) == 0xfc00
}
- /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
+ /// Returns `true` if the address is a unicast address with link-local scope,
+ /// as defined in [RFC 4291].
///
- /// A common misconception is to think that "unicast link-local addresses start with
- /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
+ /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+ /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+ /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
///
- /// ```no_rust
- /// | 10 |
- /// | bits | 54 bits | 64 bits |
+ /// ```text
+ /// | 10 bits | 54 bits | 64 bits |
/// +----------+-------------------------+----------------------------+
/// |1111111010| 0 | interface ID |
/// +----------+-------------------------+----------------------------+
/// ```
+ /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+ /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+ /// and those addresses will have link-local scope.
///
- /// This method validates the format defined in the RFC and won't recognize addresses
- /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
- /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local_strict());
- ///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
- /// assert!(ip.is_unicast_link_local_strict());
- ///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
- /// assert!(!ip.is_unicast_link_local_strict());
- /// assert!(ip.is_unicast_link_local());
- ///
- /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(!ip.is_unicast_link_local_strict());
- /// assert!(ip.is_unicast_link_local());
- /// ```
- ///
- /// # See also
- ///
- /// - [IETF RFC 4291 section 2.5.6]
- /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
- /// insight)
- /// - [`Ipv6Addr::is_unicast_link_local()`]
+ /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+ /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
///
- /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
- /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
- /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[inline]
- pub const fn is_unicast_link_local_strict(&self) -> bool {
- matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
- }
-
- /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
- ///
- /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
- /// i.e. addresses with the following format:
- ///
- /// ```no_rust
- /// | 10 |
- /// | bits | 54 bits | 64 bits |
- /// +----------+-------------------------+----------------------------+
- /// |1111111010| arbitratry value | interface ID |
- /// +----------+-------------------------+----------------------------+
- /// ```
- ///
- /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
- /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
- /// If you need a strict validation fully compliant with the RFC, use
- /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
+ /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+ /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+ /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+ /// [loopback address]: Ipv6Addr::LOCALHOST
///
/// # Examples
///
///
/// use std::net::Ipv6Addr;
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
+ /// // The loopback address (`::1`) does not actually have link-local scope.
+ /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
- /// assert!(ip.is_unicast_link_local());
+ /// // Only addresses in `fe80::/10` have link-local scope.
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+ /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
- /// assert!(!ip.is_unicast_link_local_strict());
- ///
- /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
- /// assert!(!ip.is_unicast_link_local_strict());
+ /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+ /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+ /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
/// ```
- ///
- /// # See also
- ///
- /// - [IETF RFC 4291 section 2.4]
- /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
- /// insight)
- ///
- /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
- /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
///
/// [RFC 3879]: https://tools.ietf.org/html/rfc3879
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_site_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfec0
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_global(&self) -> bool {
!self.is_multicast()
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
match self.octets() {
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
- let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
} else {
assert!(!ip!($s).is_unicast_link_local());
}
- if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
- assert!(ip!($s).is_unicast_link_local_strict());
- } else {
- assert!(!ip!($s).is_unicast_link_local_strict());
- }
if ($mask & unicast_site_local) == unicast_site_local {
assert!(ip!($s).is_unicast_site_local());
} else {
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
- let unicast_link_local_strict: u16 = 1 << 5;
let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
unicast_link_local
);
- check!(
- "fe80::",
- &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_link_local | unicast_link_local_strict
- );
+ check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
check!(
"febf:ffff::",
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
- unicast_link_local | unicast_link_local_strict
+ unicast_link_local
);
check!(
const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
assert!(!IS_UNIQUE_LOCAL);
- const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
- assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
-
const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
assert!(!IS_UNICAST_LINK_LOCAL);
/// }
/// ```
#[unstable(feature = "unix_chroot", issue = "84715")]
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
sys::fs::chroot(dir.as_ref())
}
/// See the [`panic!`] macro for more information about panicking.
#[stable(feature = "panic_any", since = "1.51.0")]
#[inline]
+#[track_caller]
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
crate::panicking::begin_panic(msg);
}
#[stable(feature = "box_from_path", since = "1.17.0")]
impl From<&Path> for Box<Path> {
+ /// Creates a boxed [`Path`] from a reference.
+ ///
+ /// This will allocate and clone `path` to it.
fn from(path: &Path) -> Box<Path> {
let boxed: Box<OsStr> = path.inner.into();
let rw = Box::into_raw(boxed) as *mut Path;
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, Path>> for Box<Path> {
+ /// Creates a boxed [`Path`] from a clone-on-write pointer.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(cow: Cow<'_, Path>) -> Box<Path> {
match cow {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+ /// Converts a borrowed `OsStr` to a `PathBuf`.
+ ///
+ /// Allocates a [`PathBuf`] and copies the data into it.
#[inline]
fn from(s: &T) -> PathBuf {
PathBuf::from(s.as_ref().to_os_string())
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<&'a Path> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`Path`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: &'a Path) -> Cow<'a, Path> {
Cow::Borrowed(s)
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from an owned
+ /// instance of [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: PathBuf) -> Cow<'a, Path> {
Cow::Owned(s)
#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(p: &'a PathBuf) -> Cow<'a, Path> {
Cow::Borrowed(p.as_path())
#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
impl<'a> From<Cow<'a, Path>> for PathBuf {
+ /// Converts a clone-on-write pointer to an owned path.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(p: Cow<'a, Path>) -> Self {
p.into_owned()
/// Returns `true` if the path points at an existing entity.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a regular file.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a directory.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// The 2015 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[unstable(feature = "prelude_2015", issue = "85684")]
pub mod rust_2015 {
- #[unstable(feature = "prelude_2015", issue = "none")]
+ #[unstable(feature = "prelude_2015", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2018 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[unstable(feature = "prelude_2018", issue = "85684")]
pub mod rust_2018 {
- #[unstable(feature = "prelude_2018", issue = "none")]
+ #[unstable(feature = "prelude_2018", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2021 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[unstable(feature = "prelude_2021", issue = "85684")]
pub mod rust_2021 {
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[unstable(feature = "prelude_2021", issue = "85684")]
#[doc(no_inline)]
pub use super::v1::*;
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[unstable(feature = "prelude_2021", issue = "85684")]
#[doc(no_inline)]
pub use core::prelude::rust_2021::*;
}
///
/// # Examples
///
-#[cfg_attr(bootstrap, doc = "```ignore")]
-#[cfg_attr(not(bootstrap), doc = "```")]
+/// ```
/// let mut array: [i32; 3] = [0; 3];
///
/// array[1] = 1;
/// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition
/// might be made consistent to the behavior of later editions.
///
-#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
-#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// ```rust,edition2018
/// # #![allow(array_into_iter)] // override our `deny(warnings)`
/// let array: [i32; 3] = [0; 3];
///
/// * replace `for ... in array.into_iter() {` with `for ... in array {`,
/// equivalent to the post-2021 behavior (Rust 1.53+)
///
-#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
-#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// ```rust,edition2018
/// use std::array::IntoIter;
///
/// let array: [i32; 3] = [0; 3];
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
- /// this call will return an error if the mutex would otherwise be
- /// acquired.
+ /// this call will return the [`Poisoned`] error if the mutex would
+ /// otherwise be acquired.
+ ///
+ /// If the mutex could not be acquired because it is already locked, then
+ /// this call will return the [`WouldBlock`] error.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
///
/// # Examples
///
///
/// # Errors
///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
+ /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
+ /// An RwLock is poisoned whenever a writer panics while holding an exclusive
+ /// lock. `Poisoned` will only be returned if the lock would have otherwise been
/// acquired.
///
+ /// This function will return the [`WouldBlock`] error if the RwLock could not
+ /// be acquired because it was already locked exclusively.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
+ ///
/// # Examples
///
/// ```
///
/// # Errors
///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
+ /// This function will return the [`Poisoned`] error if the RwLock is
+ /// poisoned. An RwLock is poisoned whenever a writer panics while holding
+ /// an exclusive lock. `Poisoned` will only be returned if the lock would have
+ /// otherwise been acquired.
+ ///
+ /// This function will return the [`WouldBlock`] error if the RwLock could not
+ /// be acquired because it was already locked exclusively.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
+ ///
///
/// # Examples
///
Ok(bytes_copied as u64)
}
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
pub fn chroot(dir: &Path) -> io::Result<()> {
let dir = cstr(dir)?;
cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
if #[cfg(target_os = "android")] {
#[link(name = "dl")]
#[link(name = "log")]
- #[link(name = "gcc")]
extern "C" {}
} else if #[cfg(target_os = "freebsd")] {
#[link(name = "execinfo")]
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
// On platforms that support it we pass the SOCK_CLOEXEC
// flag to atomically create the socket and set it as
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
// Like above, set cloexec atomically
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
let fd = cvt_r(|| unsafe {
libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
// This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
- // true on all actual versios of Unix, is widely assumed, and is specified in SuS
+ // true on all actual versions of Unix, is widely assumed, and is specified in SuS
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
// true for a platform pretending to be Unix, the tests (our doctests, and also
// procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
+use crate::convert::{TryFrom, TryInto};
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
+use crate::num::NonZeroI32;
+use crate::os::raw::NonZero_c_int;
use crate::sys;
use crate::sys::cvt;
use crate::sys::process::process_common::*;
libc::WIFEXITED(self.0)
}
- pub fn success(&self) -> bool {
- self.code() == Some(0)
+ pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+ // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
+ // true on all actual versions of Unix, is widely assumed, and is specified in SuS
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not
+ // true for a platform pretending to be Unix, the tests (our doctests, and also
+ // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
+ match NonZero_c_int::try_from(self.0) {
+ Ok(failure) => Err(ExitStatusError(failure)),
+ Err(_) => Ok(()),
+ }
}
pub fn code(&self) -> Option<i32> {
}
}
}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(NonZero_c_int);
+
+impl Into<ExitStatus> for ExitStatusError {
+ fn into(self) -> ExitStatus {
+ ExitStatus(self.0.into())
+ }
+}
+
+impl ExitStatusError {
+ pub fn code(self) -> Option<NonZeroI32> {
+ ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+ }
+}
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] |
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] |
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- html_playground_url = "https://play.rust-lang.org/",
- test(attr(deny(warnings)))
-)]
+#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))]
#![deny(missing_docs)]
#![cfg_attr(windows, feature(libc))]
"Configure formatting of output:
pretty = Print verbose output;
terse = Display one character per test;
- json = Output a json document",
- "pretty|terse|json",
+ json = Output a json document;
+ junit = Output a JUnit document",
+ "pretty|terse|json|junit",
)
.optflag("", "show-output", "Show captured stdout of successful tests")
.optopt(
}
OutputFormat::Json
}
-
+ Some("junit") => {
+ if !allow_unstable {
+ return Err("The \"junit\" format is only accepted on the nightly compiler".into());
+ }
+ OutputFormat::Junit
+ }
Some(v) => {
return Err(format!(
- "argument for --format must be pretty, terse, or json (was \
+ "argument for --format must be pretty, terse, json or junit (was \
{})",
v
));
cli::TestOpts,
event::{CompletedTest, TestEvent},
filter_tests,
- formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
+ formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
helpers::{concurrency::get_concurrency, metrics::MetricMap},
options::{Options, OutputFormat},
run_tests,
Box::new(TerseFormatter::new(output, opts.use_color(), max_name_len, is_multithreaded))
}
OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+ OutputFormat::Junit => Box::new(JunitFormatter::new(output)),
};
let mut st = ConsoleTestState::new(opts)?;
--- /dev/null
+use std::io::{self, prelude::Write};
+use std::time::Duration;
+
+use super::OutputFormatter;
+use crate::{
+ console::{ConsoleTestState, OutputLocation},
+ test_result::TestResult,
+ time,
+ types::{TestDesc, TestType},
+};
+
+pub struct JunitFormatter<T> {
+ out: OutputLocation<T>,
+ results: Vec<(TestDesc, TestResult, Duration)>,
+}
+
+impl<T: Write> JunitFormatter<T> {
+ pub fn new(out: OutputLocation<T>) -> Self {
+ Self { out, results: Vec::new() }
+ }
+
+ fn write_message(&mut self, s: &str) -> io::Result<()> {
+ assert!(!s.contains('\n'));
+
+ self.out.write_all(s.as_ref())
+ }
+}
+
+impl<T: Write> OutputFormatter for JunitFormatter<T> {
+ fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
+ // We write xml header on run start
+ self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
+ }
+
+ fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
+ // We do not output anything on test start.
+ Ok(())
+ }
+
+ fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
+ // We do not output anything on test timeout.
+ Ok(())
+ }
+
+ fn write_result(
+ &mut self,
+ desc: &TestDesc,
+ result: &TestResult,
+ exec_time: Option<&time::TestExecTime>,
+ _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
+ // them to a Vec and write them all at once when run is complete.
+ let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default();
+ self.results.push((desc.clone(), result.clone(), duration));
+ Ok(())
+ }
+ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+ self.write_message("<testsuites>")?;
+
+ self.write_message(&*format!(
+ "<testsuite name=\"test\" package=\"test\" id=\"0\" \
+ errors=\"0\" \
+ failures=\"{}\" \
+ tests=\"{}\" \
+ skipped=\"{}\" \
+ >",
+ state.failed, state.total, state.ignored
+ ))?;
+ for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+ let (class_name, test_name) = parse_class_name(&desc);
+ match result {
+ TestResult::TrIgnored => { /* no-op */ }
+ TestResult::TrFailed => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message("<failure type=\"assert\"/>")?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrFailedMsg(ref m) => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrTimedFail => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message("<failure type=\"timeout\"/>")?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrBench(ref b) => {
+ self.write_message(&*format!(
+ "<testcase classname=\"benchmark::{}\" \
+ name=\"{}\" time=\"{}\" />",
+ class_name, test_name, b.ns_iter_summ.sum
+ ))?;
+ }
+
+ TestResult::TrOk | TestResult::TrAllowedFail => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\"/>",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ }
+ }
+ }
+ self.write_message("<system-out/>")?;
+ self.write_message("<system-err/>")?;
+ self.write_message("</testsuite>")?;
+ self.write_message("</testsuites>")?;
+
+ Ok(state.failed == 0)
+ }
+}
+
+fn parse_class_name(desc: &TestDesc) -> (String, String) {
+ match desc.test_type {
+ TestType::UnitTest => parse_class_name_unit(desc),
+ TestType::DocTest => parse_class_name_doc(desc),
+ TestType::IntegrationTest => parse_class_name_integration(desc),
+ TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
+ }
+}
+
+fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
+ // Module path => classname
+ // Function name => name
+ let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
+ let (class_name, test_name) = match module_segments[..] {
+ [test] => (String::from("crate"), String::from(test)),
+ [ref path @ .., test] => (path.join("::"), String::from(test)),
+ [..] => unreachable!(),
+ };
+ (class_name, test_name)
+}
+
+fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
+ // File path => classname
+ // Line # => test name
+ let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
+ let (class_name, test_name) = match segments[..] {
+ [file, line] => (String::from(file.trim()), String::from(line.trim())),
+ [..] => unreachable!(),
+ };
+ (class_name, test_name)
+}
+
+fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
+ (String::from("integration"), String::from(desc.name.as_slice()))
+}
};
mod json;
+mod junit;
mod pretty;
mod terse;
pub(crate) use self::json::JsonFormatter;
+pub(crate) use self::junit::JunitFormatter;
pub(crate) use self::pretty::PrettyFormatter;
pub(crate) use self::terse::TerseFormatter;
#![crate_name = "test"]
#![unstable(feature = "test", issue = "50297")]
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
+#![doc(test(attr(deny(warnings))))]
#![cfg_attr(unix, feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
Terse,
/// JSON output
Json,
+ /// JUnit output
+ Junit,
}
/// Whether ignored test should be run or not
cfg-if = "0.1.8"
[build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
[features]
+
+# Only applies for Linux and Fuchsia targets
+# Static link to the in-tree build of llvm libunwind
llvm-libunwind = []
+
+# Only applies for Linux and Fuchsia targets
+# If crt-static is enabled, static link to `libunwind.a` provided by system
+# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
system-llvm-libunwind = []
println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
- if cfg!(feature = "system-llvm-libunwind") {
+ if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
+ // linking for Linux is handled in lib.rs
return;
}
// linking for Linux is handled in lib.rs
if target.contains("musl") {
llvm_libunwind::compile();
+ } else if target.contains("android") {
+ let build = cc::Build::new();
+
+ // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+ // check if we have `libunwind` available and if so use it. Otherwise
+ // fall back to `libgcc` to support older ndk versions.
+ let has_unwind =
+ build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+
+ if has_unwind {
+ println!("cargo:rustc-link-lib=unwind");
+ } else {
+ println!("cargo:rustc-link-lib=gcc");
+ }
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
pub fn compile() {
let target = env::var("TARGET").expect("TARGET was not set");
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
- let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
- let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
- let cfg = &mut cc::Build::new();
-
- cfg.cpp(true);
- cfg.cpp_set_stdlib(None);
- cfg.warnings(false);
+ let mut cc_cfg = cc::Build::new();
+ let mut cpp_cfg = cc::Build::new();
+ let root = Path::new("../../src/llvm-project/libunwind");
- // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
- if target_endian_little {
- cfg.define("__LITTLE_ENDIAN__", Some("1"));
+ cpp_cfg.cpp(true);
+ cpp_cfg.cpp_set_stdlib(None);
+ cpp_cfg.flag("-nostdinc++");
+ cpp_cfg.flag("-fno-exceptions");
+ cpp_cfg.flag("-fno-rtti");
+ cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+ // Don't set this for clang
+ // By default, Clang builds C code in GNU C17 mode.
+ // By default, Clang builds C++ code according to the C++98 standard,
+ // with many C++11 features accepted as extensions.
+ if cpp_cfg.get_compiler().is_like_gnu() {
+ cpp_cfg.flag("-std=c++11");
+ cc_cfg.flag("-std=c99");
}
- if target_env == "msvc" {
- // Don't pull in extra libraries on MSVC
- cfg.flag("/Zl");
- cfg.flag("/EHsc");
- cfg.define("_CRT_SECURE_NO_WARNINGS", None);
- cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
- } else if target.contains("x86_64-fortanix-unknown-sgx") {
- cfg.cpp(false);
-
- cfg.static_flag(true);
- cfg.opt_level(3);
-
- cfg.flag("-nostdinc++");
- cfg.flag("-fno-exceptions");
- cfg.flag("-fno-rtti");
- cfg.flag("-fstrict-aliasing");
- cfg.flag("-funwind-tables");
- cfg.flag("-fvisibility=hidden");
- cfg.flag("-fno-stack-protector");
- cfg.flag("-ffreestanding");
- cfg.flag("-fexceptions");
-
- // easiest way to undefine since no API available in cc::Build to undefine
- cfg.flag("-U_FORTIFY_SOURCE");
- cfg.define("_FORTIFY_SOURCE", "0");
-
- cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+ if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
+ // use the same GCC C compiler command to compile C++ code so we do not need to setup the
+ // C++ compiler env variables on the builders.
+ // Don't set this for clang++, as clang++ is able to compile this without libc++.
+ if cpp_cfg.get_compiler().is_like_gnu() {
+ cpp_cfg.cpp(false);
+ }
+ }
- cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
- cfg.define("RUST_SGX", "1");
- cfg.define("__NO_STRING_INLINES", None);
- cfg.define("__NO_MATH_INLINES", None);
- cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
- cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
- cfg.define("NDEBUG", None);
- } else {
- cfg.flag("-std=c99");
- cfg.flag("-std=c++11");
- cfg.flag("-nostdinc++");
- cfg.flag("-fno-exceptions");
- cfg.flag("-fno-rtti");
+ for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
+ cfg.warnings(false);
cfg.flag("-fstrict-aliasing");
cfg.flag("-funwind-tables");
cfg.flag("-fvisibility=hidden");
- cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+ cfg.include(root.join("include"));
+ cfg.cargo_metadata(false);
+
+ if target.contains("x86_64-fortanix-unknown-sgx") {
+ cfg.static_flag(true);
+ cfg.opt_level(3);
+ cfg.flag("-fno-stack-protector");
+ cfg.flag("-ffreestanding");
+ cfg.flag("-fexceptions");
+
+ // easiest way to undefine since no API available in cc::Build to undefine
+ cfg.flag("-U_FORTIFY_SOURCE");
+ cfg.define("_FORTIFY_SOURCE", "0");
+ cfg.define("RUST_SGX", "1");
+ cfg.define("__NO_STRING_INLINES", None);
+ cfg.define("__NO_MATH_INLINES", None);
+ cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+ cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+ cfg.define("NDEBUG", None);
+ }
}
- let mut unwind_sources = vec![
- "Unwind-EHABI.cpp",
- "Unwind-seh.cpp",
+ let mut c_sources = vec![
"Unwind-sjlj.c",
"UnwindLevel1-gcc-ext.c",
"UnwindLevel1.c",
"UnwindRegistersRestore.S",
"UnwindRegistersSave.S",
- "libunwind.cpp",
];
- if target_vendor == "apple" {
- unwind_sources.push("Unwind_AppleExtras.cpp");
- }
+ let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
+ let cpp_len = cpp_sources.len();
if target.contains("x86_64-fortanix-unknown-sgx") {
- unwind_sources.push("UnwindRustSgx.c");
+ c_sources.push("UnwindRustSgx.c");
}
- let root = Path::new("../../src/llvm-project/libunwind");
- cfg.include(root.join("include"));
- for src in unwind_sources {
- cfg.file(root.join("src").join(src));
+ for src in c_sources {
+ cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}
- if target_env == "musl" {
- // use the same C compiler command to compile C++ code so we do not need to setup the
- // C++ compiler env variables on the builders
- cfg.cpp(false);
- // linking for musl is handled in lib.rs
- cfg.cargo_metadata(false);
- println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
+ for src in cpp_sources {
+ cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}
- cfg.compile("unwind");
+ let out_dir = env::var("OUT_DIR").unwrap();
+ println!("cargo:rustc-link-search=native={}", &out_dir);
+
+ cpp_cfg.compile("unwind-cpp");
+
+ let mut count = 0;
+ for entry in std::fs::read_dir(&out_dir).unwrap() {
+ let obj = entry.unwrap().path().canonicalize().unwrap();
+ if let Some(ext) = obj.extension() {
+ if ext == "o" {
+ cc_cfg.object(&obj);
+ count += 1;
+ }
+ }
+ }
+ assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+ cc_cfg.compile("unwind");
}
}
}
#[cfg(target_env = "musl")]
-#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
-#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
-extern "C" {}
+cfg_if::cfg_if! {
+ if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+ compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
+ } else if #[cfg(feature = "llvm-libunwind")] {
+ #[link(name = "unwind", kind = "static")]
+ extern "C" {}
+ } else if #[cfg(feature = "system-llvm-libunwind")] {
+ #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+ #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ } else {
+ #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
+ #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ }
+}
// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
// glibc needs it, and needs it listed later on the linker command line. We
extern "C" {}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[link(name = "unwind", kind = "static-nobundle")]
+#[link(name = "unwind", kind = "static")]
extern "C" {}
filetime = "0.2"
num_cpus = "1.0"
getopts = "0.2.19"
-cc = "1.0.67"
+cc = "1.0.68"
libc = "0.2"
serde = { version = "1.0.8", features = ["derive"] }
serde_json = "1.0.2"
).decode(default_encoding).splitlines()]
filtered_submodules = []
submodules_names = []
+ llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
+ external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
+ llvm_needed = not self.get_toml('codegen-backends', 'rust') \
+ or "llvm" in self.get_toml('codegen-backends', 'rust')
for module in submodules:
- # This is handled by native::Llvm in rustbuild, not here
if module.endswith("llvm-project"):
- continue
+ # Don't sync the llvm-project submodule if an external LLVM was
+ # provided, if we are downloading LLVM or if the LLVM backend is
+ # not being built. Also, if the submodule has been initialized
+ # already, sync it anyways so that it doesn't mess up contributor
+ # pull requests.
+ if external_llvm_provided or not llvm_needed:
+ if self.get_toml('lld') != 'true' and not llvm_checked_out:
+ continue
check = self.check_submodule(module, slow_submodules)
filtered_submodules.append((module, check))
submodules_names.append(module)
recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
cwd=self.rust_root, stdout=subprocess.PIPE)
recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
- # { filename: hash }
recorded_submodules = {}
for data in recorded:
- # [mode, kind, hash, filename]
data = data.split()
recorded_submodules[data[3]] = data[2]
for module in filtered_submodules:
tool::Rustfmt,
tool::Miri,
tool::CargoMiri,
- native::Lld
+ native::Lld,
+ native::CrtBeginEnd
),
Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
check::Std,
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
}
+ /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable.
+ pub fn doc_rust_lang_org_channel(&self) -> String {
+ let channel = match &*self.config.channel {
+ "stable" => &self.version,
+ "beta" => "beta",
+ "nightly" | "dev" => "nightly",
+ // custom build of rustdoc maybe? link to the latest stable docs just in case
+ _ => "stable",
+ };
+ "https://doc.rust-lang.org/".to_owned() + channel
+ }
+
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
StepDescription::run(v, self, paths);
}
return;
}
- add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
+ let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
+
+ // Ensure that the downloaded LLVM libraries can be found.
+ if self.config.llvm_from_ci {
+ let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+ dylib_dirs.push(ci_llvm_lib);
+ }
+
+ add_dylib_path(dylib_dirs, cmd);
}
/// Gets a path to the compiler specified.
DependencyType::TargetSelfContained,
);
}
+ let crt_path = builder.ensure(native::CrtBeginEnd { target });
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
- let src = compiler_file(builder, builder.cc(target), target, obj);
+ let src = crt_path.join(obj);
let target = libdir_self_contained.join(obj);
builder.copy(&src, &target);
target_deps.push((target, DependencyType::TargetSelfContained));
if target.contains("riscv") {
cargo.rustflag("-Cforce-unwind-tables=yes");
}
+
+ let html_root =
+ format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);
+ cargo.rustflag(&html_root);
+ cargo.rustdocflag(&html_root);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
cargo
.arg("-p")
.arg(package)
+ .arg("-Zskip-rustdoc-fingerprint")
.arg("--")
.arg("--markdown-css")
.arg("rust.css")
cargo.rustdocflag("-Znormalize-docs");
cargo.rustdocflag("--show-type-layout");
compile::rustc_cargo(builder, &mut cargo, target);
+ cargo.arg("-Zskip-rustdoc-fingerprint");
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
&[],
);
+ cargo.arg("-Zskip-rustdoc-fingerprint");
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
cargo.arg("-p").arg("rustdoc");
slice::from_ref(&self.build.triple)
}
- /// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
- /// contributors checking in a submodule change by accident.
- pub fn maybe_update_llvm_submodule(&self) {
- if self.in_tree_llvm_info.is_git() {
- native::update_llvm_submodule(self);
- }
- }
-
/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
unsafe {
job::setup(self);
}
- self.maybe_update_llvm_submodule();
-
if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(self, *check, &paths);
}
eprintln!(
"
Couldn't find required command: ninja
-You should install ninja, or set ninja=false in config.toml
+You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section.
"
);
std::process::exit(1);
src/tools/cargo \
src/tools/cargotest \
$(BOOTSTRAP_ARGS)
-check-aux-and-gui: check-aux
- $(Q)$(BOOTSTRAP) test --stage 2 \
- src/test/rustdoc-gui \
- $(BOOTSTRAP_ARGS)
check-bootstrap:
$(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
dist:
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::TargetSelection;
use crate::util::{self, exe};
-use crate::{Build, GitRepo};
+use crate::GitRepo;
use build_helper::up_to_date;
pub struct Meta {
Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
}
-// modified from `check_submodule` and `update_submodule` in bootstrap.py
-pub(crate) fn update_llvm_submodule(build: &Build) {
- let llvm_project = &Path::new("src").join("llvm-project");
-
- fn dir_is_empty(dir: &Path) -> bool {
- t!(std::fs::read_dir(dir)).next().is_none()
- }
-
- // NOTE: The check for the empty directory is here because when running x.py
- // the first time, the llvm submodule won't be checked out. Check it out
- // now so we can build it.
- if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
- return;
- }
-
- // check_submodule
- let checked_out = if build.config.fast_submodules {
- Some(output(
- Command::new("git")
- .args(&["rev-parse", "HEAD"])
- .current_dir(build.config.src.join(llvm_project)),
- ))
- } else {
- None
- };
-
- // update_submodules
- let recorded = output(
- Command::new("git")
- .args(&["ls-tree", "HEAD"])
- .arg(llvm_project)
- .current_dir(&build.config.src),
- );
- let hash =
- recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
-
- // update_submodule
- if let Some(llvm_hash) = checked_out {
- if hash == llvm_hash {
- // already checked out
- return;
- }
- }
-
- println!("Updating submodule {}", llvm_project.display());
- build.run(
- Command::new("git")
- .args(&["submodule", "-q", "sync"])
- .arg(llvm_project)
- .current_dir(&build.config.src),
- );
-
- // Try passing `--progress` to start, then run git again without if that fails.
- let update = |progress: bool| {
- let mut git = Command::new("git");
- git.args(&["submodule", "update", "--init", "--recursive"]);
- if progress {
- git.arg("--progress");
- }
- git.arg(llvm_project).current_dir(&build.config.src);
- git
- };
- // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
- if !update(true).status().map_or(false, |status| status.success()) {
- build.run(&mut update(false));
- }
-
- build.run(
- Command::new("git")
- .args(&["reset", "-q", "--hard"])
- .current_dir(build.config.src.join(llvm_project)),
- );
- build.run(
- Command::new("git")
- .args(&["clean", "-qdfx"])
- .current_dir(build.config.src.join(llvm_project)),
- );
-}
-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Llvm {
pub target: TargetSelection,
Err(m) => m,
};
- if !builder.config.dry_run {
- update_llvm_submodule(builder);
- }
if builder.config.llvm_link_shared
&& (target.contains("windows") || target.contains("apple-darwin"))
{
.define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
- if target != "aarch64-apple-darwin" {
+ if target != "aarch64-apple-darwin" && !target.contains("windows") {
cfg.define("LLVM_ENABLE_ZLIB", "ON");
} else {
cfg.define("LLVM_ENABLE_ZLIB", "OFF");
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
}
}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CrtBeginEnd {
+ pub target: TargetSelection,
+}
+
+impl Step for CrtBeginEnd {
+ type Output = PathBuf;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("src/llvm-project/compiler-rt/lib/crt")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(CrtBeginEnd { target: run.target });
+ }
+
+ /// Build crtbegin.o/crtend.o for musl target.
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let out_dir = builder.native_dir(self.target).join("crt");
+
+ if builder.config.dry_run {
+ return out_dir;
+ }
+
+ let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
+ let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
+ if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o"))
+ && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
+ {
+ return out_dir;
+ }
+
+ builder.info("Building crtbegin.o and crtend.o");
+ t!(fs::create_dir_all(&out_dir));
+
+ let mut cfg = cc::Build::new();
+
+ if let Some(ar) = builder.ar(self.target) {
+ cfg.archiver(ar);
+ }
+ cfg.compiler(builder.cc(self.target));
+ cfg.cargo_metadata(false)
+ .out_dir(&out_dir)
+ .target(&self.target.triple)
+ .host(&builder.config.build.triple)
+ .warnings(false)
+ .debug(false)
+ .opt_level(3)
+ .file(crtbegin_src)
+ .file(crtend_src);
+
+ // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
+ // Currently only consumer of those objects is musl, which use .init_array/.fini_array
+ // instead of .ctors/.dtors
+ cfg.flag("-std=c11")
+ .define("CRT_HAS_INITFINI_ARRAY", None)
+ .define("EH_USE_FRAME_REGISTRY", None);
+
+ cfg.compile("crt");
+
+ t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o")));
+ t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o")));
+ out_dir
+ }
+}
SourceType::Submodule,
&[],
);
+ cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").arg("miri").arg("setup");
// Tell `cargo miri setup` where to find the sources.
SourceType::Submodule,
&[],
);
+ cargo.add_rustc_lib_path(builder, compiler);
// miri tests need to know about the stage sysroot
cargo.env("MIRI_SYSROOT", miri_sysroot);
cargo.arg("--").args(builder.config.cmd.test_args());
- cargo.add_rustc_lib_path(builder, compiler);
-
let mut cargo = Command::from(cargo);
if !try_run(builder, &mut cargo) {
return;
}
}
+fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool {
+ let mut command = Command::new(&npm);
+ command.arg("list").arg("--depth=0");
+ if global {
+ command.arg("--global");
+ }
+ let lines = command
+ .output()
+ .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
+ .unwrap_or(String::new());
+ lines.contains(&" browser-ui-test@")
+}
+
+fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool {
+ check_if_browser_ui_test_is_installed_global(npm, false)
+ || check_if_browser_ui_test_is_installed_global(npm, true)
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocGUI {
pub target: TargetSelection,
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-gui")
+ let builder = run.builder;
+ let run = run.path("src/test/rustdoc-gui");
+ run.default_condition(
+ builder.config.nodejs.is_some()
+ && builder
+ .config
+ .npm
+ .as_ref()
+ .map(|p| check_if_browser_ui_test_is_installed(p))
+ .unwrap_or(false),
+ )
}
fn make_run(run: RunConfig<'_>) {
}
fn run(self, builder: &Builder<'_>) {
- if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) {
- builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
-
- // The goal here is to check if the necessary packages are installed, and if not, we
- // display a warning and move on.
- let mut command = Command::new(&npm);
- command.arg("list").arg("--depth=0");
- let lines = command
- .output()
- .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
- .unwrap_or(String::new());
- if !lines.contains(&" browser-ui-test@") {
- println!(
- "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
- dependency is missing",
- );
- println!(
- "If you want to install the `{0}` dependency, run `npm install {0}`",
- "browser-ui-test",
- );
- return;
- }
+ let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
+ let npm = builder.config.npm.as_ref().expect("npm isn't available");
- let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+ builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
- // We remove existing folder to be sure there won't be artifacts remaining.
- let _ = fs::remove_dir_all(&out_dir);
+ // The goal here is to check if the necessary packages are installed, and if not, we
+ // panic.
+ if !check_if_browser_ui_test_is_installed(&npm) {
+ eprintln!(
+ "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
+ dependency is missing",
+ );
+ eprintln!(
+ "If you want to install the `{0}` dependency, run `npm install {0}`",
+ "browser-ui-test",
+ );
+ panic!("Cannot run rustdoc-gui tests");
+ }
- // We generate docs for the libraries present in the rustdoc-gui's src folder.
- let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
- for entry in libs_dir.read_dir().expect("read_dir call failed") {
- let entry = entry.expect("invalid entry");
- let path = entry.path();
- if path.extension().map(|e| e == "rs").unwrap_or(false) {
- let mut command = builder.rustdoc_cmd(self.compiler);
- command.arg(path).arg("-o").arg(&out_dir);
- builder.run(&mut command);
- }
- }
+ let out_dir = builder.test_out(self.target).join("rustdoc-gui");
- // We now run GUI tests.
- let mut command = Command::new(&nodejs);
- command
- .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
- .arg("--doc-folder")
- .arg(out_dir)
- .arg("--tests-folder")
- .arg(builder.build.src.join("src/test/rustdoc-gui"));
- builder.run(&mut command);
- } else {
- builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests");
+ // We remove existing folder to be sure there won't be artifacts remaining.
+ let _ = fs::remove_dir_all(&out_dir);
+
+ let mut nb_generated = 0;
+ // We generate docs for the libraries present in the rustdoc-gui's src folder.
+ let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
+ for entry in libs_dir.read_dir().expect("read_dir call failed") {
+ let entry = entry.expect("invalid entry");
+ let path = entry.path();
+ if path.extension().map(|e| e == "rs").unwrap_or(false) {
+ let mut command = builder.rustdoc_cmd(self.compiler);
+ command.arg(path).arg("-o").arg(&out_dir);
+ builder.run(&mut command);
+ nb_generated += 1;
+ }
}
+ assert!(nb_generated > 0, "no documentation was generated...");
+
+ // We now run GUI tests.
+ let mut command = Command::new(&nodejs);
+ command
+ .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
+ .arg("--doc-folder")
+ .arg(out_dir)
+ .arg("--tests-folder")
+ .arg(builder.build.src.join("src/test/rustdoc-gui"));
+ builder.run(&mut command);
}
}
}
}
cmd.env("RUSTC_BOOTSTRAP", "1");
+ cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
builder.add_rust_test_threads(&mut cmd);
if builder.config.sanitizers_enabled(target) {
if tool == "tidy" {
tool = "rust-tidy";
}
- let cargo_out =
- builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
- let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
+ let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
+ let bin = builder.tools_dir(compiler).join(exe(tool, target));
builder.copy(&cargo_out, &bin);
Some(bin)
}
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
cargo.env("CFG_VERSION", builder.rust_version());
cargo.env("CFG_RELEASE_NUM", &builder.version);
+ cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
let info = GitInfo::new(builder.config.ignore_git, &dir);
if let Some(sha) = info.sha() {
}
/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
+/// If The dylib_path_par is already set for this cmd, the old value will be overwritten!
pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
let mut list = dylib_path();
for path in path {
}
}
-#[track_caller]
pub fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
# riscv targets currently do not need a C compiler, as compiler_builtins
# doesn't currently have it enabled, and the riscv gcc compiler is not
# installed.
-ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
+ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \
+ CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
+ CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \
+ CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a" \
+ CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \
CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \
CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \
+ AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+ CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+ CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-8 \
CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-8 \
AR_x86_64_fortanix_unknown_sgx=ar \
COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/
RUN /tmp/build-fuchsia-toolchain.sh
COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/
-RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386
-RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 pc
+# Build deprecated target 'x86_64-sun-solaris2.10' until removed
+RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 sun
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun
COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
ENV TARGETS=$TARGETS,wasm32-wasi
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
ENV TARGETS=$TARGETS,x86_64-pc-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
ARCH=$1
LIB_ARCH=$2
APT_ARCH=$3
+MANUFACTURER=$4
BINUTILS=2.28.1
GCC=6.5.0
-# Choose correct target based on the $ARCH
-case "$ARCH" in
-x86_64)
- TARGET=x86_64-pc-solaris2.10
- ;;
-sparcv9)
- TARGET=sparcv9-sun-solaris2.10
- ;;
-*)
- printf 'ERROR: unknown architecture: %s\n' "$ARCH"
- exit 1
-esac
+TARGET=${ARCH}-${MANUFACTURER}-solaris2.10
# First up, build binutils
mkdir binutils
# Install es-check
# Pin its version to prevent unrelated CI failures due to future es-check versions.
RUN npm install es-check@5.2.3 -g
+RUN npm install eslint@7.20.0 -g
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
python3 ../x.py doc --stage 0 library/test && \
/scripts/validate-toolstate.sh && \
# Runs checks to ensure that there are no ES5 issues in our JS code.
- es-check es5 ../src/librustdoc/html/static/*.js
+ es-check es5 ../src/librustdoc/html/static/*.js && \
+ eslint ../src/librustdoc/html/static/*.js
libgl1-mesa-dev \
llvm-dev \
libfreetype6-dev \
- libexpat1-dev \
- libexpat1-dev \
- gnupg \
- apt-utils \
- wget \
- fonts-ipafont-gothic \
- fonts-wqy-zenhei \
- fonts-thai-tlwg \
- fonts-kacst \
- fonts-freefont-ttf \
- libxss1 \
- libxtst6
-
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
-
-# Install required dependencies from browser-UI-test framework
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-RUN npm install browser-ui-test -g --unsafe-perm=true
+ libexpat1-dev
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
RUN /scripts/cmake.sh
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
-ENV RUST_CHECK_TARGET check-aux-and-gui
+ENV RUST_CHECK_TARGET check-aux
cmake \
libssl-dev \
sudo \
- xz-utils \
- pkg-config
+ xz-utils
+
+# Install dependencies for chromium browser
+RUN apt-get install -y \
+ gconf-service \
+ libasound2 \
+ libatk1.0-0 \
+ libatk-bridge2.0-0 \
+ libc6 \
+ libcairo2 \
+ libcups2 \
+ libdbus-1-3 \
+ libexpat1 \
+ libfontconfig1 \
+ libgcc1 \
+ libgconf-2-4 \
+ libgdk-pixbuf2.0-0 \
+ libglib2.0-0 \
+ libgtk-3-0 \
+ libnspr4 \
+ libpango-1.0-0 \
+ libpangocairo-1.0-0 \
+ libstdc++6 \
+ libx11-6 \
+ libx11-xcb1 \
+ libxcb1 \
+ libxcomposite1 \
+ libxcursor1 \
+ libxdamage1 \
+ libxext6 \
+ libxfixes3 \
+ libxi6 \
+ libxrandr2 \
+ libxrender1 \
+ libxss1 \
+ libxtst6 \
+ fonts-liberation \
+ libappindicator1 \
+ libnss3 \
+ lsb-release \
+ xdg-utils \
+ wget
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
+RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
+ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
+
+# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
+# to create a new folder. For reference:
+# 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.2.12 --unsafe-perm=true
+
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py
+
+ENV SCRIPT /tmp/checktools.sh ../x.py && \
+ NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
# There is not an easy blanket search for subtrees. For now, manually list
# the subtrees.
echo "Executing the job since clippy or rustfmt subtree was updated"
+elif ! (git diff --quiet "$BASE_COMMIT" -- \
+ src/test/rustdoc-gui \
+ src/librustdoc \
+ src/tools/rustdoc-gui); then
+ # There was a change in either rustdoc or in its GUI tests.
+ echo "Executing the job since rustdoc was updated"
else
echo "Not executing this job since no submodules nor subtrees were updated"
ciCommandSetEnv SKIP_JOB 1
-Subproject commit 1da3c411f17adb1ba5de1683bb6acee83362b54a
+Subproject commit 302a115e8f71876dfc884aebb0ca5ccb02b8a962
-Subproject commit 569c3391f5c0cc43433bc77831d17f8ff4d76602
+Subproject commit 7349d173fa28a0bb834cf0264a05286620ef0923
-Subproject commit 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a7
+Subproject commit 9c68af3ce6ccca2395e1868addef26a0542e9ddd
-Subproject commit 5f8c6da200ada77760a2fe1096938ef58151c9a6
+Subproject commit 805e016c5792ad2adabb66e348233067d5ea9f10
-Subproject commit 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447f
+Subproject commit 50de7f0682adc5d95ce858fe6318d19b4b951553
- [JSON Output](json.md)
- [Tests](tests/index.md)
- [Platform Support](platform-support.md)
+ - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
- [Target Tier Policy](target-tier-policy.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
target | std | host | notes
-------|:---:|:----:|-------
`aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64
-`aarch64-apple-ios-sim` | ? | | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | | Apple iOS Simulator on ARM64
`aarch64-apple-tvos` | * | | ARM64 tvOS
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
`aarch64-unknown-hermit` | ? | |
--- /dev/null
+# aarch64-apple-ios-sim
+
+**Tier: 3**
+
+Apple iOS Simulator on ARM64.
+
+## Designated Developers
+
+* [@badboy](https://github.com/badboy)
+* [@deg4uss3r](https://github.com/deg4uss3r)
+
+## Requirements
+
+This target is cross-compiled.
+To build this target Xcode 12 or higher on macOS is required.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["aarch64-apple-ios-sim"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
+
+Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+
+## Building Rust programs
+
+*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
+
+If `rustc` has support for that target and the library artifacts are available,
+then Rust programs can be built for that target:
+
+```text
+rustc --target aarch64-apple-ios-sim your-code.rs
+```
+
+On Rust Nightly it is possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-apple-ios-sim
+```
+
+There is no easy way to run simple programs in the iOS simulator.
+Static library builds can be embedded into iOS applications.
`lib.rs` to test your README as part of your doctests:
```rust,no_run
-#![feature(external_doc)]
-
-#[doc(include = "../README.md")]
+#[doc = include_str!("../README.md")]
#[cfg(doctest)]
pub struct ReadmeDoctests;
```
```md
- [x] Complete task
-- [ ] IncComplete task
+- [ ] Incomplete task
```
-This will render as
+This will render as:
-<ul>
- <li><input type="checkbox"></li>
- <li><input type="checkbox" checked></li>
-</ul>
+> - [x] Complete task
+> - [ ] Incomplete task
See the specification for the [task list extension] for more details.
[unstable-masked]: ../unstable-book/language-features/doc-masked.html
[issue-masked]: https://github.com/rust-lang/rust/issues/44027
-### Include external files as API documentation
-
-As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
-is useful if certain documentation is so long that it would break the flow of reading the source.
-Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to
-instead read that file and use it as if it were written inline.
-
-[RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
-
-`#[doc(include = "...")]` currently requires the `#![feature(external_doc)]` feature gate. For more
-information, see [its chapter in the Unstable Book][unstable-include] and [its tracking
-issue][issue-include].
-
-[unstable-include]: ../unstable-book/language-features/external-doc.html
-[issue-include]: https://github.com/rust-lang/rust/issues/44732
-
## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
--- /dev/null
+# `force-warns`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
+++ /dev/null
-# `external_doc`
-
-The tracking issue for this feature is: [#44732]
-
-The `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to
-include external files in documentation. Use the attribute in place of, or in addition to, regular
-doc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders
-documentation for your crate.
-
-With the following files in the same directory:
-
-`external-doc.md`:
-
-```markdown
-# My Awesome Type
-
-This is the documentation for this spectacular type.
-```
-
-`lib.rs`:
-
-```no_run (needs-external-files)
-#![feature(external_doc)]
-
-#[doc(include = "external-doc.md")]
-pub struct MyAwesomeType;
-```
-
-`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`
-struct.
-
-When locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the
-`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,
-start your paths with `../docs/` for `rustdoc` to properly find the file.
-
-This feature was proposed in [RFC #1990] and initially implemented in PR [#44781].
-
-[#44732]: https://github.com/rust-lang/rust/issues/44732
-[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990
-[#44781]: https://github.com/rust-lang/rust/pull/44781
+++ /dev/null
-# `member_constraints`
-
-The tracking issue for this feature is: [#61997]
-
-[#61997]: https://github.com/rust-lang/rust/issues/61997
-
-------------------------
-
-The `member_constraints` feature gate lets you use `impl Trait` syntax with
-multiple unrelated lifetime parameters.
-
-A simple example is:
-
-```rust
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- (x, y)
-}
-
-fn main() { }
-```
-
-Without the `member_constraints` feature gate, the above example is an
-error because both `'a` and `'b` appear in the impl Trait bounds, but
-neither outlives the other.
unichr = chr
+channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+
class CustomHTMLParser(HTMLParser):
"""simplified HTML parser.
def normalize_xpath(path):
+ path = path.replace("{{channel}}", channel)
if path.startswith('//'):
return '.' + path # avoid warnings
elif path.startswith('.//'):
def check_string(data, pat, regexp):
+ pat = pat.replace("{{channel}}", channel)
if not pat:
return True # special case a presence testing
elif regexp:
<Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic>
</Expand>
</Type>
+ <Type Name="enum$<*>">
+ <Intrinsic Name="tag" Expression="variant0.variant$" />
+ <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
+
+ <Expand>
+ <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
+ <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
+ <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
+ <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
+ <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
+ <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
+ <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
+ <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
+ <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
+ <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
+ <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
+ <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
+ <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
+ <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
+ <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
+ <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag,
+ $T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant -->
+ <Type Name="enum$<*, *, *, *>">
+ <Intrinsic Name="tag" Expression="discriminant" />
+ <Intrinsic Name="is_dataful" Expression="tag() >= $T2 && tag() <= $T3" />
+ <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
+ <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
+ <Expand>
+ <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
+ <Synthetic Condition="is_dataful()" Name="[variant]">
+ <DisplayString>{"$T4",sb}</DisplayString>
+ </Synthetic>
+ </Expand>
+ </Type>
</AutoVisualizer>
</Expand>
</Type>
- <Type Name="core::option::Option<*>">
- <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
- <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
- <Expand>
- <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
- </Expand>
- </Type>
-
<Type Name="core::option::Option<*>" Priority="MediumLow">
<DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
<DisplayString>Some({($T1 *)this})</DisplayString>
</Expand>
</Type>
- <Type Name="core::result::Result<*>">
- <DisplayString Condition="RUST$ENUM$DISR == 0x0">Ok({__0})</DisplayString>
- <DisplayString Condition="RUST$ENUM$DISR == 0x1">Err({(*($T2*) &__0)})</DisplayString>
- <Expand>
- <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x0">__0</Item>
- <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x1">(*($T2*) &__0)</Item>
- </Expand>
- </Type>
-
<Type Name="core::ptr::non_null::NonNull<*>">
<DisplayString>{(void*) pointer}</DisplayString>
<Expand>
}
WherePredicate::EqPredicate { lhs, rhs } => {
match lhs {
- Type::QPath { name: left_name, ref self_type, ref trait_ } => {
+ Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
let ty = &*self_type;
match **trait_ {
Type::ResolvedPath {
}
fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
- let imported_from = cx.tcx.original_crate_name(did.krate);
+ let imported_from = cx.tcx.crate_name(did.krate);
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
LoadedMacro::MacroDef(def, _) => {
let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
self_type: box clean::Generic(ref s),
trait_: box clean::ResolvedPath { did, .. },
name: ref _name,
+ ..
},
ref bounds,
} => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
GenericBound::TraitBound(t, _) => t.trait_,
GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
};
+ let self_type = self.self_ty().clean(cx);
Type::QPath {
name: cx.tcx.associated_item(self.item_def_id).ident.name,
- self_type: box self.self_ty().clean(cx),
+ self_def_id: self_type.def_id(),
+ self_type: box self_type,
trait_: box trait_,
}
}
.filter_map(|pred| {
let (name, self_type, trait_, bounds) = match *pred {
WherePredicate::BoundPredicate {
- ty: QPath { ref name, ref self_type, ref trait_ },
+ ty: QPath { ref name, ref self_type, ref trait_, .. },
ref bounds,
} => (name, self_type, trait_, bounds),
_ => return None,
let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
let trait_segments = &segments[..segments.len() - 1];
+ let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
let trait_path = self::Path {
global: p.is_global(),
- res: Res::Def(
- DefKind::Trait,
- cx.tcx.associated_item(p.res.def_id()).container.id(),
- ),
+ res: Res::Def(DefKind::Trait, trait_def),
segments: trait_segments.clean(cx),
};
Type::QPath {
name: p.segments.last().expect("segments were empty").ident.name,
+ self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path, hir_id),
}
let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
Type::QPath {
name: segment.ident.name,
+ self_def_id: res.opt_def_id(),
self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path, hir_id),
}
format!("{}/std/", s.trim_end_matches('/'))
}
Some(ExternalLocation::Unknown) | None => {
- "https://doc.rust-lang.org/nightly/std/".to_string()
+ format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
}
};
// This is a primitive so the url is done "by hand".
crate fn is_crate(&self) -> bool {
self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
}
-
crate fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
}
// #[doc(...)]
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
for item in list {
- // #[doc(include)]
+ // #[doc(hidden)]
if !item.has_name(sym::cfg) {
continue;
}
SugaredDoc,
/// A doc fragment created from a "raw" `#[doc=""]` attribute.
RawDoc,
- /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
- /// given filename and the file contents.
- Include { filename: Symbol },
}
// The goal of this function is to apply the `DocFragment` transformations that are required when
where
T: IntoIterator<Item = &'a DocFragment>,
{
- let mut prev_kind: Option<DocFragmentKind> = None;
iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty()
- && prev_kind
- .take()
- .map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
- .unwrap_or(false)
- {
- acc.push('\n');
- }
add_doc_fragment(&mut acc, &frag);
- prev_kind = Some(frag.kind);
acc
})
}
self.other_attrs.lists(name)
}
- /// Reads a `MetaItem` from within an attribute, looks for whether it is a
- /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
- /// its expansion.
- crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
- mi.meta_item_list().and_then(|list| {
- for meta in list {
- if meta.has_name(sym::include) {
- // the actual compiled `#[doc(include="filename")]` gets expanded to
- // `#[doc(include(file="filename", contents="file contents")]` so we need to
- // look for that instead
- return meta.meta_item_list().and_then(|list| {
- let mut filename: Option<Symbol> = None;
- let mut contents: Option<Symbol> = None;
-
- for it in list {
- if it.has_name(sym::file) {
- if let Some(name) = it.value_str() {
- filename = Some(name);
- }
- } else if it.has_name(sym::contents) {
- if let Some(docs) = it.value_str() {
- contents = Some(docs);
- }
- }
- }
-
- if let (Some(filename), Some(contents)) = (filename, contents) {
- Some((filename, contents))
- } else {
- None
- }
- });
- }
- }
-
- None
- })
- }
-
crate fn has_doc_flag(&self, flag: Symbol) -> bool {
for attr in &self.other_attrs {
if !attr.has_name(sym::doc) {
let mut doc_strings: Vec<DocFragment> = vec![];
let mut doc_line = 0;
- fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
+ fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
if let Some(prev) = doc_strings.last_mut() {
- if matches!(prev.kind, DocFragmentKind::Include { .. })
- || prev.kind != frag.kind
- || prev.parent_module != frag.parent_module
- {
- // add a newline for extra padding between segments
- prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
- || prev.kind == DocFragmentKind::RawDoc
- } else {
- prev.need_backline = true;
- }
+ prev.need_backline = true;
}
}
indent: 0,
};
- update_need_backline(&mut doc_strings, &frag);
+ update_need_backline(&mut doc_strings);
doc_strings.push(frag);
None
} else {
- if attr.has_name(sym::doc) {
- if let Some(mi) = attr.meta() {
- if let Some((filename, contents)) = Attributes::extract_include(&mi) {
- let line = doc_line;
- doc_line += contents.as_str().lines().count();
- let frag = DocFragment {
- line,
- span: attr.span,
- doc: contents,
- kind: DocFragmentKind::Include { filename },
- parent_module,
- need_backline: false,
- indent: 0,
- };
- update_need_backline(&mut doc_strings, &frag);
- doc_strings.push(frag);
- }
- }
- }
Some(attr.clone())
}
};
let mut out = String::new();
add_doc_fragment(&mut out, &ori);
while let Some(new_frag) = iter.next() {
- if matches!(ori.kind, DocFragmentKind::Include { .. })
- || new_frag.kind != ori.kind
- || new_frag.parent_module != ori.parent_module
- {
+ if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
break;
}
add_doc_fragment(&mut out, &new_frag);
QPath {
name: Symbol,
self_type: Box<Type>,
+ self_def_id: Option<DefId>,
trait_: Box<Type>,
},
crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
let (self_, trait_, name) = match self {
- QPath { self_type, trait_, name } => (self_type, trait_, name),
+ QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
_ => return None,
};
let trait_did = match **trait_ {
}
}
- crate fn as_str(&self) -> &'static str {
- use self::PrimitiveType::*;
- match *self {
- Isize => "isize",
- I8 => "i8",
- I16 => "i16",
- I32 => "i32",
- I64 => "i64",
- I128 => "i128",
- Usize => "usize",
- U8 => "u8",
- U16 => "u16",
- U32 => "u32",
- U64 => "u64",
- U128 => "u128",
- F32 => "f32",
- F64 => "f64",
- Str => "str",
- Bool => "bool",
- Char => "char",
- Array => "array",
- Slice => "slice",
- Tuple => "tuple",
- Unit => "unit",
- RawPointer => "pointer",
- Reference => "reference",
- Fn => "fn",
- Never => "never",
- }
- }
-
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
}
})
}
- crate fn to_url_str(&self) -> &'static str {
- self.as_str()
- }
-
crate fn as_sym(&self) -> Symbol {
use PrimitiveType::*;
match self {
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
- MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
+ Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
Type::BorrowedRef { lifetime, mutability, type_ } => {
Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
}
- Type::QPath { name, self_type, trait_ } => Type::QPath {
+ Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath {
name,
+ self_def_id,
self_type: Box::new(strip_type(*self_type)),
trait_: Box::new(strip_type(*trait_)),
},
auto_impls.into_iter().chain(blanket_impls)
}
+/// If `res` has a documentation page associated, store it in the cache.
+///
+/// This is later used by [`href()`] to determine the HTML link for the item.
+///
+/// [`href()`]: crate::html::format::href
crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
+ use DefKind::*;
debug!("register_res({:?})", res);
let (did, kind) = match res {
- Res::Def(DefKind::Fn, i) => (i, ItemType::Function),
- Res::Def(DefKind::TyAlias, i) => (i, ItemType::Typedef),
- Res::Def(DefKind::Enum, i) => (i, ItemType::Enum),
- Res::Def(DefKind::Trait, i) => (i, ItemType::Trait),
Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+ // associated items are documented, but on the page of their parent
(cx.tcx.parent(i).unwrap(), ItemType::Trait)
}
- Res::Def(DefKind::Struct, i) => (i, ItemType::Struct),
- Res::Def(DefKind::Union, i) => (i, ItemType::Union),
- Res::Def(DefKind::Mod, i) => (i, ItemType::Module),
- Res::Def(DefKind::ForeignTy, i) => (i, ItemType::ForeignType),
- Res::Def(DefKind::Const, i) => (i, ItemType::Constant),
- Res::Def(DefKind::Static, i) => (i, ItemType::Static),
Res::Def(DefKind::Variant, i) => {
+ // variant items are documented, but on the page of their parent
(cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
}
- Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
- MacroKind::Bang => (i, ItemType::Macro),
- MacroKind::Attr => (i, ItemType::ProcAttribute),
- MacroKind::Derive => (i, ItemType::ProcDerive),
- },
- Res::Def(DefKind::TraitAlias, i) => (i, ItemType::TraitAlias),
- Res::SelfTy(Some(def_id), _) => (def_id, ItemType::Trait),
- Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
- _ => return res.def_id(),
+ // Each of these have their own page.
+ Res::Def(
+ kind
+ @
+ (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
+ | Macro(..) | TraitAlias),
+ i,
+ ) => (i, kind.into()),
+ // This is part of a trait definition; document the trait.
+ Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait),
+ // This is an inherent impl; it doesn't have its own page.
+ Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id,
+ Res::SelfTy(None, None)
+ | Res::PrimTy(_)
+ | Res::ToolMod
+ | Res::SelfCtor(_)
+ | Res::Local(_)
+ | Res::NonMacroAttr(_)
+ | Res::Err => return res.def_id(),
+ Res::Def(
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
+ | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ id,
+ ) => return id,
};
if did.is_local() {
return did;
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
})
}
+
+/// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links
+/// 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");
use std::str::FromStr;
use rustc_data_structures::fx::FxHashMap;
-use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
-use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options};
+use rustc_session::config::{
+ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
+};
+use rustc_session::config::{get_cmd_lint_options, nightly_options};
use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
use rustc_session::getopts;
use rustc_session::lint::Level;
return Err(0);
}
- if matches.opt_strs("print").iter().any(|opt| opt == "unversioned-files") {
- for file in crate::html::render::FILES_UNVERSIONED.keys() {
- println!("{}", file);
- }
- return Err(0);
- }
-
let color = config::parse_color(&matches);
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
config::parse_json(&matches);
}
}
- let target =
- matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| {
- if target.ends_with(".json") {
- TargetTriple::TargetPath(PathBuf::from(target))
- } else {
- TargetTriple::TargetTriple(target)
- }
- });
+ let target = parse_target_triple(matches, error_format);
let show_coverage = matches.opt_present("show-coverage");
let generate_redirect_map = matches.opt_present("generate-redirect-map");
let show_type_layout = matches.opt_present("show-type-layout");
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, _) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
Ok(Options {
input,
// By default, rustdoc ignores all lints.
// Specifically unblock lints relevant to documentation or the lint machinery itself.
let mut lints_to_show = vec![
- // it's unclear whether this should be part of rustdoc directly (#77364)
+ // it's unclear whether these should be part of rustdoc directly (#77364)
rustc_lint::builtin::MISSING_DOCS.name.to_string(),
+ rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(),
// these are definitely not part of rustdoc, but we want to warn on them anyway.
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
- let help = "The following guide may be of use:\n\
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
+ let help = format!(
+ "The following guide may be of use:\n\
+ {}/rustdoc/how-to-write-documentation.html",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
tcx.struct_lint_node(
crate::lint::MISSING_CRATE_LEVEL_DOCS,
DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
|lint| {
let mut diag =
lint.build("no documentation found for this crate's top-level module");
- diag.help(help);
+ diag.help(&help);
diag.emit();
},
);
use rustc_target::spec::abi::Abi;
use crate::clean::{
- self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+ self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, GetDefId, PrimitiveType,
};
use crate::formats::item_type::ItemType;
use crate::html::escape::Escape;
f,
"<a class=\"primitive\" href=\"{}primitive.{}.html\">",
"../".repeat(len),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
f,
"<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
loc.join("/"),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
fmt::Display::fmt(&tybounds(param_names, cx), f)
}
clean::Infer => write!(f, "_"),
- clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cx),
+ clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(
write!(f, "impl {}", print_generic_bounds(bounds, cx))
}
}
- clean::QPath { ref name, ref self_type, ref trait_ } => {
+ clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
let should_show_cast = match *trait_ {
box clean::ResolvedPath { ref path, .. } => {
- !path.segments.is_empty() && !self_type.is_self_type()
+ !path.segments.is_empty()
+ && self_def_id
+ .zip(trait_.def_id())
+ .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
}
_ => true,
};
{sidebar}\
</nav>\
<div class=\"theme-picker\">\
- <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
+ <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
<img src=\"{static_root_path}brush{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Pick another theme!\">\
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
type=\"search\">\
</div>\
- <button type=\"button\" id=\"help-button\">?</button>
- <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+ <button type=\"button\" id=\"help-button\" title=\"help\">?</button>
+ <a id=\"settings-menu\" href=\"{root_path}settings.html\" title=\"settings\">\
<img src=\"{static_root_path}wheel{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Change settings\">\
{after_content}\
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
data-search-index-js=\"{root_path}search-index{suffix}.js\" \
- data-search-js=\"{static_root_path}search{suffix}.js\"></div>
+ data-search-js=\"{static_root_path}search{suffix}.js\"></div>\
<script src=\"{static_root_path}main{suffix}.js\"></script>\
{extra_scripts}\
</body>\
<html lang="en">
<head>
<meta http-equiv="refresh" content="0;URL={url}">
+ <title>Redirection</title>
</head>
<body>
<p>Redirecting to <a href="{url}">{url}</a>...</p>
)
};
let keywords = make_item_keywords(it);
+ let name;
+ let tyname_s = if it.is_crate() {
+ name = format!("{} crate", tyname);
+ name.as_str()
+ } else {
+ tyname.as_str()
+ };
let page = layout::Page {
- css_class: tyname.as_str(),
+ css_class: tyname_s,
root_path: &self.root_path(),
static_root_path: self.shared.static_root_path.as_deref(),
title: &title,
mod write_shared;
crate use context::*;
-crate use write_shared::FILES_UNVERSIONED;
use std::collections::VecDeque;
use std::default::Default;
})
})
.map(|item| format!("{}.{}", item.type_(), name));
- write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\">",
+ id, item_type, in_trait_class,
+ );
w.write_str("<code>");
render_assoc_item(
w,
);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write_srclink(cx, item, w);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
}
clean::TypedefItem(ref tydef, _) => {
let source_id = format!("{}.{}", ItemType::AssocType, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+ id, item_type, in_trait_class
+ );
assoc_type(
w,
item,
);
w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::AssocConstItem(ref ty, ref default) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+ id, item_type, in_trait_class
+ );
assoc_const(
w,
item,
);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write_srclink(cx, item, w);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::AssocTypeItem(ref bounds, ref default) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(w, "<div id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class,);
assoc_type(
w,
item,
);
w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::StrippedItem(..) => return,
_ => panic!("can't make docs for trait item with name {:?}", item.name),
}
}
let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
- let open_details = |close_tags: &mut String| {
+ let open_details = |close_tags: &mut String, is_collapsed: bool| {
if toggled {
close_tags.insert_str(0, "</details>");
- "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
+ if is_collapsed {
+ "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
+ } else {
+ "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+ }
} else {
""
}
};
if render_mode == RenderMode::Normal {
+ let is_implementing_trait;
let id = cx.derive_id(match i.inner_impl().trait_ {
Some(ref t) => {
+ is_implementing_trait = true;
if is_on_foreign_type {
get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
} else {
format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
}
}
- None => "impl".to_string(),
+ None => {
+ is_implementing_trait = false;
+ "impl".to_string()
+ }
});
let aliases = if aliases.is_empty() {
String::new()
if let Some(use_absolute) = use_absolute {
write!(
w,
- "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
- open_details(&mut close_tags),
+ "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\
+ <code class=\"in-band\">",
+ open_details(&mut close_tags, is_implementing_trait),
id,
aliases
);
} else {
write!(
w,
- "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
- open_details(&mut close_tags),
+ "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\
+ <code class=\"in-band\">{}</code>",
+ open_details(&mut close_tags, is_implementing_trait),
id,
aliases,
i.inner_impl().print(false, cx)
);
write_srclink(cx, &i.impl_item, w);
if !toggled {
- w.write_str("</h3>");
+ w.write_str("</div>");
} else {
- w.write_str("</h3></summary>");
+ w.write_str("</div></summary>");
}
if trait_.is_some() {
);
}
}
- if toggled {
+ if !default_impl_items.is_empty() || !impl_items.is_empty() {
w.write_str("<div class=\"impl-items\">");
w.push_buffer(default_impl_items);
- if trait_.is_some() && !impl_items.is_empty() {
- w.write_str("<details class=\"undocumented\"><summary></summary>");
- close_tags.insert_str(0, "</details>");
- }
w.push_buffer(impl_items);
close_tags.insert_str(0, "</div>");
}
"<div class=\"block version\">\
<p>Version {}</p>\
</div>",
- Escape(version)
+ Escape(version),
);
}
}
write!(
buffer,
"<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
- it.name.as_ref().expect("crates always have a name")
+ it.name.as_ref().expect("crates always have a name"),
);
}
+
match *it.kind {
clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
- _ => (),
+ _ => {}
}
// The sidebar is designed to display sibling functions, modules and
// as much HTML as possible in order to allow non-JS-enabled browsers
// to navigate the documentation (though slightly inefficiently).
- buffer.write_str("<p class=\"location\">");
- for (i, name) in cx.current.iter().take(parentlen).enumerate() {
- if i > 0 {
- buffer.write_str("::<wbr>");
+ if !it.is_mod() {
+ buffer.write_str("<p class=\"location\">Other items in<br>");
+ for (i, name) in cx.current.iter().take(parentlen).enumerate() {
+ if i > 0 {
+ buffer.write_str("::<wbr>");
+ }
+ write!(
+ buffer,
+ "<a href=\"{}index.html\">{}</a>",
+ &cx.root_path()[..(cx.current.len() - i - 1) * 3],
+ *name
+ );
}
- write!(
- buffer,
- "<a href=\"{}index.html\">{}</a>",
- &cx.root_path()[..(cx.current.len() - i - 1) * 3],
- *name
- );
+ buffer.write_str("</p>");
}
- buffer.write_str("</p>");
// Sidebar refers to the enclosing module, not this module.
- let relpath = if it.is_mod() { "../" } else { "" };
+ let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
write!(
buffer,
"<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
ty = it.type_(),
path = relpath
);
-
- if parentlen == 0 {
- write!(
- buffer,
- "<script defer src=\"{}sidebar-items{}.js\"></script>",
- relpath, cx.shared.resource_suffix
- );
- } else {
- write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
- }
-
+ write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
// Closes sidebar-elems div.
buffer.write_str("</div>");
}
}
}
-fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
- match *ty {
+fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
+ match ty {
ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
let mut sidebar = String::new();
+ // Re-exports are handled a bit differently because they can be extern crates or imports.
if items.iter().any(|it| {
- it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+ it.name.is_some()
+ && (it.type_() == ItemType::ExternCrate
+ || (it.type_() == ItemType::Import && !it.is_stripped()))
}) {
- sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
+ let (id, name) = item_ty_to_strs(ItemType::Import);
+ sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
}
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
ItemType::ForeignType,
ItemType::Keyword,
] {
- if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
- let (short, name) = item_ty_to_strs(&myty);
- sidebar.push_str(&format!(
- "<li><a href=\"#{id}\">{name}</a></li>",
- id = short,
- name = name
- ));
+ if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
+ let (id, name) = item_ty_to_strs(myty);
+ sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
}
}
);
}
}
- write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
+ write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap());
write!(
buf,
- "<button id=\"copy-path\" onclick=\"copy_path(this)\">\
+ "<button id=\"copy-path\" onclick=\"copy_path(this)\" title=\"copy path\">\
<img src=\"{static_root_path}clipboard{suffix}.svg\" \
width=\"19\" height=\"18\" \
- alt=\"Copy item import\">\
+ alt=\"Copy item import\" \
+ title=\"Copy item import to clipboard\">\
</button>",
static_root_path = page.get_static_root_path(),
suffix = page.resource_suffix,
w.write_str("</table>");
}
curty = myty;
- let (short, name) = item_ty_to_strs(&myty.unwrap());
+ let (short, name) = item_ty_to_strs(myty.unwrap());
write!(
w,
"<h2 id=\"{id}\" class=\"section-header\">\
info!("Documenting {} on {:?}", name, t.name);
let item_type = m.type_();
let id = cx.derive_id(format!("{}.{}", item_type, name));
- write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
- write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
+ let mut content = Buffer::empty_from(w);
+ document(&mut content, cx, m, Some(t));
+ let toggled = !content.is_empty();
+ if toggled {
+ write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
+ }
+ write!(w, "<div id=\"{}\" class=\"method has-srclink\"><code>", id);
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
w.write_str("</code>");
render_stability_since(w, m, t, cx.tcx());
write_srclink(cx, m, w);
- w.write_str("</h3></summary>");
- document(w, cx, m, Some(t));
+ w.write_str("</div>");
+ if toggled {
+ write!(w, "</summary>");
+ w.push_buffer(content);
+ write!(w, "</details>");
+ }
}
if !types.is_empty() {
w.write_str(
"Non-exhaustive structs could have additional fields added in future. \
Therefore, non-exhaustive structs cannot be constructed in external crates \
- using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
+ using the traditional <code>Struct { .. }</code> syntax; cannot be \
matched against without a wildcard <code>..</code>; and \
struct update syntax will not work.",
);
use crate::error::Error;
use crate::html::{layout, static_files};
-crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
+static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
map! {
"FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
"FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
"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-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR,
+ "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
"COPYRIGHT.txt" => static_files::COPYRIGHT,
)?;
write_minify("search.js", static_files::SEARCH_JS)?;
write_minify("settings.js", static_files::SETTINGS_JS)?;
- write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?;
if cx.shared.include_sources {
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
}
}());
- function addSidebarCrates(crates) {
- // Draw a convenient sidebar of known crates if we have a listing
- if (window.rootPath === "../" || window.rootPath === "./") {
- var sidebar = document.getElementsByClassName("sidebar-elems")[0];
- if (sidebar) {
- var div = document.createElement("div");
- div.className = "block crate";
- div.innerHTML = "<h3>Crates</h3>";
- var ul = document.createElement("ul");
- div.appendChild(ul);
-
- for (var i = 0; i < crates.length; ++i) {
- var klass = "crate";
- if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
- klass += " current";
- }
- var link = document.createElement("a");
- link.href = window.rootPath + crates[i] + "/index.html";
- link.className = klass;
- link.textContent = crates[i];
-
- var li = document.createElement("li");
- li.appendChild(link);
- ul.appendChild(li);
- }
- sidebar.appendChild(div);
- }
- }
- }
-
// delayed sidebar rendering.
window.initSidebarItems = function(items) {
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
var current = window.sidebarCurrent;
+ function addSidebarCrates(crates) {
+ if (!hasClass(document.body, "crate")) {
+ // We only want to list crates on the crate page.
+ return;
+ }
+ // Draw a convenient sidebar of known crates if we have a listing
+ var div = document.createElement("div");
+ div.className = "block crate";
+ div.innerHTML = "<h3>Crates</h3>";
+ var ul = document.createElement("ul");
+ div.appendChild(ul);
+
+ for (var i = 0; i < crates.length; ++i) {
+ var klass = "crate";
+ if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
+ klass += " current";
+ }
+ var link = document.createElement("a");
+ link.href = window.rootPath + crates[i] + "/index.html";
+ link.className = klass;
+ link.textContent = crates[i];
+
+ var li = document.createElement("li");
+ li.appendChild(link);
+ ul.appendChild(li);
+ }
+ sidebar.appendChild(div);
+ }
+
function block(shortty, longty) {
var filtered = items[shortty];
if (!filtered) {
ul.appendChild(li);
}
div.appendChild(ul);
- if (sidebar) {
- sidebar.appendChild(div);
- }
+ sidebar.appendChild(div);
}
- block("primitive", "Primitive Types");
- block("mod", "Modules");
- block("macro", "Macros");
- block("struct", "Structs");
- block("enum", "Enums");
- block("union", "Unions");
- block("constant", "Constants");
- block("static", "Statics");
- block("trait", "Traits");
- block("fn", "Functions");
- block("type", "Type Definitions");
- block("foreigntype", "Foreign Types");
- block("keyword", "Keywords");
- block("traitalias", "Trait Aliases");
-
- // `crates{version}.js` should always be loaded before this script, so we can use it safely.
- addSidebarCrates(window.ALL_CRATES);
+ if (sidebar) {
+ var isModule = hasClass(document.body, "mod");
+ if (!isModule) {
+ block("primitive", "Primitive Types");
+ block("mod", "Modules");
+ block("macro", "Macros");
+ block("struct", "Structs");
+ block("enum", "Enums");
+ block("union", "Unions");
+ block("constant", "Constants");
+ block("static", "Statics");
+ block("trait", "Traits");
+ block("fn", "Functions");
+ block("type", "Type Definitions");
+ block("foreigntype", "Foreign Types");
+ block("keyword", "Keywords");
+ block("traitalias", "Trait Aliases");
+ }
+
+ // `crates{version}.js` should always be loaded before this script, so we can use
+ // it safely.
+ addSidebarCrates(window.ALL_CRATES);
+ }
};
window.register_implementors = function(imp) {
--- /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.
font-display: swap;
}
+/* Avoid using legacy CJK serif fonts in Windows like Batang */
+@font-face {
+ font-family: 'Noto Sans KR';
+ src: url("noto-sans-kr-v13-korean-regular.woff") format("woff");
+ font-display: swap;
+ unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;
+}
+
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif 4", serif;
+ font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
h3 {
font-size: 1.3em;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h1, h2, h3, h4 {
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
h1.fqn > .in-band > a:hover {
text-decoration: underline;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h2, h3, h4 {
border-bottom: 1px solid;
}
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
+.impl, .method,
+.type, .associatedconstant,
+.associatedtype {
flex-basis: 100%;
font-weight: 600;
margin-top: 16px;
margin-bottom: 10px;
position: relative;
}
-h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
+.impl, .method.trait-impl,
+.type.trait-impl,
+.associatedconstant.trait-impl,
+.associatedtype.trait-impl {
padding-left: 15px;
}
+div.impl-items > div {
+ padding-left: 0;
+}
+
h1, h2, h3, h4,
.sidebar, a.source, .search-input, .search-results .result-name,
-div.item-list .out-of-band,
+.content table td:first-child > a,
+div.item-list .out-of-band, span.since,
#source-sidebar, #sidebar-toggle,
details.rustdoc-toggle > summary::before,
details.undocumented > summary::before,
-.content ul.crate a.crate,
+div.impl-items > div:not(.docblock):not(.item-info),
+.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;
border: none;
}
-.location a:first-child {
+.location a:first-of-type {
font-weight: 500;
}
+.location a:hover {
+ text-decoration: underline;
+}
.block {
padding: 0;
margin-bottom: 14px;
}
.block h2, .block h3 {
- margin-top: 0;
- margin-bottom: 8px;
text-align: center;
}
.block ul, .block li {
font-weight: normal;
}
-h3.impl > .out-of-band {
- font-size: 21px;
-}
-
-h4.method > .out-of-band {
- font-size: 19px;
-}
-
-h4 > code, h3 > code, .invisible > code {
+.method > code, .trait-impl > code, .invisible > code {
max-width: calc(100% - 41px);
display: block;
}
}
.content .multi-column li { width: 100%; display: inline-block; }
-.content .method {
+.content > .methods > .method {
font-size: 1em;
position: relative;
}
font-size: 0.8em;
}
-.content .methods > div:not(.notable-traits):not(.methods) {
+.content .methods > div:not(.notable-traits):not(.method) {
margin-left: 40px;
margin-bottom: 15px;
}
margin-left: 20px;
margin-top: -34px;
}
-.content .docblock > .impl-items > h4 {
- border-bottom: 0;
-}
.content .docblock >.impl-items .table-display {
margin: 0;
}
text-decoration: underline;
}
-.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink {
+.invisible > .srclink,
+.method > code + .srclink {
position: absolute;
top: 0;
right: 0;
.search-results.active {
display: block;
+ /* prevent overhanging tabs from moving the first result */
+ clear: both;
}
-.search-results .desc {
+.search-results .desc > span {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
}
-.search-results a {
+.search-results > a {
+ display: block;
+ width: 100%;
/* A little margin ensures the browser's outlining of focused links has room to display. */
margin-left: 2px;
margin-right: 2px;
- display: block;
+ border-bottom: 1px solid #aaa3;
}
-.result-name {
- width: 50%;
- float: left;
+.search-results > a > div {
+ display: flex;
+ flex-flow: row wrap;
}
-.result-name span.primitive::after {
- content: ' (primitive type)';
- font-style: italic;
+.search-results .result-name, .search-results div.desc, .search-results .result-description {
+ width: 50%;
+}
+.search-results .result-name {
+ padding-right: 1em;
}
-.result-name span.keyword::after {
- content: ' (keyword)';
- font-style: italic;
+.search-results .result-name > span {
+ display: inline-block;
}
body.blur > :not(#help) {
flex-grow: 1;
}
-.impl-items h4, h4.impl, h3.impl, .methods h3 {
+.has-srclink {
display: flex;
flex-basis: 100%;
font-size: 16px;
margin: 0;
}
+.notable-traits .notable {
+ margin: 0;
+ margin-bottom: 13px;
+ font-size: 19px;
+ font-weight: 600;
+}
+
.notable-traits .docblock code.content{
margin: 0;
padding: 0;
margin-left: 5px;
}
-h4 > .notable-traits {
- position: absolute;
- left: -44px;
- top: 2px;
-}
-
#all-types {
text-align: center;
border: 1px solid;
border-top: 1px solid;
}
-
-
-h3.notable {
- margin: 0;
- margin-bottom: 13px;
- font-size: 19px;
-}
-
kbd {
display: inline-block;
padding: 3px 5px;
details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
left: -23px;
- top: initial;
+ top: 3px;
}
.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- top: 3px;
left: -2px;
}
padding: 0;
}
- .content h4 > .out-of-band {
- position: inherit;
- }
-
#search {
margin-left: 0;
}
z-index: 1;
}
- h4 > .notable-traits {
+ .notable-traits {
position: absolute;
left: -22px;
top: 24px;
.search-container > div {
width: calc(100% - 32px);
}
+
+ /* Display an alternating layout on tablets and phones */
+ .search-results > a {
+ border-bottom: 1px solid #aaa9;
+ padding: 5px 0px;
+ }
+ .search-results .result-name, .search-results div.desc, .search-results .result-description {
+ width: 100%;
+ }
+ .search-results div.desc, .search-results .result-description {
+ padding-left: 2em;
+ }
}
@media print {
extraClass = " active";
}
- var output = "";
+ var output = document.createElement("div");
var duplicates = {};
var length = 0;
if (array.length > 0) {
- output = "<div class=\"search-results " + extraClass + "\">";
+ output.className = "search-results " + extraClass;
array.forEach(function(item) {
- var name, type;
-
- name = item.name;
- type = itemTypes[item.ty];
-
if (item.is_alias !== true) {
if (duplicates[item.fullPath]) {
return;
}
duplicates[item.fullPath] = true;
}
+
+ var name = item.name;
+ var type = itemTypes[item.ty];
+
length += 1;
- output += "<a class=\"result-" + type + "\" href=\"" + item.href + "\">" +
- "<div><div class=\"result-name\">" +
- (item.is_alias === true ?
- ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
- "class=\"grey\"><i> - see </i></span>") : "") +
- item.displayPath + "<span class=\"" + type + "\">" +
- name + "</span></div><div>" +
- "<span class=\"desc\">" + item.desc +
- " </span></div></div></a>";
+ var extra = "";
+ if (type === "primitive") {
+ extra = " <i>(primitive type)</i>";
+ } else if (type === "keyword") {
+ extra = " <i>(keyword)</i>";
+ }
+
+ var link = document.createElement("a");
+ link.className = "result-" + type;
+ link.href = item.href;
+
+ var wrapper = document.createElement("div");
+ var resultName = document.createElement("div");
+ resultName.className = "result-name";
+
+ if (item.is_alias) {
+ var alias = document.createElement("span");
+ alias.className = "alias";
+
+ var bold = document.createElement("b");
+ bold.innerText = item.alias;
+ alias.appendChild(bold);
+
+ alias.insertAdjacentHTML(
+ "beforeend",
+ "<span class=\"grey\"><i> - see </i></span>");
+
+ resultName.appendChild(alias);
+ }
+ resultName.insertAdjacentHTML(
+ "beforeend",
+ item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
+ wrapper.appendChild(resultName);
+
+ var description = document.createElement("div");
+ description.className = "desc";
+ var spanDesc = document.createElement("span");
+ spanDesc.innerText = item.desc + "\u00A0";
+
+ description.appendChild(spanDesc);
+ wrapper.appendChild(description);
+ link.appendChild(wrapper);
+ output.appendChild(link);
});
- output += "</div>";
} else {
- output = "<div class=\"search-failed\"" + extraClass + ">No results :(<br/>" +
+ output.className = "search-failed" + extraClass;
+ output.innerHTML = "No results :(<br/>" +
"Try on <a href=\"https://duckduckgo.com/?q=" +
encodeURIComponent("rust " + query.query) +
"\">DuckDuckGo</a>?<br/><br/>" +
"href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
"introductions to language features and the language itself.</li><li><a " +
"href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
- " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
+ " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
}
return [output, length];
}
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
- "</div><div id=\"results\">" +
- ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
+ "</div>";
+
+ var resultsElem = document.createElement("div");
+ resultsElem.id = "results";
+ resultsElem.appendChild(ret_others[0]);
+ resultsElem.appendChild(ret_in_args[0]);
+ resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output;
+ search.appendChild(resultsElem);
// Reset focused elements.
searchState.focusedByTab = [null, null, null];
searchState.showResults(search);
+++ /dev/null
-initSidebarItems({});
color: #c5c5c5;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: white;
}
h1.fqn {
h1.fqn a {
color: #fff;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #5c6773;
}
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4 {
border: none;
}
border-color: #5c6773;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #5c6773;
+}
+
#titles > button.selected {
background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
background-color: rgba(70, 70, 70, 0.33);
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #c5c5c5;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #999;
}
color: #ddd;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: #ddd;
}
h1.fqn {
border-bottom-color: #d2d2d2;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #d2d2d2;
}
border-color: #777;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #d2d2d2;
+}
+
#titles > button:not(.selected) {
background-color: #252525;
border-top-color: #252525;
background-color: #606060;
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #fff;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #ccc;
}
color: black;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: black;
}
h1.fqn {
border-bottom-color: #D5D5D5;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #DDDDDD;
}
border-color: #999;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #DDDDDD;
+}
+
#titles > button:not(.selected) {
background-color: #e6e6e6;
border-top-color: #e6e6e6;
background-color: #f9f9f9;
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #000;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #999;
}
crate static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
}
+crate mod noto_sans_kr {
+ /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR
+ /// font.
+ crate static REGULAR: &[u8] = include_bytes!("static/noto-sans-kr-v13-korean-regular.woff");
+
+ /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR
+ /// font.
+ crate static LICENSE: &[u8] =
+ include_bytes!("static/noto-sans-kr-v13-korean-regular-LICENSE.txt");
+}
+
/// Files related to the sidebar in rustdoc sources.
crate mod sidebar {
/// File script to handle sidebar.
crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
-
- /// Top Level sidebar items script which will load a sidebar without items.
- crate static ITEMS: &str = include_str!("static/sidebar-items.js");
}
.unwrap_or_default(),
},
Generic(s) => Type::Generic(s.to_string()),
- Primitive(p) => Type::Primitive(p.as_str().to_string()),
+ Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
- QPath { name, self_type, trait_ } => Type::QualifiedPath {
+ QPath { name, self_type, trait_, .. } => Type::QualifiedPath {
name: name.to_string(),
self_type: Box::new((*self_type).into_tcx(tcx)),
trait_: Box::new((*trait_).into_tcx(tcx)),
#![feature(box_syntax)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(test)]
#![feature(crate_visibility_modifier)]
#![feature(never_type)]
use rustc_session::getopts;
use rustc_session::{early_error, early_warn};
+use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+
/// A macro to create a FxHashMap.
///
/// Example:
"LEVEL",
)
}),
+ unstable("force-warns", |o| {
+ o.optopt(
+ "",
+ "force-warns",
+ "Lints that will warn even if allowed somewhere else",
+ "LINTS",
+ )
+ }),
unstable("index-page", |o| {
o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
}),
"Generate JSON file at the top level instead of generating HTML redirection files",
)
}),
- unstable("print", |o| {
- o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]")
- }),
unstable("emit", |o| {
o.optmulti(
"",
}
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
println!(" @path Read newline separated options from `path`\n");
- println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
+ println!(
+ "More information available at {}/rustdoc/what-is-rustdoc.html",
+ DOC_RUST_LANG_ORG_CHANNEL
+ );
}
/// A result type used by several functions under `main()`.
}
}
- fn name(self, tcx: TyCtxt<'_>) -> String {
+ fn name(self, tcx: TyCtxt<'_>) -> Symbol {
match self {
- Res::Def(_, id) => tcx.item_name(id).to_string(),
- Res::Primitive(prim) => prim.as_str().to_string(),
+ Res::Def(_, id) => tcx.item_name(id),
+ Res::Primitive(prim) => prim.as_sym(),
}
}
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
- let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
+ let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
})
})
AnchorFailure::RustdocAnchorConflict(res),
));
}
- return Ok((res, Some(ty.as_str().to_owned())));
+ return Ok((res, Some(ty.as_sym().to_string())));
}
_ => return Ok((res, extra_fragment.clone())),
}
return None;
}
res = prim;
- fragment = Some(prim.name(self.cx.tcx));
+ fragment = Some(prim.name(self.cx.tcx).to_string());
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
) {
diag_info.link_range = disambiguator_range;
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
- let msg = "see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators";
- diag.note(msg);
+ let msg = format!(
+ "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
+ diag.note(&msg);
});
}
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
use rustc_span;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
&Spanned { span, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
&krate.item,
- self.cx.tcx.crate_name,
+ self.cx.tcx.crate_name(LOCAL_CRATE),
);
// Attach the crate's exported macros to the top-level module.
// In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
# stable release's version number. `date` is the date where the release we're
# bootstrapping off was released.
-date: 2021-04-07
+date: 2021-05-23
rustc: beta
# We use a nightly rustfmt to format the source because it solves some
// min-llvm-version: 12.0.0
-// needs-llvm-components: aarch64 x86
-// revisions:x64 A64
+// needs-llvm-components: aarch64 x86 powerpc
+// revisions: x64 A64 ppc64le
// assembly-output: emit-asm
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
+// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
#![feature(no_core, lang_items)]
#![no_core]
pub fn orange() -> &'static u8 {
&PIERIS
}
+
+// For ppc64 we need to make sure to generate TOC entries even with the static relocation model
+// ppc64le: .tc chaenomeles[TC],chaenomeles
+// ppc64le: .tc banana[TC],banana
+// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA
+// ppc64le: .tc PIERIS[TC],PIERIS
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 12,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 14,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 17,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
--- /dev/null
+// only-cdb
+// ignore-tidy-linelength
+// compile-flags:-g
+
+// cdb-command: g
+
+// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb
+// so the best we can do is to make sure we are generating the right debuginfo
+
+// cdb-command: dx -r2 a,!
+// cdb-check:a,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 b,!
+// cdb-check:b,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 c,!
+// cdb-check:c,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 d,!
+// cdb-check:d,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 e,!
+// cdb-check:e,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 f,!
+// cdb-check:f,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *]
+// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx -r2 g,!
+// cdb-check:g,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *]
+// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx h
+// cdb-check:h : Some [Type: enum$<core::option::Option<u32>>]
+// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option]
+// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int]
+
+// cdb-command: dx i
+// cdb-check:i : None [Type: enum$<core::option::Option<u32>>]
+// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option]
+
+// cdb-command: dx j
+// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx -r2 k,!
+// cdb-check:k,! [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 [Type: alloc::string::String]
+// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
+
+pub enum CStyleEnum {
+ Low = 2,
+ High = 16,
+}
+
+pub enum NicheLayoutEnum {
+ Tag1,
+ Data { my_data: CStyleEnum },
+ Tag2,
+}
+
+fn main() {
+ let a = Some(CStyleEnum::Low);
+ let b = Option::<CStyleEnum>::None;
+ let c = NicheLayoutEnum::Tag1;
+ let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High };
+ let e = NicheLayoutEnum::Tag2;
+ let f = Some(&1u32);
+ let g = Option::<&'static u32>::None;
+ let h = Some(12u32);
+ let i = Option::<u32>::None;
+ let j = CStyleEnum::High;
+ let k = Some("IAMA optional string!".to_string());
+
+ zzz(); // #break
+}
+
+fn zzz() { () }
// ignore-freebsd: gdb package too new
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
+// ignore-tidy-linelength
// compile-flags:-g
// min-gdb-version: 7.7
// min-lldb-version: 310
// NOTE: OsString doesn't have a .natvis entry yet.
// cdb-command: dx some
-// cdb-check:some : Some(8) [Type: [...]::Option<i16>]
+// cdb-check:some : Some [Type: enum$<core::option::Option<i16>>]
// cdb-command: dx none
-// cdb-check:none : None [Type: [...]::Option<i64>]
+// cdb-check:none : None [Type: enum$<core::option::Option<i64>>]
// cdb-command: dx some_string
-// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>]
+// cdb-check:some_string [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
#![allow(unused_variables)]
use std::ffi::OsString;
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_free_fn {
use point::{self, Point};
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
point::distance_squared(&x);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn call_function0() {
a::function0(77);
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn call_function1() {
a::function1(77);
}
pub mod fn_with_type_in_sig {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn boop(p: Option<&Point>) -> f32 {
p.map(|p| p.total()).unwrap_or(0.0)
}
pub mod call_fn_with_type_in_sig {
use fn_with_type_in_sig;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn bip() -> f32 {
fn_with_type_in_sig::boop(None)
}
pub mod fn_with_type_in_body {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn boop() -> f32 {
Point::origin().total()
}
pub mod call_fn_with_type_in_body {
use fn_with_type_in_body;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn bip() -> f32 {
fn_with_type_in_body::boop()
}
pub mod fn_make_struct {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn make_origin(p: Point) -> Point {
Point { ..p }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn dirty() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_changed_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.distance_from_origin();
pub mod fn_calls_another_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.x();
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_changed_method {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.distance_from_point(None);
pub mod fn_calls_another_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.x();
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
// Check that reordering otherwise identical items is not considered a
// change at all.
-#[rustc_clean(label = "hir_crate", cfg = "rpass2")]
+#[rustc_clean(cfg = "rpass2")]
// But removing an item, naturally, is.
-#[rustc_dirty(label = "hir_crate", cfg = "rpass3")]
+#[rustc_clean(except="hir_crate", cfg = "rpass3")]
#[cfg(rpass1)]
pub struct X {
pub x: u32,
mod y {
use x;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig",
+ cfg="cfail2",
+ )]
pub fn y() {
- //[cfail2]~^ ERROR `typeck(y)` should be clean but is not
+ //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not
+ //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not
+ //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `type_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `fn_sig(y)` should be dirty but is not
+ //[cfail2]~| ERROR `typeck(y)` should be clean but is not
x::x();
}
}
mod z {
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck", cfg="cfail2")]
pub fn z() {
//[cfail2]~^ ERROR `typeck(z)` should be dirty but is not
}
#[cfg(not(cfail1))]
use super::callee2 as callee;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-
-
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
pub fn change_callee_indirectly_function() {
callee(1, 2)
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameOfTypeParameter<T> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTypeParameter<S, T> {
Variant1(S),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameOfLifetimeParameter<'b> {
Variant1(&'b u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameter<'a, 'b> {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTraitBound<T: Sync> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTraitBoundWhere<T> where T: Sync {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_function_name2(c: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_parameter_name(d: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_parameter_type(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_return_type(c: i32) -> i8;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_parameter(c: i32, d: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_return_type(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn make_function_variadic(c: i32, ...);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "rust-call" {
pub fn change_calling_convention(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn make_function_public(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_function1(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
#[link(name = "bar")]
extern "C" {
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn indirectly_change_parameter_type(c: c_int);
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn indirectly_change_return_type() -> c_int;
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_simple_index(slice: &[u32]) -> u32 {
slice[4]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_lower_bound(slice: &[u32]) -> &[u32] {
&slice[2..5]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_upper_bound(slice: &[u32]) -> &[u32] {
&slice[3..7]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn add_lower_bound(slice: &[u32]) -> &[u32] {
&slice[3..4]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn add_upper_bound(slice: &[u32]) -> &[u32] {
&slice[3..7]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_mutability(slice: &mut [u32]) -> u32 {
(&slice[3..5])[0]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
&slice[3..=7]
}
#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
- #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
+ #[rustc_clean(
+ cfg="cfail2",
+ except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir",
+ )]
#[rustc_clean(cfg="cfail3")]
pub fn method_selfness(&self) { }
}
pub struct LayoutPacked;
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
#[repr(packed)]
pub struct LayoutPacked;
struct LayoutC;
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
#[repr(C)]
struct LayoutC;
struct TupleStructFieldType(i32);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
// Note that changing the type of a field does not change the type of the struct or enum, but
// adding/removing fields or changing a fields name or visibility does.
struct TupleStructFieldType(
struct TupleStructAddField(i32);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct TupleStructAddField(
i32,
u32
struct TupleStructFieldVisibility(char);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct TupleStructFieldVisibility(pub char);
struct RecordStructFieldType { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
// Note that changing the type of a field does not change the type of the struct or enum, but
// adding/removing fields or changing a fields name or visibility does.
struct RecordStructFieldType {
struct RecordStructFieldName { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructFieldName { y: f32 }
struct RecordStructAddField { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructAddField {
x: f32,
y: () }
struct RecordStructFieldVisibility { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructFieldVisibility {
pub x: f32
}
struct AddLifetimeParameter<'a>(&'a f32, &'a f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64);
struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameterBound<'a, 'b: 'a>(
&'a f32,
&'b f64
struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
&'a f32,
&'b f64)
struct AddTypeParameter<T1>(T1, T1);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameter<T1, T2>(
// The field contains the parent's Generics, so it's dirty even though its
// type hasn't changed.
struct AddTypeParameterBound<T>(T);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameterBound<T: Send>(
T
);
struct AddTypeParameterBoundWhereClause<T>(T);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameterBoundWhereClause<T>(
T
) where T: Sync;
// fingerprint is stable (i.e., that there are no random influences like memory
// addresses taken into account by the hashing algorithm).
// Note: there is no #[cfg(...)], so this is ALWAYS compiled
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub struct EmptyStruct;
struct Visibility;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub struct Visibility;
struct ReferencedType1;
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_clean(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct TupleStruct(
FieldType
);
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_clean(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct RecordStruct {
_x: FieldType
}
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_dirty(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct Struct<T: Trait>(T);
}
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_dirty(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct Struct<T>(T) where T : Trait;
}
trait TraitVisibility { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait TraitVisibility { }
trait TraitUnsafety { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
unsafe trait TraitUnsafety { }
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait TraitAddMethod {
fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodName {
fn methodChanged();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> u32;
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> u64;
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterName {
// FIXME(#38501) This should preferably always be clean.
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(b: u32);
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn with_default(y: i32) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: i64);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterTypeRef {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: &mut i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParametersOrder {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(b: i64, a: i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddMethodAutoImplementation {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeOrderOfMethods {
fn method1();
fn method0();
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfRefToMut {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(&mut self);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToMut: Sized {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToRef {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(&self);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddUnsafeModifier {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
unsafe fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddExternModifier {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
extern "C" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeExternCToRustIntrinsic {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
extern "stdcall" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTypeParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Sized>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToMethodLifetimeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0 + ReferencedTrait1>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Sized + Sync>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
}
#[cfg(cfail1)]
trait TraitAddAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddAssociatedType {
type Associated;
// Apparently the type bound contributes to the predicates of the trait, but
// does not change the associated item itself.
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated: ReferencedTrait0;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToAssociatedType<'a> {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated: 'a;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddDefaultToAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated = ReferenceType0;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddAssociatedConstant {
const Value: u32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddInitializerToAssociatedConstant {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
const Value: u32 = 1;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeTypeOfAssociatedConstant {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
const Value: f64;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
trait TraitAddSuperTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSuperTrait : ReferencedTrait0 { }
trait TraitAddBuiltiBound { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltiBound : Send { }
trait TraitAddStaticLifetimeBound { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticLifetimeBound : 'static { }
trait TraitAddTraitAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
#[cfg(cfail1)]
trait TraitAddTraitAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
#[cfg(cfail1)]
trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
#[cfg(cfail1)]
trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
trait TraitAddTypeParameterToTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTypeParameterToTrait<T> { }
trait TraitAddLifetimeParameterToTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToTrait<'a> { }
trait TraitAddTraitBoundToTypeParameterOfTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
trait TraitAddBuiltinBoundToTypeParameterOfTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
trait TraitAddSecondTypeParameterToTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTypeParameterToTrait<T, S> { }
trait TraitAddSecondLifetimeParameterToTrait<'a> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + ReferencedTrait1> { }
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { }
trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send + Sync> { }
trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { }
trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
where T: ReferencedTrait0 + ReferencedTrait1 { }
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { }
trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { }
#[cfg(not(cfail1))]
use super::ReferenceType1 as ReturnType;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> ReturnType;
}
}
#[cfg(not(cfail1))]
use super::ReferenceType1 as ArgType;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeArgType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: ArgType);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Bound>(a: T);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameterWhere {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T>(a: T) where T: Bound;
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeTraitBound<T: Bound> {
fn method(a: T);
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeTraitBoundWhere<T> where T: Bound {
fn method(a: T);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait ChangeMethodNameTrait {
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name2();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodNameTrait for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name2() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodBodyTrait for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() {
()
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodBodyTraitInlined for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[inline]
fn method_name() {
panic!()
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodSelfnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self) {
()
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl RemoveMethodSelfnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodSelfmutnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeItemKindTrait for Foo {
type name = ();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl RemoveItemTrait for Foo {
type TypeName = ();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddItemTrait for Foo {
type TypeName = ();
fn method_name() { }
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait ChangeHasValueTrait {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() { }
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeHasValueTrait for Foo {
fn method_name() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddDefaultTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
default fn method_name() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddArgumentTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self, _x: u32) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeArgumentTypeTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self, _x: char) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T> AddTypeParameterToImpl<T> for Bar<T> {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn id(t: T) -> T { t }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeSelfTypeOfImpl for u64 {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T: 'static> AddLifetimeBoundToImplParameter for T {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T: Clone> AddTraitBoundToImplParameter for T {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddNoMangleToMethod for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[no_mangle]
fn add_no_mangle_to_method(&self) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl MakeMethodInline for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[inline]
fn make_method_inline(&self) -> u8 { 0 }
}
mod y {
use x;
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
pub fn yyyy() {
x::xxxx();
}
mod z {
use y;
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
pub fn z() {
y::yyyy();
}
}
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")]
#[inline(always)]
pub fn changed_fn() {
// This will cause additional hygiene to be generate,
#[cfg(rpass2)]
use Trait2;
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_dirty(label="typeck", cfg="rpass2")]
+ #[rustc_clean(except="typeck", cfg="rpass2")]
fn bar() {
().method();
}
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
fn baz() {
22; // no method call, traits in scope don't matter
}
#![crate_type = "rlib"]
#![feature(rustc_attrs)]
-#[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-#[rustc_dirty(label = "hir_owner_nodes", cfg = "cfail2")]
+#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")]
pub fn foo() {
#[cfg(cfail1)]
pub fn baz() {} // order is different...
- #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
- #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
+ #[rustc_clean(cfg = "cfail2")]
pub fn bar() {} // but that doesn't matter.
#[cfg(cfail2)]
#[cfg(rpass3)]
use mod2::Foo;
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="hir_owner", cfg="rpass3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+ #[rustc_clean(cfg="rpass2")]
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
fn in_expr() {
Foo(0);
}
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="hir_owner", cfg="rpass3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+ #[rustc_clean(cfg="rpass2")]
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
fn in_type() {
test::<Foo>();
}
--- /dev/null
+// no-prefer-dynamic
+//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
+//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
--- /dev/null
+// aux-build:my_lib.rs
+// error-pattern: error: linking with
+// revisions:cfail1 cfail2
+// compile-flags:-Z query-dep-graph
+
+// Tests that re-ordering the `-l` arguments used
+// when compiling an external dependency does not lead to
+// an 'unstable fingerprint' error.
+
+extern crate my_lib;
+
+fn main() {}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck,optimized_mir", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_X() -> u32 {
let x: a::X = 22;
x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_Y() {
let x: a::Y = 'c';
}
#![feature(rustc_attrs)]
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn line_same() {
let _ = line!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn col_same() {
let _ = column!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn file_same() {
let _ = file!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
fn line_different() {
#[cfg(rpass1)]
{
}
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
fn col_different() {
#[cfg(rpass1)]
{
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub struct SomeType {
pub x: u32,
pub y: i64,
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub struct SomeOtherType {
pub a: i32,
pub b: u64,
pub fn main() {}
#[cfg(rpass2)]
-#[rustc_dirty(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
pub fn main() {}
}
#[cfg(rpass2)]
-#[rustc_dirty(label="optimized_mir", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
pub fn main() {
let _ = 0u8 + 1;
}
}
#[cfg(cfail2)]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_dirty(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")]
pub fn x() {
println!("{}", "2");
}
pub mod y {
use x;
- #[rustc_clean(label="typeck", cfg="cfail2")]
- #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn y() {
x::x();
}
pub mod z {
use y;
- #[rustc_clean(label="typeck", cfg="cfail2")]
- #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn z() {
y::y();
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="fn_sig,typeck", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
//[cfail2]~^ ERROR struct `X` has no field named `x`
//[cfail2]~^ ERROR no field `x` on type `X`
}
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
//[cfail2]~^ ERROR no field `x` on type `X`
}
-#[rustc_clean(label="typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
use a::*;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck,fn_sig", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_X() -> u32 {
let x: a::X = 22;
x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_Y() {
let x: a::Y = 'c';
}
#![allow(warnings)]
#![feature(rustc_attrs)]
-// Sanity check for the dirty-clean system. We add #[rustc_dirty]/#[rustc_clean]
+// Sanity check for the dirty-clean system. We add #[rustc_clean]
// attributes in places that are not checked and make sure that this causes an
// error.
fn main() {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
{
// empty block
}
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
{
// empty block
}
}
struct _Struct {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
_field1: i32,
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
_field2: i32,
}
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + val: Unevaluated(FOO, [], None)
// mir::Constant
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
_1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref.rs:5:6: 5:10
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref.rs:5:6: 5:10
-+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
_1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref_project.rs:5:6: 5:17
- // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
// + val: Unevaluated(bar, [], Some(promoted[1]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:7: 12:9
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
_4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
// + val: Unevaluated(bar, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:11: 12:14
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
_7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(discriminant, [T], Some(promoted[2]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:70:42: 70:44
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45
// + val: Unevaluated(discriminant, [T], Some(promoted[1]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:71:42: 71:45
- // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46
// + val: Unevaluated(discriminant, [T], Some(promoted[0]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:72:42: 72:47
- // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48
// + val: Unevaluated(full_tested_match, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/match_false_edges.rs:16:14: 16:15
- // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[4011]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
_4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
scope 5 {
debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
}
+ scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+ debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ }
}
}
scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
- StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
_10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
_9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
- _8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
+- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ _18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
// mir::Constant
// + span: $DIR/remove_storage_markers.rs:8:14: 8:19
- // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
}
bb2: {
-- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
- _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- }
-
- bb3: {
_0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
}
- bb4: {
+ bb3: {
- StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
_12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
}
+
+ bb4: {
+- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
+ _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+ switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+ }
}
// + val: Unevaluated(array_casts, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[317d]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[13e7]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6
_14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6
// closure
- // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0})
+ // + def_id: DefId(0:14 ~ retag[13e7]::main::{closure#0})
// + substs: [
// i8,
// for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/retag.rs:47:21: 47:23
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[13e7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
_23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23
--- /dev/null
+// Test for issue 85480
+// Pretty print anonymous struct and union types
+
+// pp-exact
+// pretty-compare-only
+
+struct Foo {
+ _: union {
+ _: struct {
+ a: u8,
+ b: u16,
+ },
+ c: u32,
+ },
+ d: u64,
+ e: f32,
+}
+
+type A =
+ struct {
+ field: u8,
+ };
+
+fn main() { }
12| 1| if b {
13| 1| println!("non_async_func println in block");
14| 1| }
+ ^0
15| 1|}
16| |
17| |
5| 1| if true {
6| 1| countdown = 10;
7| 1| }
+ ^0
8| |
9| | const B: u32 = 100;
10| 1| let x = if countdown > 7 {
24| 1| if true {
25| 1| countdown = 10;
26| 1| }
+ ^0
27| |
28| 1| if countdown > 7 {
29| 1| countdown -= 4;
41| 1| if true {
42| 1| countdown = 10;
43| 1| }
+ ^0
44| |
45| 1| if countdown > 7 {
46| 1| countdown -= 4;
53| | } else {
54| 0| return;
55| | }
- 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ 56| 0| }
+ 57| |
58| |
59| 1| let mut countdown = 0;
60| 1| if true {
61| 1| countdown = 1;
62| 1| }
+ ^0
63| |
64| 1| let z = if countdown > 7 {
^0
8| 1|//! assert_eq!(1, 1);
9| |//! } else {
10| |//! // this is not!
- 11| |//! assert_eq!(1, 2);
+ 11| 0|//! assert_eq!(1, 2);
12| |//! }
13| 1|//! ```
14| |//!
74| 1| if true {
75| 1| assert_eq!(1, 1);
76| | } else {
- 77| | assert_eq!(1, 2);
+ 77| 0| assert_eq!(1, 2);
78| | }
79| 1|}
80| |
19| 1| if true {
20| 1| println!("Exiting with error...");
21| 1| return Err(1);
- 22| | }
- 23| |
- 24| | let _ = Firework { strength: 1000 };
- 25| |
- 26| | Ok(())
+ 22| 0| }
+ 23| 0|
+ 24| 0| let _ = Firework { strength: 1000 };
+ 25| 0|
+ 26| 0| Ok(())
27| 1|}
28| |
29| |// Expected program output:
--- /dev/null
+ 1| |#![feature(generators, generator_trait)]
+ 2| |
+ 3| |use std::ops::{Generator, GeneratorState};
+ 4| |use std::pin::Pin;
+ 5| |
+ 6| |// The following implementation of a function called from a `yield` statement
+ 7| |// (apparently requiring the Result and the `String` type or constructor)
+ 8| |// creates conditions where the `generator::StateTransform` MIR transform will
+ 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+ 10| |// to handle this condition, and still report dead block coverage.
+ 11| 1|fn get_u32(val: bool) -> Result<u32, String> {
+ 12| 1| if val { Ok(1) } else { Err(String::from("some error")) }
+ ^0
+ 13| 1|}
+ 14| |
+ 15| 1|fn main() {
+ 16| 1| let is_true = std::env::args().len() == 1;
+ 17| 1| let mut generator = || {
+ 18| 1| yield get_u32(is_true);
+ 19| 1| return "foo";
+ 20| 1| };
+ 21| |
+ 22| 1| match Pin::new(&mut generator).resume(()) {
+ 23| 1| GeneratorState::Yielded(Ok(1)) => {}
+ 24| 0| _ => panic!("unexpected return from resume"),
+ 25| | }
+ 26| 1| match Pin::new(&mut generator).resume(()) {
+ 27| 1| GeneratorState::Complete("foo") => {}
+ 28| 0| _ => panic!("unexpected return from resume"),
+ 29| | }
+ 30| 1|}
+
11| 3| self.strength = new_strength;
12| 3| }
------------------
- | <generics::Firework<f64>>::set_strength:
- | 10| 2| fn set_strength(&mut self, new_strength: T) {
- | 11| 2| self.strength = new_strength;
- | 12| 2| }
- ------------------
| <generics::Firework<i32>>::set_strength:
| 10| 1| fn set_strength(&mut self, new_strength: T) {
| 11| 1| self.strength = new_strength;
| 12| 1| }
+ ------------------
+ | <generics::Firework<f64>>::set_strength:
+ | 10| 2| fn set_strength(&mut self, new_strength: T) {
+ | 11| 2| self.strength = new_strength;
+ | 12| 2| }
------------------
13| |}
14| |
30| 1| if true {
31| 1| println!("Exiting with error...");
32| 1| return Err(1);
- 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal
- 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- 36| | // in other tests, the lines below would have coverage (which would show they had `0`
- 37| | // executions, assuming the condition still evaluated to `true`).
- 38| |
- 39| | let _ = Firework { strength: 1000 };
- 40| |
- 41| | Ok(())
+ 33| 0| }
+ 34| 0|
+ 35| 0|
+ 36| 0|
+ 37| 0|
+ 38| 0|
+ 39| 0| let _ = Firework { strength: 1000 };
+ 40| 0|
+ 41| 0| Ok(())
42| 1|}
43| |
44| |// Expected program output:
9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
10| 1| if true {
11| 1| if false {
- 12| | while true {
- 13| | }
+ 12| 0| while true {
+ 13| 0| }
14| 1| }
- 15| 1| write!(f, "error")?;
- ^0
- 16| | } else {
- 17| | }
+ 15| 1| write!(f, "cool")?;
+ ^0
+ 16| 0| } else {
+ 17| 0| }
18| |
19| 10| for i in 0..10 {
20| 10| if true {
21| 10| if false {
- 22| | while true {}
+ 22| 0| while true {}
23| 10| }
- 24| 10| write!(f, "error")?;
- ^0
- 25| | } else {
- 26| | }
+ 24| 10| write!(f, "cool")?;
+ ^0
+ 25| 0| } else {
+ 26| 0| }
27| | }
28| 1| Ok(())
29| 1| }
34| |impl std::fmt::Display for DisplayTest {
35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36| 1| if false {
- 37| | } else {
+ 37| 0| } else {
38| 1| if false {
- 39| | while true {}
+ 39| 0| while true {}
40| 1| }
- 41| 1| write!(f, "error")?;
- ^0
+ 41| 1| write!(f, "cool")?;
+ ^0
42| | }
43| 10| for i in 0..10 {
44| 10| if false {
- 45| | } else {
+ 45| 0| } else {
46| 10| if false {
- 47| | while true {}
+ 47| 0| while true {}
48| 10| }
- 49| 10| write!(f, "error")?;
- ^0
+ 49| 10| write!(f, "cool")?;
+ ^0
50| | }
51| | }
52| 1| Ok(())
1| 1|fn main() {
2| 1| if false {
- 3| | loop {}
+ 3| 0| loop {}
4| 1| }
5| 1|}
} else {
return;
}
- } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ }
+
let mut countdown = 0;
if true {
--- /dev/null
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `generator::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+ if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+ let mut generator = || {
+ yield get_u32(is_true);
+ return "foo";
+ };
+
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Yielded(Ok(1)) => {}
+ _ => panic!("unexpected return from resume"),
+ }
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Complete("foo") => {}
+ _ => panic!("unexpected return from resume"),
+ }
+}
if true {
println!("Exiting with error...");
return Err(1);
- } // The remaining lines below have no coverage because `if true` (with the constant literal
- // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- // in other tests, the lines below would have coverage (which would show they had `0`
- // executions, assuming the condition still evaluated to `true`).
+ }
+
+
+
+
let _ = Firework { strength: 1000 };
while true {
}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
for i in 0..10 {
if false {
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
}
Ok(())
-#![feature(external_doc)]
-
-#[doc(include="input.md")]
+#[doc = include_str!("input.md")]
pub struct SomeStruct;
pub fn main() {
--- /dev/null
+# only-linux
+# ignore-32bit
+
+-include ../tools.mk
+
+all:
+ $(RUSTC) eh_frame-terminator.rs
+ $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788'
+ objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator'
--- /dev/null
+// run-pass
+
+#![feature(backtrace)]
+#[derive(Clone, Copy)]
+struct Foo {
+ array: [u64; 10240],
+}
+
+impl Foo {
+ const fn new() -> Self {
+ Self {
+ array: [0x1122_3344_5566_7788; 10240]
+ }
+ }
+}
+
+static BAR: [Foo; 10240] = [Foo::new(); 10240];
+
+fn main() {
+ let bt = std::backtrace::Backtrace::force_capture();
+ println!("Hello, world! {:?}", bt);
+ println!("{:x}", BAR[0].array[0]);
+}
--- /dev/null
+# ignore-msvc
+
+-include ../tools.mk
+
+all:
+ $(RUSTC) depa.rs
+ $(RUSTC) depb.rs
+ $(RUSTC) depc.rs
+ $(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"'
+ $(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"'
+ $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"'
+ $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta"'
--- /dev/null
+#![crate_type = "rlib"]
+
+#[link(name = "testa")]
+extern "C" {}
+
+#[link(name = "testa")]
+extern "C" {}
--- /dev/null
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "testb", cfg(foo))]
+extern "C" {}
+
+#[link(name = "testb", cfg(bar))]
+extern "C" {}
--- /dev/null
+#![crate_type = "rlib"]
+
+#[link(name = "testa")]
+extern "C" {}
--- /dev/null
+extern crate depa;
+extern crate depb;
+extern crate depc;
+
+fn main() {}
+++ /dev/null
--include ../tools.mk
-
-all:
- $(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt
+++ /dev/null
-COPYRIGHT.txt
-FiraSans-LICENSE.txt
-FiraSans-Medium.woff
-FiraSans-Medium.woff2
-FiraSans-Regular.woff
-FiraSans-Regular.woff2
-LICENSE-APACHE.txt
-LICENSE-MIT.txt
-SourceCodePro-It.ttf.woff
-SourceCodePro-LICENSE.txt
-SourceCodePro-Regular.ttf.woff
-SourceCodePro-Semibold.ttf.woff
-SourceSerif4-Bold.ttf.woff
-SourceSerif4-It.ttf.woff
-SourceSerif4-LICENSE.md
-SourceSerif4-Regular.ttf.woff
--- /dev/null
+include ../tools.mk
+
+# Test that rustdoc will properly canonicalize the target spec json path just like rustc
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path"
+
+all:
+ $(RUSTC) --crate-type lib dummy_core.rs --target target.json
+ $(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json
--- /dev/null
+#![feature(no_core)]
+#![no_core]
--- /dev/null
+#![feature(no_core)]
+#![no_core]
+extern crate dummy_core;
--- /dev/null
+{
+ "arch": "x86_64",
+ "cpu": "x86-64",
+ "crt-static-respected": true,
+ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+ "dynamic-linking": true,
+ "env": "gnu",
+ "executables": true,
+ "has-elf-tls": true,
+ "has-rpath": true,
+ "is-builtin": true,
+ "linker-is-gnu": true,
+ "llvm-target": "x86_64-unknown-linux-gnu",
+ "max-atomic-width": 64,
+ "os": "linux",
+ "position-independent-executables": true,
+ "pre-link-args": {
+ "gcc": [
+ "-m64"
+ ]
+ },
+ "relro-level": "full",
+ "stack-probes": {
+ "kind": "inline-or-call",
+ "min-llvm-version-for-inline": [
+ 11,
+ 0,
+ 1
+ ]
+ },
+ "supported-sanitizers": [
+ "address",
+ "leak",
+ "memory",
+ "thread"
+ ],
+ "target-family": "unix",
+ "target-pointer-width": "64"
+}
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(associated_type_defaults)]
-#![feature(external_doc)]
extern crate rustc_graphviz;
// A simple rust project
}
}
+#[doc = include_str!("extra-docs.md")]
+struct StructWithDocs;
+
trait Foo {
type Bar = FrameBuffer;
}
-
-#[doc(include = "extra-docs.md")]
-struct StructWithDocs;
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUT=$(TMPDIR)/emit
+
+all: asm llvm-bc llvm-ir obj metadata link dep-info mir
+
+asm: $(OUT)
+ $(RUSTC) --emit asm=$(OUT)/libfoo.s foo.rs
+ test -f $(OUT)/libfoo.s
+llvm-bc: $(OUT)
+ $(RUSTC) --emit llvm-bc=$(OUT)/libfoo.bc foo.rs
+ test -f $(OUT)/libfoo.bc
+llvm-ir: $(OUT)
+ $(RUSTC) --emit llvm-ir=$(OUT)/libfoo.ll foo.rs
+ test -f $(OUT)/libfoo.ll
+obj: $(OUT)
+ $(RUSTC) --emit obj=$(OUT)/libfoo.o foo.rs
+ test -f $(OUT)/libfoo.o
+metadata: $(OUT)
+ $(RUSTC) --emit metadata=$(OUT)/libfoo.rmeta foo.rs
+ test -f $(OUT)/libfoo.rmeta
+link: $(OUT)
+ $(RUSTC) --emit link=$(OUT)/libfoo.rlib foo.rs
+ test -f $(OUT)/libfoo.rlib
+dep-info: $(OUT)
+ $(RUSTC) --emit dep-info=$(OUT)/libfoo.d foo.rs
+ test -f $(OUT)/libfoo.d
+mir: $(OUT)
+ $(RUSTC) --emit mir=$(OUT)/libfoo.mir foo.rs
+ test -f $(OUT)/libfoo.mir
+
+$(OUT):
+ mkdir -p $(OUT)
--- /dev/null
+#![crate_type = "rlib"]
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+SESSION_DIR := $(TMPDIR)/session
+OUTPUT_FILE := $(TMPDIR)/build-output
+
+all:
+ echo $(TMPDIR)
+ # Make it so that rustc will fail to create a session directory.
+ touch $(SESSION_DIR)
+ # Check exit code is 1 for an error, and not 101 for ICE.
+ $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ]
+ $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)
+ # -v tests are fragile, hopefully this text won't change
+ $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE)
--- /dev/null
+// intentionally empty
all:
$(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
+ $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
--- /dev/null
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
+
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/index.html
+// We set the theme so we're sure that the corect values will be used, whatever the computer
+// this test is running on.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// We reload the page so the local storage settings are being used.
+reload:
+write: (".search-input", "thisisanalias")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Checking that the colors for the alias element are the ones expected.
+assert: (".result-name > .alias", {"color": "rgb(255, 255, 255)"})
+assert: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"})
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/index.html
+size: (900, 1000)
+write: (".search-input", "test")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// The width is returned by "getComputedStyle" which returns the exact number instead of the
+// CSS rule which is "50%"...
+assert: (".search-results div.desc", {"width": "320px"})
+size: (600, 100)
+// As counter-intuitive as it may seem, in this width, the width is "100%", which is why
+// when computed it's larger.
+assert: (".search-results div.desc", {"width": "570px"})
// Note: The two next assert commands could be merged as one but readability would be
// less good.
//
-// Checking that the CSS is displaying " (keyword)"...
-assert: (".result-name span.keyword::after", {"content": '" (keyword)"'})
-// ... in italic.
-assert: (".result-name span.keyword::after", {"font-style": "italic"})
+// Checking that the CSS is displaying " (keyword)" in italic.
+assert: (".result-name span.keyword > i", "(keyword)")
+assert: (".result-name span.keyword", "CookieMonster (keyword)")
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/index.html
+assert: (".sidebar > .location", "Crate test_docs")
+// In modules, we only have one "location" element.
+assert: (".sidebar .location", 1)
+assert: (".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: (".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: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Keywords")
+assert: ("#structs + table td > a", "Foo")
+click: "#structs + table td > a"
+
+// PAGE: struct.Foo.html
+assert: (".sidebar .location", 2)
+// We check that there is no crate listed outside of the top level.
+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"
+
+// PAGE: lib2/index.html
+goto: file://|DOC_PATH|/lib2/index.html
+assert: (".sidebar > .location", "Crate lib2")
+// We check that we have the crates list and that the "current" on is now "lib2".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+// We now go to the "foobar" function page.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Functions")
+assert: ("#functions + table td > a", "foobar")
+click: "#functions + table td > a"
+
+// PAGE: fn.foobar.html
+// In items containing no items (like functions or constants) and in modules, we have one
+// "location" elements.
+assert: (".sidebar .location", 1)
+// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
+assert: (".sidebar .sidebar-elems .location", "Other items inlib2")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./module/index.html
+assert: (".sidebar > .location", "Module module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./sub_module/sub_sub_module/index.html
+assert: (".sidebar > .location", "Module sub_sub_module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert: ("#functions + table td > a", "foo")
}
/// Just a normal enum.
+#[doc(alias = "ThisIsAnAlias")]
pub enum WhoLetTheDogOut {
/// Woof!
Woof,
--- /dev/null
+pub mod module {
+ pub mod sub_module {
+ pub mod sub_sub_module {
+ pub fn foo() {}
+ }
+ pub fn bar() {}
+ }
+ pub fn whatever() {}
+}
+
+pub fn foobar() {}
// check-pass
// compile-flags: -Z unstable-options --check
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![warn(missing_docs)]
//~^ WARN
warning: missing documentation for the crate
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:4:9
+ --> $DIR/check.rs:5:9
|
LL | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: missing documentation for a function
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^
warning: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
warning: missing code example in this documentation
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
warning: missing code example in this documentation
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
--- /dev/null
+// check-pass
+
+#[doc(include = "external-cross-doc.md")]
+//~^ WARNING unknown `doc` attribute `include`
+//~| HELP use `doc = include_str!` instead
+// FIXME(#85497): make this a deny instead so it's more clear what's happening
+//~| NOTE on by default
+//~| WARNING previously accepted
+//~| NOTE see issue #82730
+pub struct NeedMoreDocs;
--- /dev/null
+warning: unknown `doc` attribute `include`
+ --> $DIR/doc-include-suggestion.rs:3:7
+ |
+LL | #[doc(include = "external-cross-doc.md")]
+ | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
+ |
+ = note: `#[warn(invalid_doc_attributes)]` 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+warning: 1 warning emitted
+
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(notable_trait)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(spotlight)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-warning: unknown `doc` attribute `spotlight`
- --> $DIR/doc-spotlight.rs:6:7
+error: unknown `doc` attribute `spotlight`
+ --> $DIR/doc-spotlight.rs:5:7
|
LL | #[doc(spotlight)]
| ^^^^^^^^^ help: use `notable_trait` instead
|
- = note: `#[warn(invalid_doc_attributes)]` on by default
+note: the lint level is defined here
+ --> $DIR/doc-spotlight.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= 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: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
-warning: 1 warning emitted
+error: aborting due to previous error
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Email me at <hello@localhost>.
error: unknown disambiguator `hello`
- --> $DIR/email-address-localhost.rs:3:18
+ --> $DIR/email-address-localhost.rs:4:18
|
LL | //! Email me at <hello@localhost>.
| ^^^^^
|
note: the lint level is defined here
- --> $DIR/email-address-localhost.rs:1:9
+ --> $DIR/email-address-localhost.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to previous error
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Linking to [foo@banana] and [`bar@banana!()`].
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:3:17
+ --> $DIR/unknown-disambiguator.rs:4:17
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
note: the lint level is defined here
- --> $DIR/unknown-disambiguator.rs:1:9
+ --> $DIR/unknown-disambiguator.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `bar`
- --> $DIR/unknown-disambiguator.rs:3:35
+ --> $DIR/unknown-disambiguator.rs:4:35
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:34
+ --> $DIR/unknown-disambiguator.rs:10:34
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:48
+ --> $DIR/unknown-disambiguator.rs:10:48
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:31
+ --> $DIR/unknown-disambiguator.rs:7:31
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:57
+ --> $DIR/unknown-disambiguator.rs:7:57
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to 6 previous errors
// error-pattern: no documentation found
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(rustdoc::missing_crate_level_docs)]
//^~ NOTE defined here
error: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/no-crate-level-doc-lint.rs:2:9
+ --> $DIR/no-crate-level-doc-lint.rs:3:9
|
LL | #![deny(rustdoc::missing_crate_level_docs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
error: aborting due to previous error
/// Docs for QUX1 in impl.
const QUX1: i8 = 5;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
- // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
const QUX_DEFAULT0: u16 = 6;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
/// Docs for QUX_DEFAULT1 in impl.
const QUX_DEFAULT1: i16 = 7;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
- // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
- // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
}
impl Foo {
// @has async_fn/struct.Foo.html
- // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
// taken from `tokio` as an example of a method that was particularly bad before
- // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+ // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
- // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+ // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
pub async fn mut_self(&mut self) {}
}
#![feature(auto_traits)]
-// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
pub struct Foo;
pub auto trait Bar {}
# Cross-crate imported docs
-This file is to make sure `#[doc(include="file.md")]` works when you re-export an item with included
+This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included
docs.
-#![feature(external_doc)]
-#![deny(missing_doc)]
-
-#[doc(include="external-cross-doc.md")]
+#[deny(missing_docs)]
+#[doc = include_str!("external-cross-doc.md")]
pub struct NeedMoreDocs;
# External Docs
-This file is here to test the `#[doc(include="file")]` attribute.
+This file is here to test the `#[doc = include_str!("file")]` attribute.
#![crate_name = "foo"]
-// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
pub struct S2 {}
mod m {
pub struct S {}
pub struct Foo;
impl Foo {
- // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn gated() -> u32 { 42 }
- // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.2.0")]
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'const fn new()'
+// @has - '//*[@class="method has-srclink"]' 'const fn new()'
pub struct Foo(usize);
impl Foo {
inner: T,
}
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
impl Add for Simd<u8, 16> {
type Output = Self;
}
// @has foo/trait.Array.html
-// @has - '//h3[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
impl <T, const N: usize> Array for [T; N] {
type Item = T;
}
// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
-// @has foo/struct.Foo.html '//h3[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
impl<const M: usize> Foo<M> where u8: Trait<M> {
// @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
pub const FOO_ASSOC: usize = M + 13;
}
}
-// @has foo/struct.Bar.html '//h3[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
// @has - '//*[@id="method.hey"]' \
// 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
}
// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
pub struct VSet<T, const ORDER: Order> {
inner: Vec<T>,
}
-// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
impl <T> VSet<T, {Order::Sorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
-// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
impl <T> VSet<T, {Order::Unsorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
pub struct Escape<const S: &'static str>;
-// @has foo/struct.Escape.html '//h3[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
+// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
pub fn f() {}
}
fn foo(foo: Self::Fuu);
}
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
impl<T: Bar<Fuu = u32>> Foo<T> {
pub fn new(t: T) -> Foo<T> {
Foo {
// @has issue_33054/impls/struct.Foo.html
// @has - '//code' 'impl Foo'
// @has - '//code' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
// @has - '//code' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
#![crate_name = "foo"]
// @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
pub struct Foo;
pub trait EmptyTrait {}
-// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
impl EmptyTrait for Foo {}
pub trait NotEmpty {
fn foo(&self);
}
-// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
impl NotEmpty for Foo {
fn foo(&self) {}
}
// This test ensures that the [src] link is present on traits items.
-// @has foo/trait.Iterator.html '//h3[@id="method.zip"]/a[@class="srclink"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]/a[@class="srclink"]' "[src]"
pub use std::iter::Iterator;
-#![feature(external_doc)]
-
-// @has external_doc/struct.CanHasDocs.html
-// @has - '//h1' 'External Docs'
-// @has - '//h2' 'Inline Docs'
-#[doc(include = "auxiliary/external-doc.md")]
-/// ## Inline Docs
-pub struct CanHasDocs;
-
// @has external_doc/struct.IncludeStrDocs.html
// @has - '//h1' 'External Docs'
// @has - '//h2' 'Inline Docs'
use std::fmt;
-// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Bar;
-// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Foo;
// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
pub struct Foo<T> { field: T }
-// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault'
// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault'
// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
// @has - '//*[@class="docblock"]' 'dox for method_no_default'
// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
-// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//div[@class="docblock"]' 'docs for method_with_default'
pub use assoc_items::MyStruct;
// @has foo/trait.MyTrait.html
// @has 'foo/struct.MyStruct.html'
// @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
-// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//div[@class="docblock"]' 'docs for my_trait_method'
pub use impl_inline_without_trait::MyStruct;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
// @!has - '//*[@class="impl"]//code' 'Bar for'
// @!has - '//*[@class="impl"]//code' 'Qux for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Qux for'
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
// @!has - '//*[@class="impl"]//code' 'Bar for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for'
// @!has - '//*[@class="impl"]//code' 'Qux for'
pub use rustdoc_nonreachable_impls::Foo;
/// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl
/// [Vec::into_iter()] uses a disambiguator
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
pub fn foo() {}
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
// @has builtin_macros/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html'
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
//! [cfg]
--- /dev/null
+// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
//! Here's a link to [`Iterator<Box<T>>::Item`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
//! And [`Result<T, !>`] and [`Result<!, E>`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
//! This is also pretty tricky: [`TypeId::of::<String>()`].
//! And this too: [`Vec::<std::error::Error>::len`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
//! [`Box::<T>new()`]. We may not support them in the future!
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
//! These will be resolved as regular links:
//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
#![feature(intra_doc_pointers)]
#![deny(rustdoc::broken_intra_doc_links)]
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
//! [slice::rotate_left]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
//! [array::map]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'owned str'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str ref'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.len"]' '&str::len'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
//! [owned str][str]
//! [str ref][&str]
//! [str::is_empty]
//! [&str::len]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
//! [pointer::is_null]
//! [*const::is_null]
//! [*mut::is_null]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
//! [unit]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
//! [tuple]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
//! [reference]
//! [&]
//! [&mut]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
//! [fn]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
//! [never]
//! [!]
#![deny(broken_intra_doc_links)]
//! [i32::MAX]
-// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
#![crate_type = "rlib"]
// @has prim_methods_external_core/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods_local/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
pub mod char {
/// [char]
- // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+ // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct Inner;
}
/// See [prim@char]
-// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct MyString;
/// See also [crate::char] and [mod@char]
#![deny(broken_intra_doc_links)]
// @has primitive_disambiguators/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim'
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
//! [str::trim()]
// @has primitive_non_default_impl/fn.str_methods.html
/// [`str::trim`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
/// [`str::to_lowercase`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
/// [`str::into_boxed_bytes`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
/// [`str::replace`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
pub fn str_methods() {}
// @has primitive_non_default_impl/fn.f32_methods.html
/// [f32::powi]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
/// [f32::sqrt]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
/// [f32::mul_add]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
pub fn f32_methods() {}
// @has primitive_non_default_impl/fn.f64_methods.html
/// [`f64::powi`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
/// [`f64::sqrt`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
/// [`f64::mul_add`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
pub fn f64_methods() {}
// documenting the re-export.
// @has outer/index.html
-// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
+// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
// @ has - '//a[@href="fn.f.html"]' "g"
pub use f as g;
// Make sure the documentation is actually correct by documenting an inlined re-export
/// [mod@std::env]
// @has outer/fn.f.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env"
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
pub use inner::f;
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
pub struct S;
impl S {
// @has foo/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
//! A `bool` is either [`true`] or [`false`].
-// ignore-tidy-linelength
#![deny(broken_intra_doc_links)]
#![feature(lang_items)]
#![feature(no_core)]
/// [Self::f]
/// [Self::MAX]
// @has intra_link_prim_self/primitive.usize.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.f"]' 'Self::f'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
impl usize {
/// Some docs
pub fn f() {}
pub const MAX: usize = 10;
// FIXME(#8995) uncomment this when associated types in inherent impls are supported
- // @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+ // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
// / [Self::ME]
//pub type ME = usize;
}
pub trait Blah { }
// @count issue_21474/struct.What.html \
-// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
pub struct What;
fn my_string(&self) -> String;
}
-// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
impl<T> MyTrait for T where T: fmt::Debug {
fn my_string(&self) -> String {
format!("{:?}", self)
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
impl T<[i32; ($n * $n)]> for S {
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
// @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
impl T<(i32,)> for S {
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
// @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
// @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
impl T<(i32, i32)> for S {
// @has 'foo/struct.Foo1.html'
pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
impl Bar<Foo1, &'static Foo1> for Foo1 {}
// @has 'foo/struct.Foo2.html'
pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
impl Bar<&'static Foo2, Foo2> for u8 {}
// @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
// @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Switch<B: Signal> {
pub inner: <B as Signal2>::Item2,
}
}
// @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as Owned<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}
}
}
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
array_impls! { 10 3 2 1 0 }
// @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Send for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
pub struct ScopeFutureContents<'scope, S>
where S: ScopeHandle<'scope>,
{
#![feature(negative_impls)]
// @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Sync for A"
pub struct A();
impl !Send for A {}
impl !Sync for A {}
// @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for B<T>"
pub struct B<T: ?Sized>(A, Box<T>);
}
// @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \
-// Parser<'a>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a> Send for Parser<'a>"
pub struct Parser<'a> {
field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
}
{}
// @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for IntoIter<T>"
pub struct IntoIter<T>{
hello:DynTrait<FooInterface<T>>,
}
pub struct Struct {}
impl Struct {
- // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32'
+ // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+ // 'pub const fn blurp() -> i32'
/// A useless function that always returns 1.
pub const fn blurp() -> i32 {
1
impl<T: Something> AnAmazingTrait for T {}
// @has 'issue_78673/struct.MyStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
pub struct MyStruct;
impl AnAmazingTrait for MyStruct {}
// generic structs may have _both_ specific and blanket impls that apply
// @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
pub struct AnotherStruct<T>(T);
impl<T: Something> Something for AnotherStruct<T> {}
--- /dev/null
+// @has issue_85454/trait.FromResidual.html
+// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+pub trait FromResidual<R = <Self as Try>::Residual> {
+ fn from_residual(residual: R) -> Self;
+}
+
+pub trait Try: FromResidual {
+ type Output;
+ type Residual;
+ fn from_output(output: Self::Output) -> Self;
+ fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+pub enum ControlFlow<B, C = ()> {
+ Continue(C),
+ Break(B),
+}
+++ /dev/null
-#![allow(unused)]
-
-// @has 'item_hide_threshold/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub struct PubStruct {
- pub a: usize,
- pub b: usize,
-}
-
-// @has 'item_hide_threshold/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub struct BigPubStruct {
- pub a: usize,
- pub b: usize,
- pub c: usize,
- pub d: usize,
- pub e: usize,
- pub f: usize,
- pub g: usize,
- pub h: usize,
- pub i: usize,
- pub j: usize,
- pub k: usize,
- pub l: usize,
- pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub union BigUnion {
- pub a: usize,
- pub b: usize,
- pub c: usize,
- pub d: usize,
- pub e: usize,
- pub f: usize,
- pub g: usize,
- pub h: usize,
- pub i: usize,
- pub j: usize,
- pub k: usize,
- pub l: usize,
- pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub union Union {
- pub a: usize,
- pub b: usize,
- pub c: usize,
-}
-
-// @has 'item_hide_threshold/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
-pub struct PrivStruct {
- a: usize,
- b: usize,
-}
-
-// @has 'item_hide_threshold/enum.Enum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub enum Enum {
- A, B, C,
- D {
- a: u8,
- b: u8
- }
-}
-
-// @has 'item_hide_threshold/enum.LargeEnum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
-pub enum LargeEnum {
- A, B, C, D, E, F(u8), G, H, I, J, K, L, M
-}
-
-// @has 'item_hide_threshold/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub trait Trait {
- type A;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
-pub trait GinormousTrait {
- type A;
- type B;
- type C;
- type D;
- type E;
- type F;
- type G;
- type H;
- type I;
- type J;
- type K;
- type L;
- type M;
- const N: usize = 1;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
-pub trait HugeTrait {
- type A;
- const M: usize = 1;
- const N: usize = 1;
- const O: usize = 1;
- const P: usize = 1;
- const Q: usize = 1;
- const R: usize = 1;
- const S: usize = 1;
- const T: usize = 1;
- const U: usize = 1;
- const V: usize = 1;
- const W: usize = 1;
- const X: usize = 1;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
-pub trait BigTrait {
- type A;
- #[must_use]
- fn foo();
- fn bar();
- fn baz();
- fn quux();
- fn frob();
- fn greeble();
- fn blap();
- fn whoop();
- fn pow();
- fn bang();
- fn oomph();
- fn argh();
- fn wap();
- fn ouch();
-}
// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
-// @has foo/index.html '//div[@class="block items"]//a/@href' '#keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
// @!has - '//*[@class="docblock"]' 'There is another line'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more'
pub struct S1(usize);
/// Docs associated with the S1 trait implementation.
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
pub struct S2(usize);
/// Docs associated with the S2 trait implementation.
}
// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has - '//details/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @!has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
pub struct S3(usize);
/// Docs associated with the S3 trait implementation.
pub struct Foo;
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
// @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
impl Foo {
pub fn foo(mut self) {}
// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
pub struct Bravo<B>(B);
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha"
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \
+// "impl !Send for Alpha"
impl !Send for Alpha {}
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl<B> !Send for Bravo<B>"
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\
+// impl<B> !Send for Bravo<B>"
impl<B> !Send for Bravo<B> {}
include!("primitive/primitive-generic-impl.rs");
-// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
#![crate_name = "foo"]
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
/// It contains [`u32`] and [i64].
/// It also links to [std::primitive::i32], [std::primitive::str],
// @has bar/p/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub mod p {
pub use foo::bar::*;
}
// @has bar/baz/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub use foo::bar as baz;
// @has bar/index.html
// @has - '//code' 'pub use str;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str'
+// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str'
// @has - '//code' 'pub use i32 as my_i32;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'i32'
+// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32'
pub use str;
pub use i32 as my_i32;
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'pub fn new()'
-// @has - '//*[@class="method"]' 'fn not_pub()'
+// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
+// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
pub struct Foo(usize);
impl Foo {
// @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
+// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
+// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
pub trait Foo {}
impl Foo for u32 {}
#![crate_name = "foo"]
// @has foo/struct.Bar.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
pub struct Bar {
a: u16,
}
// @has foo/struct.Foo.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
pub struct Foo<T: ?Sized>(T);
// @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
pub struct Unsized {
data: [u8],
}
use std::iter::Iterator;
// @has foo/struct.Odd.html
-// @has - '//h4[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
pub struct Odd {
current: usize,
}
#![crate_name = "foo"]
// @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
-// @!has - '//h3[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Sync"]/code' 'impl Sync for Unsized'
-// @!has - '//h3[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Any"]/code' 'impl<T> Any for T'
-// @has - '//h3[@id="impl-Any"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @!has - '//div[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized'
+// @!has - '//div[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T'
+// @has - '//div[@id="impl-Any"]/a[@class="srclink"]' '[src]'
pub struct Unsized {
data: [u8],
}
// @has basic/struct.Foo.html
// @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
// @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Foo<T> {
field: T,
}
}
// @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \
-// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
{}
// @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
}
// @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \
-// Foo<T> where T: Sync'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
//
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
// 'impl<T> Send for Foo<T>'
//
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
pub struct Foo<T> {
field: T,
}
}
// @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for Outer<T>"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \
-// !Sync for Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for Outer<T>"
pub struct Outer<T: Copy> {
inner_field: Inner<T>,
}
}
// @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \
-// Foo<T> where T: Copy'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Send for Foo<T> where T: Copy'
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
// 'impl<T> Sync for Foo<T> where T: Sync'
pub struct Foo<T> {
inner_field: Inner<T>,
}
// @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Outer<T> where T: Copy + Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Outer<T> where T: Copy + Send"
pub struct Outer<T> {
inner_field: Inner<T>,
}
}
// @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// 'c: 'static,"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
}
// @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \
-// WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
where P1: Pattern;
}
// @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
pub struct Owned<T> where T: OwnedTrait<'static> {
marker: <T as OwnedTrait<'static>>::Reader,
}
--- /dev/null
+#![allow(unused)]
+
+// @has 'toggle_item_contents/struct.PubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub struct PubStruct {
+ pub a: usize,
+ pub b: usize,
+}
+
+// @has 'toggle_item_contents/struct.BigPubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub struct BigPubStruct {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.BigUnion.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub union BigUnion {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.Union.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub union Union {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+}
+
+// @has 'toggle_item_contents/struct.PrivStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
+pub struct PrivStruct {
+ a: usize,
+ b: usize,
+}
+
+// @has 'toggle_item_contents/enum.Enum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub enum Enum {
+ A, B, C,
+ D {
+ a: u8,
+ b: u8
+ }
+}
+
+// @has 'toggle_item_contents/enum.LargeEnum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
+pub enum LargeEnum {
+ A, B, C, D, E, F(u8), G, H, I, J, K, L, M
+}
+
+// @has 'toggle_item_contents/trait.Trait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub trait Trait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.GinormousTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
+pub trait GinormousTrait {
+ type A;
+ type B;
+ type C;
+ type D;
+ type E;
+ type F;
+ type G;
+ type H;
+ type I;
+ type J;
+ type K;
+ type L;
+ type M;
+ const N: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.HugeTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
+pub trait HugeTrait {
+ type A;
+ const M: usize = 1;
+ const N: usize = 1;
+ const O: usize = 1;
+ const P: usize = 1;
+ const Q: usize = 1;
+ const R: usize = 1;
+ const S: usize = 1;
+ const T: usize = 1;
+ const U: usize = 1;
+ const V: usize = 1;
+ const W: usize = 1;
+ const X: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.BigTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
+pub trait BigTrait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+ fn baz();
+ fn quux();
+ fn frob();
+ fn greeble();
+ fn blap();
+ fn whoop();
+ fn pow();
+ fn bang();
+ fn oomph();
+ fn argh();
+ fn wap();
+ fn ouch();
+}
--- /dev/null
+#![crate_name = "foo"]
+
+// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Struct methods with no documentation should not be wrapped.
+//
+// @has foo/struct.Foo.html
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()'
+pub struct Foo {
+}
+
+impl Foo {
+ pub fn not_documented() {}
+
+ /// is_documented is documented
+ pub fn is_documented() {}
+}
#![crate_name = "foo"]
+// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Trait methods with no documentation should not be wrapped.
+//
// @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//code' 'bar'
+// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
pub trait Foo {
- fn bar() -> ();
+ fn not_documented();
+
+ /// is_documented is documented
+ fn is_documented();
+
+ fn not_documented_optional() {}
+
+ /// is_documented_optional is documented
+ fn is_documented_optional() {}
}
pub trait Foo {
- // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
+ // @has foo/trait.Foo.html '//div[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
#[must_use]
fn foo();
}
pub struct Bar;
impl Bar {
- // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//div[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
#[must_use]
pub fn bar() {}
- // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//div[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
#[must_use]
pub fn bar2() {}
}
impl MyTrait for String {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
type Assoc = ();
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
const VALUE: u32 = 5;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
fn defaulted_override(&self) {}
}
impl MyTrait for Vec<u8> {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
type Assoc = ();
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
const VALUE: u32 = 5;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
fn defaulted_override(&self) {}
}
impl MyTrait for MyStruct {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
type Assoc = bool;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
const VALUE: u32 = 20;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
fn defaulted_override(&self) {}
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
}
pub struct MyStruct;
}
// @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl"]//code' 'impl MyAlias'
-// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias'
// @has - 'Alias docstring'
// @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias'
// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
-#![feature(external_doc)]
-
#![crate_name = "foo"]
// @has foo/struct.Example.html
// @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z'
///a
///no whitespace
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct J;
// @has foo/struct.K.html
///
/// 4 whitespaces!
///
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct K;
pub struct Delta<D>(D);
-// @has foo/struct.Delta.html '//*[@class="impl"]//code' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \
// "impl<D> Delta<D> where D: MyTrait"
impl<D> Delta<D> where D: MyTrait {
pub fn delta() {}
pub struct Echo<E>(E);
-// @has foo/struct.Echo.html '//*[@class="impl"]//code' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
pub enum Foxtrot<F> { Foxtrot1(F) }
-// @has foo/enum.Foxtrot.html '//*[@class="impl"]//code' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
// run-pass
-// revisions: default nomiropt
+// revisions: default nomiropt thirunsafeck
//[nomiropt]compile-flags: -Z mir-opt-level=0
+//[thirunsafeck]compile-flags: -Zthir-unsafeck
#![allow(unused)]
}
fn main() {
- S::f(); //~ ERROR call to unsafe function is unsafe
- f(); //~ ERROR call to unsafe function is unsafe
+ S::f(); //[mir]~ ERROR call to unsafe function is unsafe
+ f(); //[mir]~ ERROR call to unsafe function is unsafe
}
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5
- |
-LL | S::f();
- | ^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5
- |
-LL | f();
- | ^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.
// edition:2018
// run-pass
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-#![feature(member_constraints)]
+// Test member constraints that appear in the `impl Trait`
+// return type of an async function.
+// (This used to require a feature gate.)
trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }
+++ /dev/null
-// edition:2018
-
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
-
-async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- //~^ ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
- //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
- (a, b)
-}
-
-fn main() {
- let _ = async_ret_impl_trait(&22, &44);
-}
+++ /dev/null
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-no-fg.rs:9:1
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-no-fg.rs:9:1
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: hidden type `(&u8, &u8)` captures lifetime '_#6r
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0700`.
error: lifetime may not live long enough
- --> $DIR/ret-impl-trait-one.rs:12:80
+ --> $DIR/ret-impl-trait-one.rs:10:80
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ________________________________--__--__________________________________________^
// Test that a feature gate is needed to use `impl Trait` as the
// return type of an async.
-#![feature(member_constraints)]
-
trait Trait<'a> { }
impl<T> Trait<'_> for T { }
error[E0623]: lifetime mismatch
- --> $DIR/ret-impl-trait-one.rs:12:65
+ --> $DIR/ret-impl-trait-one.rs:10:65
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ------ ^^^^^^^^^^^^^^
+++ /dev/null
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:16:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:23:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:8:9
- |
-LL | main as usize
- | ^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:12:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:16:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constant functions is unstable
- --> $DIR/cast-ptr-to-int-const.rs:23:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
LL | let _pointer_to_something = something as *const Something;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let _pointer_to_something = &something as *const Something;
| ^
LL | let _mut_pointer_to_something = something as *mut Something;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let _mut_pointer_to_something = &mut something as *mut Something;
| ^^^^
// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-18343.rs:7:7
|
LL | struct Obj<F> where F: FnMut() -> u32 {
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:36:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (o_closure.closure)();
| ^ ^
-error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:38:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| |
| field, not a method
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:42:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (boxed_closure.boxed_closure)();
| ^ ^
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:53:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (w.wrap.closure)();
| ^ ^
-error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:55:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| |
| field, not a method
-error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:58:24
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
fn test<T>() -> [u8; size_of::<T>()] {
[0; size_of::<Foo<T>>()]
//~^ ERROR unconstrained generic constant
+ //~| ERROR mismatched types
}
fn main() {
+error[E0308]: mismatched types
+ --> $DIR/different-fn.rs:10:5
+ |
+LL | [0; size_of::<Foo<T>>()]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
+ |
+ = note: expected type `size_of::<T>()`
+ found type `size_of::<Foo<T>>()`
+
error: unconstrained generic constant
--> $DIR/different-fn.rs:10:9
|
|
= help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+// We previously always returned ambiguity when equating generic consts, even if they
+// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1`
+// should fail.
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+enum Assert<const COND: bool> {}
+trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+struct Foo<const N: usize, const M: usize>;
+trait Bar<const N: usize, const M: usize> {}
+impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M>
+where
+ Assert<{ N > 1 }>: IsTrue,
+ Assert<{ M > 1 }>: IsTrue,
+{
+}
+
+fn main() {}
#![allow(incomplete_features)]
fn test<const N: usize>() -> [u8; N - 1] {
- //~^ ERROR evaluation of constant
+ //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
todo!()
}
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
--> $DIR/from-sig-fail.rs:4:35
|
LL | fn test<const N: usize>() -> [u8; N - 1] {
-error[E0080]: evaluation of constant value failed
- --> $DIR/simple_fail.rs:9:48
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
+ --> $DIR/simple_fail.rs:10:48
|
LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
| ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed
--> $DIR/simple_fail.rs:6:33
|
LL | type Arr<const N: usize> = [u8; N - 1];
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/simple_fail.rs:9:48
+ --> $DIR/simple_fail.rs:10:48
|
LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
| ^ cannot perform const operation using `N`
#![cfg_attr(full, feature(const_evaluatable_checked))]
#![allow(incomplete_features)]
-type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
+type Arr<const N: usize> = [u8; N - 1];
//[min]~^ ERROR generic parameters may not be used in const operations
+//[full]~^^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed
fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
//[min]~^ ERROR generic parameters may not be used in const operations
-//[full]~^^ ERROR evaluation of constant
+//[full]~^^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
todo!()
}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Foo<const N: usize = M, const M: usize = 10>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar<const N: usize = M, const M: usize = 10> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+struct Foo2<const N: usize = N>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar2<const N: usize = N> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+fn main() {}
--- /dev/null
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:3:29
+ |
+LL | struct Foo<const N: usize = M, const M: usize = 10>;
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:6:27
+ |
+LL | enum Bar<const N: usize = M, const M: usize = 10> {}
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:9:30
+ |
+LL | struct Foo2<const N: usize = N>;
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:12:28
+ |
+LL | enum Bar2<const N: usize = N> {}
+ | ^ defaulted generic parameters cannot be forward declared
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0128`.
+error[E0308]: mismatched types
+ --> $DIR/issue-62504.rs:18:21
+ |
+LL | ArrayHolder([0; Self::SIZE])
+ | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+ |
+ = note: expected type `X`
+ found type `Self::SIZE`
+
error: constant expression depends on a generic parameter
--> $DIR/issue-62504.rs:18:25
|
|
= note: this may fail depending on what value the parameter takes
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
pub const fn new() -> Self {
ArrayHolder([0; Self::SIZE])
//~^ ERROR constant expression depends on a generic parameter
- //[min]~| ERROR mismatched types
+ //~| ERROR mismatched types
}
}
--- /dev/null
+// Auxiliary crate used for testing post-monomorphization errors cross-crate.
+// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments.
+
+struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
+impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
+ pub(crate) const VALID: () = {
+ let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+ };
+}
+
+macro_rules! static_assert_imm1 {
+ ($imm:ident) => {
+ let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
+ };
+}
+
+// This function triggers an error whenever the const argument does not fit in 1-bit.
+pub fn stdarch_intrinsic<const IMM1: i32>() {
+ static_assert_imm1!(IMM1);
+}
const Z: () = std::panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z2: () = std::panic!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y: () = std::unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X: () = std::unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
//
const W: () = std::panic!(MSG);
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z_CORE: () = core::panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z2_CORE: () = core::panic!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y_CORE: () = core::unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X_CORE: () = core::unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const W_CORE: () = core::panic!(MSG);
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:7:15
|
LL | const Z: () = std::panic!("cheese");
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15
|
- = note: `#[deny(const_err)]` 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:11:16
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:10:16
|
LL | const Z2: () = std::panic!();
| ---------------^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16
+ | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:15:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:13:15
|
LL | const Y: () = std::unreachable!();
| --------------^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:19:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:16:15
|
LL | const X: () = std::unimplemented!();
| --------------^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:23:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:19:15
|
LL | const W: () = std::panic!(MSG);
| --------------^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15
+ | the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:27:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:22:20
|
LL | const Z_CORE: () = core::panic!("cheese");
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20
+ | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:31:21
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:25:21
|
LL | const Z2_CORE: () = core::panic!();
| --------------------^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21
+ | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:35:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:28:20
|
LL | const Y_CORE: () = core::unreachable!();
| -------------------^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:39:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:31:20
|
LL | const X_CORE: () = core::unimplemented!();
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:43:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:34:20
|
LL | const W_CORE: () = core::panic!(MSG);
| -------------------^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20
+ | the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0080`.
const Z: () = panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y: () = unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X: () = unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
#[lang = "eh_personality"]
fn eh() {}
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/const_panic_libcore_bin.rs:9:15
|
LL | const Z: () = panic!("cheese");
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15
|
- = note: `#[deny(const_err)]` 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic_libcore_bin.rs:13:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic_libcore_bin.rs:12:15
|
LL | const Y: () = unreachable!();
| --------------^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:13:15
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic_libcore_bin.rs:17:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic_libcore_bin.rs:15:15
|
LL | const X: () = unimplemented!();
| --------------^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:17:15
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15
|
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0080`.
= 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<()>` failed
--> $DIR/issue-50814-2.rs:19:6
|
LL | &<A<T> as Foo<T>>::BAR
= 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<i32>` failed
--> $DIR/issue-50814.rs:21:6
|
LL | &Sum::<U8,U8>::MAX
--- /dev/null
+// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const
+// argument value is outside the range expected by the `stdarch` intrinsic.
+//
+// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics
+// only available on x64, and internal implementation details of `stdarch`. But mostly because these
+// are not important to trigger the diagnostics issue: it's specifically about the lack of context
+// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency.
+// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME
+// depending on the const argument value, like the `stdarch` intrinsics would.
+//
+// aux-build: post_monomorphization_error.rs
+// build-fail: this is a post-monomorphization error, it passes check runs and requires building
+// to actually fail.
+
+extern crate post_monomorphization_error;
+
+fn main() {
+ // This function triggers a PME whenever the const argument does not fit in 1-bit.
+ post_monomorphization_error::stdarch_intrinsic::<2>();
+ //~^ NOTE the above error was encountered while instantiating
+}
--- /dev/null
+error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed
+ --> $DIR/auxiliary/post_monomorphization_error.rs:7:17
+ |
+LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
+
+note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>`
+ --> $DIR/issue-85155.rs:19:5
+ |
+LL | post_monomorphization_error::stdarch_intrinsic::<2>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
impl PrintName {
const VOID: ! = panic!();
- //~^ WARN any use of this value will cause an error
- //~| WARN this was previously accepted by the compiler but is being phased out
+ //~^ ERROR any use of this value will cause an error
}
fn main() {
-warning: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/panic-assoc-never-type.rs:11:21
|
LL | const VOID: ! = panic!();
| |
| the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21
|
-note: the lint level is defined here
- --> $DIR/panic-assoc-never-type.rs:4:9
- |
-LL | #![warn(const_err)]
- | ^^^^^^^^^
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
- = note: this warning 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_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: erroneous constant used
- --> $DIR/panic-assoc-never-type.rs:17:13
+ --> $DIR/panic-assoc-never-type.rs:16:13
|
LL | let _ = PrintName::VOID;
| ^^^^^^^^^^^^^^^ referenced constant has errors
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.
-// build-fail
-
// Regression test for #66975
#![warn(const_err)]
#![feature(const_panic)]
#![feature(never_type)]
const VOID: ! = panic!();
-//~^ WARN any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
+//~^ ERROR any use of this value will cause an error
fn main() {
let _ = VOID;
- //~^ ERROR erroneous constant used
}
-warning: any use of this value will cause an error
- --> $DIR/panic-never-type.rs:8:17
+error[E0080]: any use of this value will cause an error
+ --> $DIR/panic-never-type.rs:6:17
|
LL | const VOID: ! = panic!();
| ----------------^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:8:17
+ | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17
|
-note: the lint level is defined here
- --> $DIR/panic-never-type.rs:4:9
- |
-LL | #![warn(const_err)]
- | ^^^^^^^^^
- = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
- = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: erroneous constant used
- --> $DIR/panic-never-type.rs:13:13
- |
-LL | let _ = VOID;
- | ^^^^ referenced constant has errors
+ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
#[unwind(aborts)]
const fn foo() {
- panic!() //~ ERROR any use of this value will cause an error [const_err]
- //~| WARN this was previously accepted by the compiler but is being phased out
+ panic!() //~ ERROR any use of this value will cause an error
}
const _: () = foo();
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/unwind-abort.rs:5:5
|
LL | panic!()
| |
| the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
| inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
- | inside `_` at $DIR/unwind-abort.rs:9:15
+ | inside `_` at $DIR/unwind-abort.rs:8:15
...
LL | const _: () = foo();
| --------------------
|
- = note: `#[deny(const_err)]` 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (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 E0080`.
let a: [u8; foo()];
//~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
foo();
- //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+ //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
}
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/const-extern-fn-requires-unsafe.rs:11:5
- |
-LL | foo();
- | ^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0133`.
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | None => panic!("called `Option::unwrap()` on a `None` value"),
LL | const BAR: i32 = Option::<i32>::None.unwrap();
| ----------------------------------------------
|
- = note: `#[deny(const_err)]` 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (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 E0080`.
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/assert.rs:10:15
|
LL | const _: () = assert!(false);
| |
| the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
|
- = note: `#[deny(const_err)]` 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `assert` (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 E0080`.
const _: () = assert!(false);
//[stock]~^ ERROR panicking in constants is unstable
//[const_panic]~^^ ERROR any use of this value will cause an error
-//[const_panic]~| WARN this was previously accepted by the compiler but is being phased out
fn main() {}
--> $DIR/tls.rs:12:25
|
LL | unsafe { let _val = A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
error[E0080]: could not evaluate static initializer
--> $DIR/tls.rs:19:26
|
LL | unsafe { let _val = &A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
warning: skipping const checks
|
#![allow(dead_code)]
#![allow(unused_variables)]
-#[rustc_dirty(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
+#[rustc_clean(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
fn main() {}
#[rustc_if_this_changed(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
error: attribute requires -Z query-dep-graph to be enabled
--> $DIR/dep-graph-check-attr.rs:8:1
|
-LL | #[rustc_dirty(hir_owner)]
+LL | #[rustc_clean(hir_owner)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute requires -Z query-dep-graph to be enabled
// the patterns are all fine:
(..) = x;
}
+
+ #[derive(Debug)]
+ #[deprecated(note = "Use something else instead")]
+ enum DeprecatedDebugEnum {
+ Variant1 { value: Option<String> },
+ }
+
+ #[allow(deprecated)]
+ impl DeprecatedDebugEnum {
+ fn new() -> Self {
+ DeprecatedDebugEnum::Variant1 { value: None }
+ }
+ }
+
+ #[allow(deprecated)]
+ pub fn allow_dep() {
+ let _ = DeprecatedDebugEnum::new();
+ }
}
fn main() {}
struct Foo<'a>(&'a str);
struct Buzz<'a, 'b>(&'a str, &'b str);
+struct Qux<'a, T>(&'a T);
+struct Quux<T>(T);
enum Bar {
A,
foo2: Foo<'a, 'b, 'c>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove these lifetime arguments
+
+ qux1: Qux<'a, 'b, i32>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ qux2: Qux<'a, i32, 'b>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ qux3: Qux<'a, 'b, 'c, i32>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove these lifetime arguments
+
+ qux4: Qux<'a, i32, 'b, 'c>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove these lifetime arguments
+
+ qux5: Qux<'a, 'b, i32, 'c>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ quux: Quux<'a, i32, 'b>,
+ //~^ ERROR this struct takes 0 lifetime arguments
+ //~| HELP remove this lifetime argument
}
fn main() {}
error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/E0107.rs:11:11
+ --> $DIR/E0107.rs:13:11
|
LL | buzz: Buzz<'a>,
| ^^^^ -- supplied 1 lifetime argument
| ^^^^
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/E0107.rs:15:10
+ --> $DIR/E0107.rs:17:10
|
LL | bar: Bar<'a>,
| ^^^---- help: remove these generics
| expected 0 lifetime arguments
|
note: enum defined here, with 0 lifetime parameters
- --> $DIR/E0107.rs:4:6
+ --> $DIR/E0107.rs:6:6
|
LL | enum Bar {
| ^^^
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
- --> $DIR/E0107.rs:19:11
+ --> $DIR/E0107.rs:21:11
|
LL | foo2: Foo<'a, 'b, 'c>,
| ^^^ ------ help: remove these lifetime arguments
LL | struct Foo<'a>(&'a str);
| ^^^ --
-error: aborting due to 3 previous errors
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:25:11
+ |
+LL | qux1: Qux<'a, 'b, i32>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:29:11
+ |
+LL | qux2: Qux<'a, i32, 'b>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:33:11
+ |
+LL | qux3: Qux<'a, 'b, 'c, i32>,
+ | ^^^ ------ help: remove these lifetime arguments
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:37:11
+ |
+LL | qux4: Qux<'a, i32, 'b, 'c>,
+ | ^^^ ------ help: remove these lifetime arguments
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:41:11
+ |
+LL | qux5: Qux<'a, 'b, i32, 'c>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:45:11
+ |
+LL | quux: Quux<'a, i32, 'b>,
+ | ^^^^ -- help: remove this lifetime argument
+ | |
+ | expected 0 lifetime arguments
+ |
+note: struct defined here, with 0 lifetime parameters
+ --> $DIR/E0107.rs:4:8
+ |
+LL | struct Quux<T>(T);
+ | ^^^^
+
+error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0107`.
--> $DIR/E0605.rs:6:5
|
LL | v as &u8;
- | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | &*v as &u8;
+ | ^^
error: aborting due to 2 previous errors
+++ /dev/null
-// normalize-stderr-test: "not-a-file.md:.*\(" -> "not-a-file.md: $$FILE_NOT_FOUND_MSG ("
-
-#![feature(external_doc)]
-
-#[doc(include = "not-a-file.md")]
-pub struct SomeStruct; //~^ ERROR couldn't read
-
-#[doc(include = "auxiliary/invalid-utf8.txt")]
-pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
-
-#[doc(include)]
-pub struct MissingPath; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include("../README.md"))]
-pub struct InvalidPathSyntax; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "../README.md"
-
-#[doc(include = 123)]
-pub struct InvalidPathType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include(123))]
-pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-fn main() {}
+++ /dev/null
-error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
- --> $DIR/external-doc-error.rs:5:17
- |
-LL | #[doc(include = "not-a-file.md")]
- | ^^^^^^^^^^^^^^^ couldn't read file
-
-error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
- --> $DIR/external-doc-error.rs:8:17
- |
-LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:11:7
- |
-LL | #[doc(include)]
- | ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:16:7
- |
-LL | #[doc(include("../README.md"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:21:7
- |
-LL | #[doc(include = 123)]
- | ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:26:7
- |
-LL | #[doc(include(123))]
- | ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: aborting due to 6 previous errors
-
= help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
= note: `transmute` is only allowed in constants and statics for now
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/feature-gate-const_fn_transmute.rs:29:39
+ |
+LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) }
+ | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
error[E0658]: `transmute` is not allowed in constant functions
--> $DIR/feature-gate-const_fn_transmute.rs:29:39
|
= help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
= note: `transmute` is only allowed in constants and statics for now
-error[E0658]: `transmute` is not allowed in constant functions
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/feature-gate-const_fn_transmute.rs:33:49
|
LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
- = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
- = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
- = note: `transmute` is only allowed in constants and statics for now
+ = note: consult the function's documentation for information on how to avoid undefined behavior
error[E0658]: `transmute` is not allowed in constant functions
- --> $DIR/feature-gate-const_fn_transmute.rs:37:54
+ --> $DIR/feature-gate-const_fn_transmute.rs:33:49
|
-LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
= help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
= note: `transmute` is only allowed in constants and statics for now
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/feature-gate-const_fn_transmute.rs:29:39
- |
-LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) }
- | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/feature-gate-const_fn_transmute.rs:33:49
+ --> $DIR/feature-gate-const_fn_transmute.rs:37:54
|
-LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0658]: `transmute` is not allowed in constant functions
--> $DIR/feature-gate-const_fn_transmute.rs:37:54
|
LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: consult the function's documentation for information on how to avoid undefined behavior
+ = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
+ = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
+ = note: `transmute` is only allowed in constants and statics for now
error: aborting due to 12 previous errors
+++ /dev/null
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
- //~| ERROR: `#[doc(include)]` is experimental
-fn main() {}
+++ /dev/null
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-trait Trait<'a, 'b> {}
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- //~^ ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- (x, y)
-}
-
-fn main() {}
+++ /dev/null
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/feature-gate-member-constraints.rs:4:43
- |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/feature-gate-member-constraints.rs:4:43
- |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
--> $DIR/generator-print-verbose-1.rs:35:9
|
LL | let _non_send_gen = make_non_send_generator();
- | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+ | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[70c9]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
LL | };
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
- = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
- = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
- = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
- = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
+ = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[70c9]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+ = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), [])`
+ = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}`
+ = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}]`
error: aborting due to 2 previous errors
// build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![feature(generators)]
static mut A: [i32; 5] = [1, 2, 3, 4, 5];
//~| ERROR missing lifetime specifier
//~| HELP consider introducing
//~| HELP add missing
+
+ type F = Ty<'static, usize, 'static, usize>;
+ //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
+ //~| ERROR this struct takes 1 generic argument but 2 generic arguments
+ //~| HELP remove this lifetime argument
+ //~| HELP remove this generic argument
}
mod type_and_type_and_type {
LL | type E<'a> = Ty<'a>;
| ^^^^ ^^
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/wrong-number-of-args.rs:70:14
+ |
+LL | type F = Ty<'static, usize, 'static, usize>;
+ | ^^ ------- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/wrong-number-of-args.rs:46:12
+ |
+LL | struct Ty<'a, T>;
+ | ^^ --
+
+error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+ --> $DIR/wrong-number-of-args.rs:70:14
+ |
+LL | type F = Ty<'static, usize, 'static, usize>;
+ | ^^ ----- help: remove this generic argument
+ | |
+ | expected 1 generic argument
+ |
+note: struct defined here, with 1 generic parameter: `T`
+ --> $DIR/wrong-number-of-args.rs:46:12
+ |
+LL | struct Ty<'a, T>;
+ | ^^ -
+
error[E0107]: missing generics for struct `type_and_type_and_type::Ty`
- --> $DIR/wrong-number-of-args.rs:74:14
+ --> $DIR/wrong-number-of-args.rs:80:14
|
LL | type A = Ty;
| ^^ expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:78:14
+ --> $DIR/wrong-number-of-args.rs:84:14
|
LL | type B = Ty<usize>;
| ^^ ----- supplied 1 generic argument
| expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^
error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:86:14
+ --> $DIR/wrong-number-of-args.rs:92:14
|
LL | type E = Ty<usize, String, char, f64>;
| ^^ --- help: remove this generic argument
| expected at most 3 generic arguments
|
note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - - -
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:90:14
+ --> $DIR/wrong-number-of-args.rs:96:14
|
LL | type F = Ty<>;
| ^^ expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:110:22
+ --> $DIR/wrong-number-of-args.rs:116:22
|
LL | type A = Box<dyn NonGeneric<usize>>;
| ^^^^^^^^^^------- help: remove these generics
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:98:11
+ --> $DIR/wrong-number-of-args.rs:104:11
|
LL | trait NonGeneric {
| ^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:114:22
+ --> $DIR/wrong-number-of-args.rs:120:22
|
LL | type B = Box<dyn GenericLifetime>;
| ^^^^^^^^^^^^^^^ expected named lifetime parameter
| ^^^^ ^^^^^^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:118:22
+ --> $DIR/wrong-number-of-args.rs:124:22
|
LL | type C = Box<dyn GenericLifetime<'static, 'static>>;
| ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:102:11
+ --> $DIR/wrong-number-of-args.rs:108:11
|
LL | trait GenericLifetime<'a> {
| ^^^^^^^^^^^^^^^ --
error[E0107]: missing generics for trait `GenericType`
- --> $DIR/wrong-number-of-args.rs:122:22
+ --> $DIR/wrong-number-of-args.rs:128:22
|
LL | type D = Box<dyn GenericType>;
| ^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
| ^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:126:22
+ --> $DIR/wrong-number-of-args.rs:132:22
|
LL | type E = Box<dyn GenericType<String, usize>>;
| ^^^^^^^^^^^ ----- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:130:37
+ --> $DIR/wrong-number-of-args.rs:136:37
|
LL | type F = Box<dyn GenericLifetime<>>;
| ^- expected named lifetime parameter
| ^^^^ ^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:134:22
+ --> $DIR/wrong-number-of-args.rs:140:22
|
LL | type G = Box<dyn GenericType<>>;
| ^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
| ^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:145:26
+ --> $DIR/wrong-number-of-args.rs:151:26
|
LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
| ^^^^^^^^^^^^------------------- help: remove these generics
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:141:15
+ --> $DIR/wrong-number-of-args.rs:147:15
|
LL | trait NonGenericAT {
| ^^^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:155:44
+ --> $DIR/wrong-number-of-args.rs:161:44
|
LL | type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:159:26
+ --> $DIR/wrong-number-of-args.rs:165:26
|
LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:151:15
+ --> $DIR/wrong-number-of-args.rs:157:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^ --
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:163:44
+ --> $DIR/wrong-number-of-args.rs:169:44
|
LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:163:26
+ --> $DIR/wrong-number-of-args.rs:169:26
|
LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:151:15
+ --> $DIR/wrong-number-of-args.rs:157:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:175:26
+ --> $DIR/wrong-number-of-args.rs:181:26
|
LL | type A = Box<dyn GenericTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:179:26
+ --> $DIR/wrong-number-of-args.rs:185:26
|
LL | type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:183:26
+ --> $DIR/wrong-number-of-args.rs:189:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^--------------------- help: remove these generics
| expected 0 lifetime arguments
|
note: trait defined here, with 0 lifetime parameters
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:183:26
+ --> $DIR/wrong-number-of-args.rs:189:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:195:48
+ --> $DIR/wrong-number-of-args.rs:201:48
|
LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:195:26
+ --> $DIR/wrong-number-of-args.rs:201:26
|
LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:201:26
+ --> $DIR/wrong-number-of-args.rs:207:26
|
LL | type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:205:26
+ --> $DIR/wrong-number-of-args.rs:211:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:205:26
+ --> $DIR/wrong-number-of-args.rs:211:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:211:48
+ --> $DIR/wrong-number-of-args.rs:217:48
|
LL | type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:215:48
+ --> $DIR/wrong-number-of-args.rs:221:48
|
LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:215:26
+ --> $DIR/wrong-number-of-args.rs:221:26
|
LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:221:26
+ --> $DIR/wrong-number-of-args.rs:227:26
|
LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:225:26
+ --> $DIR/wrong-number-of-args.rs:231:26
|
LL | type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:229:26
+ --> $DIR/wrong-number-of-args.rs:235:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:229:26
+ --> $DIR/wrong-number-of-args.rs:235:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:241:26
+ --> $DIR/wrong-number-of-args.rs:247:26
|
LL | type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| ^^^^^
error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:245:26
+ --> $DIR/wrong-number-of-args.rs:251:26
|
LL | type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| ^^^
error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:249:26
+ --> $DIR/wrong-number-of-args.rs:255:26
|
LL | type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:259:52
+ --> $DIR/wrong-number-of-args.rs:265:52
|
LL | type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
| ^ expected 2 lifetime parameters
| ^^^^ ^^^^^^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:263:26
+ --> $DIR/wrong-number-of-args.rs:269:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:255:15
+ --> $DIR/wrong-number-of-args.rs:261:15
|
LL | trait GenericLifetimeLifetimeAT<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:273:56
+ --> $DIR/wrong-number-of-args.rs:279:56
|
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
| ^ expected 2 lifetime parameters
| ^^^^ ^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:273:26
+ --> $DIR/wrong-number-of-args.rs:279:26
|
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:279:26
+ --> $DIR/wrong-number-of-args.rs:285:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:279:26
+ --> $DIR/wrong-number-of-args.rs:285:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:285:26
+ --> $DIR/wrong-number-of-args.rs:291:26
|
LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0107]: missing generics for struct `HashMap`
- --> $DIR/wrong-number-of-args.rs:295:18
+ --> $DIR/wrong-number-of-args.rs:301:18
|
LL | type A = HashMap;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^^^^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:299:18
+ --> $DIR/wrong-number-of-args.rs:305:18
|
LL | type B = HashMap<String>;
| ^^^^^^^ ------ supplied 1 generic argument
| ^^^
error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:303:18
+ --> $DIR/wrong-number-of-args.rs:309:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^--------- help: remove these generics
| ^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:303:18
+ --> $DIR/wrong-number-of-args.rs:309:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^^^
error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:309:18
+ --> $DIR/wrong-number-of-args.rs:315:18
|
LL | type D = HashMap<usize, String, char, f64>;
| ^^^^^^^ --- help: remove this generic argument
| ^^^^^^^ - - -
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:313:18
+ --> $DIR/wrong-number-of-args.rs:319:18
|
LL | type E = HashMap<>;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^
error[E0107]: missing generics for enum `Result`
- --> $DIR/wrong-number-of-args.rs:319:18
+ --> $DIR/wrong-number-of-args.rs:325:18
|
LL | type A = Result;
| ^^^^^^ expected 2 generic arguments
| ^^^^^^^^^^^^
error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:323:18
+ --> $DIR/wrong-number-of-args.rs:329:18
|
LL | type B = Result<String>;
| ^^^^^^ ------ supplied 1 generic argument
| ^^^
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:327:18
+ --> $DIR/wrong-number-of-args.rs:333:18
|
LL | type C = Result<'static>;
| ^^^^^^--------- help: remove these generics
| ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:327:18
+ --> $DIR/wrong-number-of-args.rs:333:18
|
LL | type C = Result<'static>;
| ^^^^^^ expected 2 generic arguments
| ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:333:18
+ --> $DIR/wrong-number-of-args.rs:339:18
|
LL | type D = Result<usize, String, char>;
| ^^^^^^ ---- help: remove this generic argument
| ^^^^^^ - -
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:337:18
+ --> $DIR/wrong-number-of-args.rs:343:18
|
LL | type E = Result<>;
| ^^^^^^ expected 2 generic arguments
LL | type E = Result<T, E>;
| ^^^^
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
Some errors have detailed explanations: E0106, E0107.
For more information about an error, try `rustc --explain E0106`.
#![feature(fn_traits,
step_trait,
- step_trait_ext,
unboxed_closures,
)]
}
}
-unsafe impl std::iter::Step for NaiveDate {
+impl std::iter::Step for NaiveDate {
fn steps_between(_: &Self, _: &Self) -> Option<usize> {
unimplemented!()
}
warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/error-handling.rs:6:32
+ --> $DIR/error-handling.rs:5:32
|
LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
| ^^^^^^^^^^^^^^^^^^^^^
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error: lifetime may not live long enough
- --> $DIR/error-handling.rs:26:16
+ --> $DIR/error-handling.rs:25:16
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- -- lifetime `'b` defined here
error: lifetime may not live long enough
- --> $DIR/error-handling.rs:26:16
+ --> $DIR/error-handling.rs:25:16
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- -- lifetime `'b` defined here
// compile-flags:-Zborrowck=mir
-#![feature(member_constraints)]
// revisions: min_tait full_tait
#![feature(min_type_alias_impl_trait)]
#![cfg_attr(full_tait, feature(type_alias_impl_trait))]
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Test case where we have elision in the impl trait and we have to
// pick the right region.
(a, a)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
#![feature(min_type_alias_impl_trait)]
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Here we wind up selecting `'a` and `'b` in the hidden type because
// those are the types that appear in the original values.
(a, b)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Here we wind up selecting `'a` and `'b` in the hidden type because
// those are the types that appear in the original values.
(a, b)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $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>
| ^^^^^^^^^^^^^^^^^^
// edition:2018
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $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>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $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>
| ^^^^^^^^^^^^^^^^^^
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
// edition:2018
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
// consider the loans for both `'a` and `'b` alive.
fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
{
// We return a value:
//
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
// check-pass
-#![feature(member_constraints)]
-
trait MultiRegionTrait<'a, 'b> {}
impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
struct Attr {
name: String,
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:14:34
+ |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-16538.rs:14:27
|
= help: the trait `Sync` is not implemented for `*const usize`
= note: shared static variables must have a type that implements `Sync`
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0015, E0133, E0277.
LL | 0 as &dyn std::any::Any;
| ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | &0 as &dyn std::any::Any;
| ^
LL | let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
| ^
--> $DIR/issue-2995.rs:2:22
|
LL | let _q: &isize = p as &isize;
- | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | let _q: &isize = &*p as &isize;
+ | ^^
error: aborting due to previous error
|
LL | let ug = Graph::<i32, i32>::new_undirected();
| ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+ |
+ = note: the function or associated item was found for
+ - `issue_30123_aux::Graph<N, E, Undirected>`
error: aborting due to previous error
// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
use std::ops::Deref;
struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
-error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
+error[E0599]: no method named `iter` found for struct `Iterate` in the current scope
--> $DIR/issue-41880.rs:27:24
|
LL | pub struct Iterate<T, F> {
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | let f = |v: &mut Vec<_>| {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+ |
+LL | #[deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |w: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |x: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#[deny(unused_unsafe)]
fn main() {
let mut v = Vec::<i32>::with_capacity(24);
+++ /dev/null
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-LL | let f = |v: &mut Vec<_>| {
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8
- |
-LL | #[deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:9:38
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-...
-LL | |w: &mut Vec<u32>| { unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-...
-LL | |x: &mut Vec<u32>| { unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 3 previous errors
-
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | let f = |v: &mut Vec<_>| {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+ |
+LL | #[deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |w: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |x: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
LL | match *ptr {}
| ^^^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
--- /dev/null
+// compile-flags: --force-warns elided_lifetimes_in_paths
+// check-pass
+
+struct Foo<'a> {
+ x: &'a u32,
+}
+
+fn foo(x: &Foo) {}
+//~^ WARN hidden lifetime parameters in types are deprecated
+
+fn main() {}
--- /dev/null
+warning: hidden lifetime parameters in types are deprecated
+ --> $DIR/force-allowed-by-default-lint.rs:8:12
+ |
+LL | fn foo(x: &Foo) {}
+ | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err
+// check-pass
+
+#![allow(const_err)]
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(dead_code)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-allowed-warning.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-deny-by-default-lint.rs:4:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = 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 #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(warnings)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-lint-allow-all-warnings.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns nonstandard_style
+// check-pass
+
+#![allow(warnings)]
+
+pub fn FUNCTION() {}
+//~^ WARN function `FUNCTION` should have a snake case name
+
+fn main() {}
--- /dev/null
+warning: function `FUNCTION` should have a snake case name
+ --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+ |
+LL | pub fn FUNCTION() {}
+ | ^^^^^^^^ help: convert the identifier to snake case: `function`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns bare_trait_objects
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-lint-in-allowed-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(bare_trait_objects)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group-allow-warning.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
use std::default::Default;
use std::marker::PhantomData;
+trait Trait {}
+
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
+pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+//~^ ERROR: uses type `Box<[u8]>`
+
+pub extern "C" fn boxed_string(p: Box<str>) { }
+//~^ ERROR: uses type `Box<str>`
+
+pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+//~^ ERROR: uses type `Box<dyn Trait>`
+
pub extern "C" fn char_type(p: char) { }
//~^ ERROR uses type `char`
error: `extern` fn uses type `[u32]`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:67:33
+ --> $DIR/lint-ctypes-fn.rs:69:33
|
LL | pub extern "C" fn slice_type(p: &[u32]) { }
| ^^^^^^ not FFI-safe
= note: slices have no C equivalent
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:70:31
+ --> $DIR/lint-ctypes-fn.rs:72:31
|
LL | pub extern "C" fn str_type(p: &str) { }
| ^^^^ not FFI-safe
= help: consider using `*const u8` and a length instead
= note: string slices have no C equivalent
+error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:79:34
+ |
+LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+ | ^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<str>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:82:35
+ |
+LL | pub extern "C" fn boxed_string(p: Box<str>) { }
+ | ^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:85:34
+ |
+LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+ | ^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
error: `extern` fn uses type `char`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:77:32
+ --> $DIR/lint-ctypes-fn.rs:88:32
|
LL | pub extern "C" fn char_type(p: char) { }
| ^^^^ not FFI-safe
= note: the `char` type has no C equivalent
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:80:32
+ --> $DIR/lint-ctypes-fn.rs:91:32
|
LL | pub extern "C" fn i128_type(p: i128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:83:32
+ --> $DIR/lint-ctypes-fn.rs:94:32
|
LL | pub extern "C" fn u128_type(p: u128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:86:33
+ --> $DIR/lint-ctypes-fn.rs:97:33
|
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
| ^^^^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:89:34
+ --> $DIR/lint-ctypes-fn.rs:100:34
|
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
| ^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:92:32
+ --> $DIR/lint-ctypes-fn.rs:103:32
|
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
| ^^^^^^^^ not FFI-safe
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:26:1
+ --> $DIR/lint-ctypes-fn.rs:28:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:95:40
+ --> $DIR/lint-ctypes-fn.rs:106:40
|
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:61:1
+ --> $DIR/lint-ctypes-fn.rs:63:1
|
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:98:51
+ --> $DIR/lint-ctypes-fn.rs:109:51
|
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:103:30
+ --> $DIR/lint-ctypes-fn.rs:114:30
|
LL | pub extern "C" fn fn_type(p: RustFn) { }
| ^^^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:106:31
+ --> $DIR/lint-ctypes-fn.rs:117:31
|
LL | pub extern "C" fn fn_type2(p: fn()) { }
| ^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:111:39
+ --> $DIR/lint-ctypes-fn.rs:122:39
|
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
| ^^^^^^^^^^^^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:114:38
+ --> $DIR/lint-ctypes-fn.rs:125:38
|
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
| ^^^^^^^^^^^^^^ not FFI-safe
= note: string slices have no C equivalent
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:160:43
+ --> $DIR/lint-ctypes-fn.rs:171:43
|
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:173:39
+ --> $DIR/lint-ctypes-fn.rs:184:39
|
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
| ^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:176:41
+ --> $DIR/lint-ctypes-fn.rs:187:41
|
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
| ^^^^^^ not FFI-safe
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
warning: Linking globals named 'foo': symbol multiply defined!
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.3a1fbbbh-cgu.0.rcgu.o":
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.288b404e693a75b4-cgu.0.rcgu.o":
error: aborting due to previous error; 1 warning emitted
// compile-flags: -C lto
// no-prefer-dynamic
// ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
use std::thread;
--- /dev/null
+// edition:2018
+
+#[macro_export]
+macro_rules! custom_matches {
+ ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+ match $expression {
+ $( $pattern )|+ $( if $guard )? => true,
+ _ => false
+ }
+ }
+}
--- /dev/null
+// edition:2021
+// check-pass
+// aux-build: foreign-crate-macro-pat.rs
+//
+// Tests that the edition of the foreign crate is used
+// when determining the behavior of the `:pat` matcher.
+
+extern crate foreign_crate_macro_pat;
+
+fn main() {
+ let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9');
+}
--- /dev/null
+// edition:2021
+// check-pass
+//
+// Regression test for issue #84429
+// Tests that we can properly invoke `matches!` from a 2021-edition crate.
+
+fn main() {
+ let _b = matches!(b'3', b'0' ..= b'9');
+}
--- /dev/null
+// run-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+// regression test for https://github.com/rust-lang/rust/pull/85678
+
+#![feature(assert_matches)]
+
+fn main() {
+ assert!(matches!((), ()));
+ assert_matches!((), ());
+}
--- /dev/null
+// Test for issue 81576
+// Remove generic arguments if no method is found for all possible generic argument
+
+use std::marker::PhantomData;
+
+struct Wrapper2<'a, T, const C: usize> {
+ x: &'a T,
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i8, C> {
+ fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i16, C> {
+ fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i32, C> {
+ fn method(&self) {}
+}
+struct Wrapper<T>(T);
+
+impl Wrapper<i8> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i16> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i32> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i64> {
+ fn method(&self) {}
+}
+
+impl Wrapper<u8> {
+ fn method(&self) {}
+}
+
+impl Wrapper<u16> {
+ fn method(&self) {}
+}
+
+struct Point<T> {
+ x: T,
+ y: T,
+}
+
+impl Point<f64> {
+ fn distance(&self) -> f64 {
+ self.x.hypot(self.y)
+ }
+}
+
+struct Other;
+
+impl Other {
+ fn other(&self) {}
+}
+
+struct Struct<T>{
+ _phatom: PhantomData<T>
+}
+
+impl<T> Default for Struct<T> {
+ fn default() -> Self {
+ Self{ _phatom: PhantomData }
+ }
+}
+
+impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
+ fn method(&self) {}
+}
+
+fn main() {
+ let point_f64 = Point{ x: 1_f64, y: 1_f64};
+ let d = point_f64.distance();
+ let point_i32 = Point{ x: 1_i32, y: 1_i32};
+ let d = point_i32.distance();
+ //~^ ERROR no method named `distance` found for struct `Point<i32>
+ let d = point_i32.other();
+ //~^ ERROR no method named `other` found for struct `Point
+ let v = vec![1_i32, 2, 3];
+ v.iter().map(|x| x * x).extend(std::iter::once(100));
+ //~^ ERROR no method named `extend` found for struct `Map
+ let wrapper = Wrapper(true);
+ wrapper.method();
+ //~^ ERROR no method named `method` found for struct `Wrapper<bool>
+ wrapper.other();
+ //~^ ERROR no method named `other` found for struct `Wrapper
+ let boolean = true;
+ let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
+ wrapper.method();
+ //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
+ wrapper.other();
+ //~^ ERROR no method named `other` found for struct `Wrapper2
+ let a = vec![1, 2, 3];
+ a.not_found();
+ //~^ ERROR no method named `not_found` found for struct `Vec
+ let s = Struct::<f64>::default();
+ s.method();
+ //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+}
--- /dev/null
+error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:82:23
+ |
+LL | struct Point<T> {
+ | --------------- method `distance` not found for this
+...
+LL | let d = point_i32.distance();
+ | ^^^^^^^^ method not found in `Point<i32>`
+ |
+ = note: the method was found for
+ - `Point<f64>`
+
+error[E0599]: no method named `other` found for struct `Point` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:84:23
+ |
+LL | struct Point<T> {
+ | --------------- method `other` not found for this
+...
+LL | let d = point_i32.other();
+ | ^^^^^ method not found in `Point<i32>`
+
+error[E0599]: no method named `extend` found for struct `Map` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:87:29
+ |
+LL | v.iter().map(|x| x * x).extend(std::iter::once(100));
+ | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
+
+error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:90:13
+ |
+LL | struct Wrapper<T>(T);
+ | --------------------- method `method` not found for this
+...
+LL | wrapper.method();
+ | ^^^^^^ method not found in `Wrapper<bool>`
+ |
+ = note: the method was found for
+ - `Wrapper<i8>`
+ - `Wrapper<i16>`
+ - `Wrapper<i32>`
+ - `Wrapper<i64>`
+ and 2 more types
+
+error[E0599]: no method named `other` found for struct `Wrapper` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:92:13
+ |
+LL | struct Wrapper<T>(T);
+ | --------------------- method `other` not found for this
+...
+LL | wrapper.other();
+ | ^^^^^ method not found in `Wrapper<bool>`
+
+error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:96:13
+ |
+LL | struct Wrapper2<'a, T, const C: usize> {
+ | -------------------------------------- method `method` not found for this
+...
+LL | wrapper.method();
+ | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+ |
+ = note: the method was found for
+ - `Wrapper2<'a, i8, C>`
+ - `Wrapper2<'a, i16, C>`
+ - `Wrapper2<'a, i32, C>`
+
+error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:98:13
+ |
+LL | struct Wrapper2<'a, T, const C: usize> {
+ | -------------------------------------- method `other` not found for this
+...
+LL | wrapper.other();
+ | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+
+error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:101:7
+ |
+LL | a.not_found();
+ | ^^^^^^^^^ method not found in `Vec<{integer}>`
+
+error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+ --> $DIR/method-not-found-generic-arg-elision.rs:104:7
+ |
+LL | struct Struct<T>{
+ | ---------------- method `method` not found for this
+...
+LL | s.method();
+ | ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `f64: Eq`
+ `f64: Ord`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | intrinsics::size_of::<T>()
= note: the following trait bounds were not satisfied:
`dyn Debug: Sized`
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | intrinsics::size_of::<T>()
--> $DIR/cast-rfc0401.rs:29:13
|
LL | let _ = v as &u8;
- | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | let _ = &*v as &u8;
+ | ^^
error[E0605]: non-primitive cast: `*const u8` as `E`
--> $DIR/cast-rfc0401.rs:30:13
// ignore-android
// ignore-emscripten no processes
// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(rustc_private)]
--- /dev/null
+// Regression test for #85794
+
+struct Baz {
+ inner : dyn fn ()
+ //~^ ERROR expected `,`, or `}`, found keyword `fn`
+ //~| ERROR functions are not allowed in struct definitions
+ //~| ERROR cannot find type `dyn` in this scope
+}
+
+fn main() {}
--- /dev/null
+error: expected `,`, or `}`, found keyword `fn`
+ --> $DIR/fn-field-parse-error-ice.rs:4:16
+ |
+LL | inner : dyn fn ()
+ | ^ help: try adding a comma: `,`
+
+error: functions are not allowed in struct definitions
+ --> $DIR/fn-field-parse-error-ice.rs:4:17
+ |
+LL | inner : dyn fn ()
+ | ^^
+ |
+ = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
+ = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+
+error[E0412]: cannot find type `dyn` in this scope
+ --> $DIR/fn-field-parse-error-ice.rs:4:13
+ |
+LL | inner : dyn fn ()
+ | ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// check-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+fn main() {
+ let _: u16 = 123i32.try_into().unwrap();
+}
--- /dev/null
+// Checks whether shadowing a const parameter leads to an ICE (#85348).
+
+impl<const N: usize> ArrayWindowsExample {
+//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412]
+ fn next() {
+ let mut N;
+ //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+ //~| ERROR: type annotations needed [E0282]
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0530]: let bindings cannot shadow const parameters
+ --> $DIR/issue-85348.rs:6:17
+ |
+LL | impl<const N: usize> ArrayWindowsExample {
+ | - the const parameter `N` is defined here
+...
+LL | let mut N;
+ | ^ cannot be named the same as a const parameter
+
+error[E0412]: cannot find type `ArrayWindowsExample` in this scope
+ --> $DIR/issue-85348.rs:3:22
+ |
+LL | impl<const N: usize> ArrayWindowsExample {
+ | ^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0282]: type annotations needed
+ --> $DIR/issue-85348.rs:6:13
+ |
+LL | let mut N;
+ | ^^^^^ consider giving `N` a type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0412, E0530.
+For more information about an error, try `rustc --explain E0282`.
--- /dev/null
+// Checks that const parameters cannot be shadowed with fresh bindings
+// even in syntactically unambiguous contexts. See
+// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221
+
+fn foo<const N: i32>(i: i32) -> bool {
+ match i {
+ N @ _ => true,
+ //~^ ERROR: match bindings cannot shadow const parameters [E0530]
+ }
+}
+
+fn bar<const N: i32>(i: i32) -> bool {
+ let N @ _ = 0;
+ //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+ match i {
+ N @ _ => true,
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0530]: match bindings cannot shadow const parameters
+ --> $DIR/shadow-const-param.rs:7:9
+ |
+LL | fn foo<const N: i32>(i: i32) -> bool {
+ | - the const parameter `N` is defined here
+LL | match i {
+LL | N @ _ => true,
+ | ^ cannot be named the same as a const parameter
+
+error[E0530]: let bindings cannot shadow const parameters
+ --> $DIR/shadow-const-param.rs:13:9
+ |
+LL | fn bar<const N: i32>(i: i32) -> bool {
+ | - the const parameter `N` is defined here
+LL | let N @ _ = 0;
+ | ^ cannot be named the same as a const parameter
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
// run-pass
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(start)]
--- /dev/null
+#![deny(invalid_doc_attributes)]
+//~^ NOTE defined here
+#![doc(x)]
+//~^ ERROR unknown `doc` attribute `x`
+//~| WARNING will become a hard error
+//~| NOTE see issue #82730
+fn main() {}
--- /dev/null
+error: unknown `doc` attribute `x`
+ --> $DIR/deny-invalid-doc-attrs.rs:3:8
+ |
+LL | #![doc(x)]
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-invalid-doc-attrs.rs:1:9
+ |
+LL | #![deny(invalid_doc_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = 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>
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
--- /dev/null
+error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+// Short form of the generic gather/scatter tests,
+// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work.
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct cptrx4<T>([*const T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct mptrx4<T>([*mut T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct i32x4([i32; 4]);
+
+extern "platform-intrinsic" {
+ fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T;
+ fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> ();
+}
+
+fn main() {
+ let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
+
+ let default = f32x4([-3_f32, -3., -3., -3.]);
+ let s_strided = f32x4([0_f32, 2., -3., 6.]);
+ let mask = i32x4([-1_i32, -1, 0, -1]);
+
+ // reading from *const
+ unsafe {
+ let pointer = &x as *const f32;
+ let pointers = cptrx4([
+ pointer.offset(0) as *const f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let r_strided = simd_gather(default, pointers, mask);
+
+ assert_eq!(r_strided, s_strided);
+ }
+
+ // writing to *mut
+ unsafe {
+ let pointer = &mut x as *mut f32;
+ let pointers = mptrx4([
+ pointer.offset(0) as *mut f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]);
+ simd_scatter(values, pointers, mask);
+
+ assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
+ }
+}
// run-pass
// ignore-emscripten FIXME(#45351) hits an LLVM assert
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(repr_simd, platform_intrinsics, concat_idents)]
#![allow(non_camel_case_types)]
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+#![feature(extern_types)]
+#![feature(repr_simd)]
+
+use std::ptr::NonNull;
+
+extern {
+ type Extern;
+}
+
+#[repr(simd)]
+struct S<T>(T);
+
+#[inline(never)]
+fn identity<T>(v: T) -> T {
+ v
+}
+
+fn main() {
+ let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4]));
+}
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S<T>(T);
+
+fn main() {
+ let _v: Option<S<[*mut [u8]; 4]>> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S([*mut [u8]; 4]);
+
+fn main() {
+ let _v: Option<S> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-pass
+
+#![cfg_attr(target_arch = "wasm32", feature(wasm_simd, wasm_target_feature))]
+
+#[cfg(target_arch = "wasm32")]
+fn main() {
+ unsafe {
+ a::api_with_simd_feature();
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod a {
+ use std::arch::wasm32::*;
+
+ #[target_feature(enable = "simd128")]
+ pub unsafe fn api_with_simd_feature() {
+ crate::b::api_takes_v128(u64x2(0, 1));
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod b {
+ use std::arch::wasm32::*;
+
+ #[inline(never)]
+ pub fn api_takes_v128(a: v128) -> v128 {
+ a
+ }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn main() {}
-error: lifetime parameter `'b` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^-
- | |
- | this lifetime is only used here
- | help: elide the single-use lifetime
+ | ^^-
+ | |
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
|
note: the lint level is defined here
--> $DIR/one-use-in-fn-argument-in-band.rs:4:9
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
-error: lifetime parameter `'a` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
+error: lifetime parameter `'b` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^-
- | |
- | this lifetime is only used here
- | help: elide the single-use lifetime
+ | ^^-
+ | |
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
error: aborting due to 2 previous errors
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:19:13
+ |
+LL | fn bad1() { unsafe {} }
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/lint-unused-unsafe.rs:7:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:20:13
+ |
+LL | fn bad2() { unsafe { bad1() } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:21:20
+ |
+LL | unsafe fn bad3() { unsafe {} }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:22:13
+ |
+LL | fn bad4() { unsafe { callback(||{}) } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:23:20
+ |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:26:9
+ |
+LL | unsafe { // don't put the warning here
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:32:5
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:33:9
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
// Exercise the unused_unsafe attribute in some positive and negative cases
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![allow(dead_code)]
#![deny(unused_unsafe)]
+++ /dev/null
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:16:13
- |
-LL | fn bad1() { unsafe {} }
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/lint-unused-unsafe.rs:4:9
- |
-LL | #![deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:17:13
- |
-LL | fn bad2() { unsafe { bad1() } }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:18:20
- |
-LL | unsafe fn bad3() { unsafe {} }
- | ---------------- ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:19:13
- |
-LL | fn bad4() { unsafe { callback(||{}) } }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:20:20
- |
-LL | unsafe fn bad5() { unsafe { unsf() } }
- | ---------------- ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:23:9
- |
-LL | unsafe { // don't put the warning here
- | ------ because it's nested under this `unsafe` block
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:29:5
- |
-LL | unsafe fn bad7() {
- | ---------------- because it's nested under this `unsafe` fn
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:30:9
- |
-LL | unsafe fn bad7() {
- | ---------------- because it's nested under this `unsafe` fn
-LL | unsafe {
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 8 previous errors
-
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:19:13
+ |
+LL | fn bad1() { unsafe {} }
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/lint-unused-unsafe.rs:7:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:20:13
+ |
+LL | fn bad2() { unsafe { bad1() } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:21:20
+ |
+LL | unsafe fn bad3() { unsafe {} }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:22:13
+ |
+LL | fn bad4() { unsafe { callback(||{}) } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:23:20
+ |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:26:9
+ |
+LL | unsafe { // don't put the warning here
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:33:9
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:32:5
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[b09c]::Id::This) }, (I,)), [])`
--> $DIR/repeated_projection_type.rs:19:1
|
LL | / impl<I, V: Id<This = (I,)>> X for V {
--- /dev/null
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_attribute]
+pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream {
+ quote!(
+ fn f(_: &mut i32) {}
+ fn g() {
+ f(123);
+ }
+ )
+}
//~^ ERROR mismatched types
let b: String = &format!("b");
//~^ ERROR mismatched types
+ let c: String = &mut format!("c");
+ //~^ ERROR mismatched types
+ let d: String = &mut (format!("d"));
+ //~^ ERROR mismatched types
}
| | help: consider removing the borrow: `format!("b")`
| expected due to this
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:6:21
+ |
+LL | let c: String = &mut format!("c");
+ | ------ ^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("c")`
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:8:21
+ |
+LL | let d: String = &mut (format!("d"));
+ | ------ ^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("d")`
+ | expected due to this
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for #85943: should not emit suggestions for adding
+// indirection to type parameters in where-clauses when suggesting
+// adding `?Sized`.
+struct A<T>(T) where T: Send;
+struct B(A<[u8]>);
+//~^ ERROR the size for values of type
+
+pub fn main() {
+}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:5:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | - required by this bound in `A`
+LL | struct B(A<[u8]>);
+ | ^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-check
+// aux-build:proc-macro-type-error.rs
+
+extern crate proc_macro_type_error;
+
+use proc_macro_type_error::hello;
+
+#[hello] //~ERROR mismatched types
+fn abc() {}
+
+fn x(_: &mut i32) {}
+
+macro_rules! bla {
+ () => {
+ x(123);
+ //~^ ERROR mismatched types
+ //~| SUGGESTION &mut 123
+ };
+ ($v:expr) => {
+ x($v)
+ }
+}
+
+fn main() {
+ bla!();
+ bla!(456);
+ //~^ ERROR mismatched types
+ //~| SUGGESTION &mut 456
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:8:1
+ |
+LL | #[hello]
+ | ^^^^^^^^ expected `&mut i32`, found integer
+ |
+ = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:15:11
+ |
+LL | x(123);
+ | ^^^
+ | |
+ | expected `&mut i32`, found integer
+ | help: consider mutably borrowing here: `&mut 123`
+...
+LL | bla!();
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:26:10
+ |
+LL | bla!(456);
+ | ^^^
+ | |
+ | expected `&mut i32`, found integer
+ | help: consider mutably borrowing here: `&mut 456`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
-error: symbol-name(_ZN5basic4main17h6c535bbea2051f85E)
+error: symbol-name(_ZN5basic4main17hd75b915511563828E)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic::main::h6c535bbea2051f85)
+error: demangling(basic::main::hd75b915511563828)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN5basic4main
//[legacy]~| ERROR demangling(basic::main
//[legacy]~| ERROR demangling-alt(basic::main)
- //[v0]~^^^^ ERROR symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
- //[v0]~| ERROR demangling(basic[17891616a171812d]::main)
+ //[v0]~^^^^ ERROR symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
+ //[v0]~| ERROR demangling(basic[de7d5b6b69c71f37]::main)
//[v0]~| ERROR demangling-alt(basic::main)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(main)
-error: symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
+error: symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic[17891616a171812d]::main)
+error: demangling(basic[de7d5b6b69c71f37]::main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
pub struct Unsigned<const F: u8>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
+//~^ ERROR symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
//~| ERROR demangling-alt(<const_generics_demangling::Unsigned<11>>)
impl Unsigned<11> {}
pub struct Signed<const F: i16>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
+//~^ ERROR symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
//~| ERROR demangling-alt(<const_generics_demangling::Signed<-152>>)
impl Signed<-152> {}
pub struct Bool<const F: bool>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
+//~^ ERROR symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
//~| ERROR demangling-alt(<const_generics_demangling::Bool<true>>)
impl Bool<true> {}
pub struct Char<const F: char>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
+//~^ ERROR symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
//~| ERROR demangling-alt(<const_generics_demangling::Char<'∂'>>)
impl Char<'∂'> {}
-error: symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+error: symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
--> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
--> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
+error: symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
--> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
--> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
+error: symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
--> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
--> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
+error: symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
--> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
--> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
//[legacy]~| ERROR demangling(impl1::foo::Foo::bar
//[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
- //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
+ //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(foo::Foo::bar)
//[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
//[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
//[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
- //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
+ //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
//[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
//[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
//[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
- //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
- //[v0]~| ERROR demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+ //[v0]~| ERROR demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
//[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
+error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
+error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
+error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
+error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+error: symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h6244e5288326926aE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h18eaa05e22e59176E)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h6244e5288326926a)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h18eaa05e22e59176)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
//[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
//[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
- //[v0]~| ERROR demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+ //[v0]~| ERROR demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
//[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
pub(crate) fn foo() {
for _ in 0..0 {
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+error: symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
+error: demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
//[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
//[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
- //[v0]~^^^^ ERROR symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
- //[v0]~| ERROR demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+ //[v0]~| ERROR demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
//[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
-error: symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+error: symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
+error: demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[17891616a171812d]::Bar>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3f8b57f879016e18]::Bar>::method)
--> $DIR/trait-objects.rs:16:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Foo>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Foo>::method)
--> $DIR/trait-objects.rs:28:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Baz>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Baz>::method)
--> $DIR/trait-objects.rs:40:5
|
LL | #[rustc_symbol_name]
--- /dev/null
+// only-wasm32
+// check-pass
+
+#![feature(wasm_target_feature)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn foo() {}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+extern "C" fn bar() {}
+
+trait A {
+ fn foo();
+ fn bar(&self);
+}
+
+struct B;
+
+impl B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+impl A for B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+fn no_features_enabled_on_this_function() {
+ bar();
+ foo();
+ B.bar();
+ B::foo();
+ <B as A>::foo();
+ <B as A>::bar(&B);
+}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn main() {}
--- /dev/null
+// edition:2018
+
+#![feature(thread_local)]
+#![feature(const_swap)]
+#[thread_local]
+static mut STATIC_VAR_2: [u32; 8] = [4; 8];
+const fn g(x: &mut [u32; 8]) {
+ //~^ ERROR mutable references are not allowed
+ std::mem::swap(x, &mut STATIC_VAR_2)
+ //~^ ERROR thread-local statics cannot be accessed
+ //~| ERROR mutable references are not allowed
+ //~| ERROR use of mutable static is unsafe
+ //~| constant functions cannot refer to statics
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: mutable references are not allowed in constant functions
+ --> $DIR/thread-local-static.rs:7:12
+ |
+LL | const fn g(x: &mut [u32; 8]) {
+ | ^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+ --> $DIR/thread-local-static.rs:9:28
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^
+
+error[E0013]: constant functions cannot refer to statics
+ --> $DIR/thread-local-static.rs:9:28
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0658]: mutable references are not allowed in constant functions
+ --> $DIR/thread-local-static.rs:9:23
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+ --> $DIR/thread-local-static.rs:9:23
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0013, E0133, E0658.
+For more information about an error, try `rustc --explain E0013`.
--- /dev/null
+// check-pass
+
+#![feature(trait_alias)]
+
+trait Foo = std::fmt::Display + std::fmt::Debug;
+trait bar = std::fmt::Display + std::fmt::Debug; //~WARN trait alias `bar` should have an upper camel case name
+
+fn main() {}
--- /dev/null
+warning: trait alias `bar` should have an upper camel case name
+ --> $DIR/style_lint.rs:6:7
+ |
+LL | trait bar = std::fmt::Display + std::fmt::Debug;
+ | ^^^ help: convert the identifier to upper camel case: `Bar`
+ |
+ = note: `#[warn(non_camel_case_types)]` on by default
+
+warning: 1 warning emitted
+
LL | *self += 1;
| ^^^^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
fn result_to_option() -> Option<u16> {
Some(Err("hello")?)
- //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option`
+ //~^ ERROR the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
}
fn control_flow_to_option() -> Option<u64> {
fn result_to_control_flow() -> ControlFlow<String> {
ControlFlow::Continue(Err("hello")?)
- //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+ //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
}
fn option_to_control_flow() -> ControlFlow<u64> {
Some(3)?;
- //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+ //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
ControlFlow::Break(10)
}
fn control_flow_to_control_flow() -> ControlFlow<i64> {
ControlFlow::Break(4_u8)?;
- //~^ ERROR the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+ //~^ ERROR the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s
ControlFlow::Continue(())
}
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
= note: required by `from_residual`
-error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/bad-interconversion.rs:22:22
|
LL | / fn result_to_option() -> Option<u16> {
LL | | Some(Err("hello")?)
- | | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `Option<u16>`
+ | | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
LL | |
LL | | }
| |_- this function returns an `Option`
= help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
= note: required by `from_residual`
-error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
--> $DIR/bad-interconversion.rs:32:39
|
LL | / fn result_to_control_flow() -> ControlFlow<String> {
| |_- this function returns a `ControlFlow`
|
= help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>`
- = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
= note: required by `from_residual`
-error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
--> $DIR/bad-interconversion.rs:37:12
|
LL | / fn option_to_control_flow() -> ControlFlow<u64> {
| |_- this function returns a `ControlFlow`
|
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>`
- = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
= note: required by `from_residual`
-error[E0277]: the `?` operator can only be used on `ControlFlow<B, _>`s in a function that returns `ControlFlow<B, _>`
+error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type)
--> $DIR/bad-interconversion.rs:43:29
|
LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> {
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
= note: required by `from_residual`
-error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
--> $DIR/option-to-result.rs:11:6
|
LL | / fn test_option() -> Option<i32>{
LL | | let a:Result<i32, i32> = Ok(5);
LL | | a?;
- | | ^ this `?` produces `Result<Infallible, i32>`, which is incompatible with `Option<i32>`
+ | | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
LL | | Some(5)
LL | | }
| |_- this function returns an `Option`
warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-74761.rs:4:32
+ --> $DIR/issue-74761.rs:3:32
|
LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
| ^^^^^^^^^^^^^^^^^^^^^
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:6
+ --> $DIR/issue-74761.rs:10:6
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:10
+ --> $DIR/issue-74761.rs:10:10
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:6
+ --> $DIR/issue-74761.rs:10:6
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:10
+ --> $DIR/issue-74761.rs:10:10
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
-#![feature(member_constraints)]
// revisions: min_tait full_tait
#![feature(min_type_alias_impl_trait)]
#![cfg_attr(full_tait, feature(type_alias_impl_trait))]
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
--- /dev/null
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+// This is issue #85435. But the real story is reflected in issue #85561, where
+// a bug in the implementation of feature(capture_disjoint_fields) () was
+// exposed to non-feature-gated code by a diagnostic changing PR that removed
+// the gating in one case.
+
+// This test is double-checking that the case of interest continues to work as
+// expected in the *absence* of that feature gate. At the time of this writing,
+// enabling the feature gate will cause this test to fail. We obviously cannot
+// stabilize that feature until it can correctly handle this test.
+
+fn main() {
+ let val: u8 = 5;
+ let u8_ptr: *const u8 = &val;
+ let _closure = || {
+ unsafe {
+ let tmp = *u8_ptr;
+ tmp
+
+ // Just dereferencing and returning directly compiles fine:
+ // *u8_ptr
+ }
+ };
+}
--- /dev/null
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+ |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ |
+LL | VOID = ();
+ | ^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ |
+LL | #[deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ |
+LL | VOID = ();
+ | ^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+ |
+LL | unsafe { unsafe { unsf() } }
+ | ------ ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ |
+LL | unsafe fn allow_level() {
+ | ----------------------- because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ |
+LL | unsafe fn nested_allow_level() {
+ | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(unused_unsafe)]
+++ /dev/null
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9
- |
-LL | #![deny(unsafe_op_in_unsafe_fn)]
- | ^^^^^^^^^^^^^^^^^^^^^^
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5
- |
-LL | *PTR;
- | ^^^^ dereference of raw pointer
- |
- = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
- |
-LL | VOID = ();
- | ^^^^^^^^^ use of mutable static
- |
- = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
- |
-LL | unsafe {}
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
- |
-LL | #![deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8
- |
-LL | #[deny(warnings)]
- | ^^^^^^^^
- = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
- |
-LL | *PTR;
- | ^^^^ dereference of raw pointer
- |
- = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
- |
-LL | VOID = ();
- | ^^^^^^^^^ use of mutable static
- |
- = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5
- |
-LL | unsafe {}
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14
- |
-LL | unsafe { unsafe { unsf() } }
- | ------ ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5
- |
-LL | unsafe fn allow_level() {
- | ----------------------- because it's nested under this `unsafe` fn
-...
-LL | unsafe { unsf() }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9
- |
-LL | unsafe fn nested_allow_level() {
- | ------------------------------ because it's nested under this `unsafe` fn
-...
-LL | unsafe { unsf() }
- | ^^^^^^ unnecessary `unsafe` block
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 13 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+ |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ |
+LL | VOID = ();
+ | ^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ |
+LL | #[deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ |
+LL | VOID = ();
+ | ^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+ |
+LL | unsafe { unsafe { unsf() } }
+ | ------ ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ |
+LL | unsafe fn allow_level() {
+ | ----------------------- because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ |
+LL | unsafe fn nested_allow_level() {
+ | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
LL | *p = 0;
| ^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
LL | return *p;
| ^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
LL | *a == b
| ^^ dereference of raw pointer
|
- = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to previous error
-Subproject commit 070e459c2d8b79c5b2ac5218064e7603329c92ae
+Subproject commit 0cecbd67323ca14a7eb6505900d0d7307b00355b
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
+[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
cargo_metadata = "0.12"
compiletest_rs = { version = "0.6.0", features = ["tmp"] }
tester = "0.9"
-clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
serde = { version = "1.0", features = ["derive"] }
derive-new = "0.5"
regex = "1.4"
quote = "1"
syn = { version = "1", features = ["full"] }
+# This is used by the `collect-metadata` alias.
+filetime = "0.2"
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
same "printed page" as the copyright notice for easier
identification within third-party archives.
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
MIT License
-Copyright (c) 2014-2020 The Rust Project Developers
+Copyright (c) 2014-2021 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
value` mapping eg.
```toml
+avoid-breaking-exported-api = false
blacklisted-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
## License
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
);
println!(
"cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
- rustc_tools_util::get_channel().unwrap_or_default()
+ rustc_tools_util::get_channel()
);
}
--- /dev/null
+avoid-breaking-exported-api = false
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use crate::consts::{constant, Constant};
-
use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_isize_or_usize;
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
&format!("`assert!(false, {})` should probably be replaced", panic_message),
None,
&format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
- )
+ );
};
if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
if is_relevant_item(cx, item) {
- check_attrs(cx, item.span, item.ident.name, attrs)
+ check_attrs(cx, item.span, item.ident.name, attrs);
}
match item.kind {
ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if is_relevant_impl(cx, item) {
- check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+ check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if is_relevant_trait(cx, item) {
- check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+ check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
if let ExprKind::Binary(cmp, left, right) = &e.kind {
if cmp.node.is_comparison() {
if let Some(cmp_opt) = fetch_int_literal(cx, right) {
- check_compare(cx, left, cmp.node, cmp_opt, e.span)
+ check_compare(cx, left, cmp.node, cmp_opt, e.span);
} else if let Some(cmp_val) = fetch_int_literal(cx, left) {
- check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
+ check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span);
}
}
}
}
fetch_int_literal(cx, right)
.or_else(|| fetch_int_literal(cx, left))
- .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
+ .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
}
}
_: Span,
_: HirId,
) {
- NonminimalBoolVisitor { cx }.visit_body(body)
+ NonminimalBoolVisitor { cx }.visit_body(body);
}
}
Term(n) => {
let terminal = self.terminals[n as usize];
if let Some(str) = simplify_not(self.cx, terminal) {
- self.output.push_str(&str)
+ self.output.push_str(&str);
} else {
self.output.push('!');
let snip = snippet_opt(self.cx, terminal.span)?;
}
match &e.kind {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
- self.bool_expr(e)
+ self.bool_expr(e);
},
ExprKind::Unary(UnOp::Not, inner) => {
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{method_chain_args, sext};
use if_chain::if_chain;
impl EarlyLintPass for CollapsibleIf {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
if !expr.span.from_expansion() {
- check_if(cx, expr)
+ check_if(cx, expr);
}
}
}
"`if` chain can be rewritten with `match`",
None,
"consider rewriting the `if` chain to use `cmp` and `match`",
- )
+ );
}
}
+++ /dev/null
-pub use clippy_utils::consts::*;
}
suggestions.push(("end", span, suggestion.to_string()));
- add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+ add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit();
}
let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
match stmt.kind {
StmtKind::Local(local) => {
if local.ty.is_some() {
- self.ty_bounds.push(TyBound::Any)
+ self.ty_bounds.push(TyBound::Any);
} else {
- self.ty_bounds.push(TyBound::Nothing)
+ self.ty_bounds.push(TyBound::Nothing);
}
},
pub FILTER_MAP,
"this lint has been replaced by `manual_filter_map`, a more specific lint"
}
+
+declare_deprecated_lint! {
+ /// **What it does:** Nothing. This lint has been deprecated.
+ ///
+ /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+ /// enables the `enum_variant_names` lint for public items.
+ /// ```
+ pub PUB_ENUM_VARIANT_NAMES,
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items"
+}
+
+declare_deprecated_lint! {
+ /// **What it does:** Nothing. This lint has been deprecated.
+ ///
+ /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+ /// enables the `wrong_self_conversion` lint for public items.
+ pub WRONG_PUB_SELF_CONVENTION,
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items"
+}
#[rustfmt::skip]
match (op, lkind, rkind) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
- lint_double_comparison!(<=)
+ lint_double_comparison!(<=);
},
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
- lint_double_comparison!(>=)
+ lint_double_comparison!(>=);
},
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
- lint_double_comparison!(!=)
+ lint_double_comparison!(!=);
},
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
- lint_double_comparison!(==)
+ lint_double_comparison!(==);
},
_ => (),
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths;
let mut is_map_used = self.is_map_used;
for arm in arms {
if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
- self.visit_non_tail_expr(guard)
+ self.visit_non_tail_expr(guard);
}
is_map_used |= self.visit_cond_arm(arm.body);
}
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
-use crate::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{miri_to_const, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
-use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_hir::{EnumDef, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
"enums where all variants share a prefix/postfix"
}
-declare_clippy_lint! {
- /// **What it does:** Detects public enumeration variants that are
- /// prefixed or suffixed by the same characters.
- ///
- /// **Why is this bad?** Public enumeration variant names should specify their variant,
- /// not repeat the enumeration name.
- ///
- /// **Known problems:** None.
- ///
- /// **Example:**
- /// ```rust
- /// pub enum Cake {
- /// BlackForestCake,
- /// HummingbirdCake,
- /// BattenbergCake,
- /// }
- /// ```
- /// Could be written as:
- /// ```rust
- /// pub enum Cake {
- /// BlackForest,
- /// Hummingbird,
- /// Battenberg,
- /// }
- /// ```
- pub PUB_ENUM_VARIANT_NAMES,
- pedantic,
- "public enums where all variants share a prefix/postfix"
-}
-
declare_clippy_lint! {
/// **What it does:** Detects type names that are prefixed or suffixed by the
/// containing module's name.
pub struct EnumVariantNames {
modules: Vec<(Symbol, String)>,
threshold: u64,
+ avoid_breaking_exported_api: bool,
}
impl EnumVariantNames {
#[must_use]
- pub fn new(threshold: u64) -> Self {
+ pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
Self {
modules: Vec::new(),
threshold,
+ avoid_breaking_exported_api,
}
}
}
impl_lint_pass!(EnumVariantNames => [
ENUM_VARIANT_NAMES,
- PUB_ENUM_VARIANT_NAMES,
MODULE_NAME_REPETITIONS,
MODULE_INCEPTION
]);
}
fn check_variant(
- cx: &EarlyContext<'_>,
+ cx: &LateContext<'_>,
threshold: u64,
- def: &EnumDef,
+ def: &EnumDef<'_>,
item_name: &str,
item_name_chars: usize,
span: Span,
- lint: &'static Lint,
) {
if (def.variants.len() as u64) < threshold {
return;
}
- for var in &def.variants {
+ for var in def.variants {
let name = var.ident.name.as_str();
if partial_match(item_name, &name) == 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())
{
- span_lint(cx, lint, var.span, "variant name starts with the enum's name");
+ span_lint(
+ cx,
+ ENUM_VARIANT_NAMES,
+ var.span,
+ "variant name starts with the enum's name",
+ );
}
if partial_rmatch(item_name, &name) == item_name_chars {
- span_lint(cx, lint, var.span, "variant name ends with the enum's name");
+ span_lint(
+ cx,
+ ENUM_VARIANT_NAMES,
+ var.span,
+ "variant name ends with the enum's name",
+ );
}
}
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)..];
- for var in &def.variants {
+ for var in def.variants {
let name = var.ident.name.as_str();
let pre_match = partial_match(pre, &name);
};
span_lint_and_help(
cx,
- lint,
+ ENUM_VARIANT_NAMES,
span,
&format!("all variants have the same {}fix: `{}`", what, value),
None,
s
}
-impl EarlyLintPass for EnumVariantNames {
- fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
+impl LateLintPass<'_> for EnumVariantNames {
+ fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
let last = self.modules.pop();
assert!(last.is_some());
}
#[allow(clippy::similar_names)]
- fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = item.ident.name.as_str();
let item_name_chars = item_name.chars().count();
let item_camel = to_camel_case(&item_name);
);
}
}
- if item.vis.kind.is_pub() {
+ if item.vis.node.is_pub() {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
}
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let lint = match item.vis.kind {
- VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
- _ => ENUM_VARIANT_NAMES,
- };
- check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
+ if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+ check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
+ }
}
self.modules.push((item.ident.name, item_camel));
}
vec![(left.span, lsnip), (right.span, rsnip)],
);
},
- )
+ );
} else if lcpy
&& !rcpy
&& implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
} else if !lcpy
&& rcpy
&& implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
}
},
// &foo == bar
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
}
},
// foo == &bar
rsnip,
Applicability::MaybeIncorrect, // FIXME #2597
);
- })
+ });
}
},
_ => {},
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{constant_simple, Constant};
-
declare_clippy_lint! {
/// **What it does:** Checks for erasing operations, e.g., `x * 0`.
///
for arg in args {
// skip `foo(macro!())`
if arg.span.ctxt() == expr.span.ctxt() {
- check_closure(cx, arg)
+ check_closure(cx, arg);
}
}
},
let ex = &body.value;
if ex.span.ctxt() != expr.span.ctxt() {
- if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
- // replace `|| vec![]` with `Vec::new`
- span_lint_and_sugg(
- cx,
- REDUNDANT_CLOSURE,
- expr.span,
- "redundant closure",
- "replace the closure with `Vec::new`",
- "std::vec::Vec::new".into(),
- Applicability::MachineApplicable,
- );
+ if decl.inputs.is_empty() {
+ if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+ // replace `|| vec![]` with `Vec::new`
+ span_lint_and_sugg(
+ cx,
+ REDUNDANT_CLOSURE,
+ expr.span,
+ "redundant closure",
+ "replace the closure with `Vec::new`",
+ "std::vec::Vec::new".into(),
+ Applicability::MachineApplicable,
+ );
+ }
}
// skip `foo(|| macro!())`
return;
cx.tcx.impl_of_method(method_def_id).and_then(|_| {
//a type may implicitly implement other type's methods (e.g. Deref)
if match_types(expected_type_of_self, actual_type_of_self) {
- return Some(get_type_name(cx, actual_type_of_self));
+ Some(get_type_name(cx, actual_type_of_self))
+ } else {
+ None
}
- None
})
}
self.visit_expr(e);
for arm in arms {
if let Some(Guard::If(if_expr)) = arm.guard {
- self.visit_expr(if_expr)
+ self.visit_expr(if_expr);
}
// make sure top level arm expressions aren't linted
self.maybe_walk_expr(&*arm.body);
-use crate::consts::{
+use clippy_utils::consts::{
constant, constant_simple, Constant,
Constant::{Int, F32, F64},
};
}
},
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
- self.mutates_static |= is_mutated_static(target)
+ self.mutates_static |= is_mutated_static(target);
},
_ => {},
}
self.cx,
NOT_UNSAFE_PTR_ARG_DEREF,
ptr.span,
- "this public function dereferences a raw pointer but is not marked `unsafe`",
+ "this public function might dereference a raw pointer but is not marked `unsafe`",
);
}
}
use rustc_span::Span;
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_opt;
use super::TOO_MANY_LINES;
return;
}
- let code_snippet = snippet(cx, body.value.span, "..");
+ let code_snippet = match snippet_opt(cx, body.value.span) {
+ Some(s) => s,
+ _ => return,
+ };
let mut line_count: u64 = 0;
let mut in_comment = false;
let mut code_in_line;
- // Skip the surrounding function decl.
- let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
- let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
- let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+ let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
+ && code_snippet.as_bytes().first().copied() == Some(b'{')
+ && code_snippet.as_bytes().last().copied() == Some(b'}')
+ {
+ // Removing the braces from the enclosing block
+ &code_snippet[1..code_snippet.len() - 1]
+ } else {
+ &code_snippet
+ }
+ .trim() // Remove leading and trailing blank lines
+ .lines();
for mut line in function_lines {
code_in_line = false;
"this function has too many lines ({}/{})",
line_count, too_many_lines_threshold
),
- )
+ );
}
}
));
}
}
- })
+ });
},
);
}
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{clip, unsext};
"change `break` to `return` as shown",
format!("return {}", snip),
app,
- )
+ );
}
#[derive(Clone, Copy, PartialEq, Eq)]
//! lint on indexing and slicing operations
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::higher;
use rustc_ast::ast::RangeLimits;
return;
},
};
- span_lint(cx, lint, expr.span, msg)
+ span_lint(cx, lint, expr.span, msg);
}
}
use rustc_span::Span;
use rustc_target::abi::LayoutOf;
-use crate::consts::{constant, Constant};
-
use clippy_utils::comparisons::Rel;
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{comparisons, sext};
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
- err_upcast_comparison(cx, span, lhs, true)
+ err_upcast_comparison(cx, span, lhs, true);
} else if match rel {
Rel::Lt => {
if invert {
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
- err_upcast_comparison(cx, span, lhs, false)
+ err_upcast_comparison(cx, span, lhs, false);
}
}
}
}
}
- check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+ check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
} else {
- check_empty_expr(cx, span, method, lit, op)
+ check_empty_expr(cx, span, method, lit, op);
}
}
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
- )
+ );
} else if init_ty.needs_drop(cx.tcx, cx.param_env) {
span_lint_and_help(
cx,
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
- )
+ );
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,
"non-binding let on an expression with `#[must_use]` type",
None,
"consider explicitly using expression value"
- )
+ );
} else if is_must_use_func_call(cx, init) {
span_lint_and_help(
cx,
"non-binding let on a result of a `#[must_use]` function",
None,
"consider explicitly using function result"
- )
+ );
}
}
}
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(rustc_private)]
#![feature(stmt_expr_attributes)]
#![feature(control_flow_enum)]
extern crate rustc_trait_selection;
extern crate rustc_typeck;
+#[macro_use]
+extern crate clippy_utils;
+
use clippy_utils::parse_msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::LintId;
};
}
-#[macro_export]
-macro_rules! sym {
- ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
-}
-
-#[macro_export]
-macro_rules! unwrap_cargo_metadata {
- ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
-}
-
-macro_rules! extract_msrv_attr {
- ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
-}
-
-mod consts;
-#[macro_use]
-mod utils;
#[cfg(feature = "metadata-collector-lint")]
mod deprecated_lints;
+mod utils;
// begin lints modules, do not remove this comment, it’s used in `update_lints`
mod absurd_extreme_comparisons;
#[doc(hidden)]
pub fn read_conf(sess: &Session) -> Conf {
- use std::path::Path;
let file_name = match utils::conf::lookup_conf_file() {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
},
};
- let file_name = if file_name.is_relative() {
- sess.local_crate_source_file
- .as_deref()
- .and_then(Path::parent)
- .unwrap_or_else(|| Path::new(""))
- .join(file_name)
- } else {
- file_name
- };
-
let TryConf { conf, errors } = utils::conf::read(&file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
"clippy::filter_map",
"this lint has been replaced by `manual_filter_map`, a more specific lint",
);
+ store.register_removed(
+ "clippy::pub_enum_variant_names",
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items",
+ );
+ store.register_removed(
+ "clippy::wrong_pub_self_convention",
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items",
+ );
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
// begin register lints, do not remove this comment, it’s used in `update_lints`
enum_variants::ENUM_VARIANT_NAMES,
enum_variants::MODULE_INCEPTION,
enum_variants::MODULE_NAME_REPETITIONS,
- enum_variants::PUB_ENUM_VARIANT_NAMES,
eq_op::EQ_OP,
eq_op::OP_REF,
erasing_op::ERASING_OP,
methods::MANUAL_FILTER_MAP,
methods::MANUAL_FIND_MAP,
methods::MANUAL_SATURATING_ARITHMETIC,
+ methods::MANUAL_STR_REPEAT,
methods::MAP_COLLECT_RESULT_UNIT,
methods::MAP_FLATTEN,
methods::MAP_UNWRAP_OR,
methods::SKIP_WHILE_NEXT,
methods::STRING_EXTEND_CHARS,
methods::SUSPICIOUS_MAP,
+ methods::SUSPICIOUS_SPLITN,
methods::UNINIT_ASSUMED_INIT,
methods::UNNECESSARY_FILTER_MAP,
methods::UNNECESSARY_FOLD,
methods::UNNECESSARY_LAZY_EVALUATIONS,
methods::UNWRAP_USED,
methods::USELESS_ASREF,
- methods::WRONG_PUB_SELF_CONVENTION,
methods::WRONG_SELF_CONVENTION,
methods::ZST_OFFSET,
minmax::MIN_MAX,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,
needless_borrow::NEEDLESS_BORROW,
+ needless_borrow::REF_BINDING_TO_REFERENCE,
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
needless_continue::NEEDLESS_CONTINUE,
needless_for_each::NEEDLESS_FOR_EACH,
]);
// end register lints, do not remove this comment, it’s used in `update_lints`
- // all the internal lints
- #[cfg(feature = "internal-lints")]
- {
- store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
- store.register_early_pass(|| box utils::internal_lints::ProduceIce);
- store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
- store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
- store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
- store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
- store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
- store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
- store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
- store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
- store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
- }
- #[cfg(feature = "metadata-collector-lint")]
- {
- if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
- store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
- }
- }
+ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
+ LintId::of(arithmetic::FLOAT_ARITHMETIC),
+ LintId::of(arithmetic::INTEGER_ARITHMETIC),
+ 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(create_dir::CREATE_DIR),
+ LintId::of(dbg_macro::DBG_MACRO),
+ LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
+ LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+ LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
+ LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
+ LintId::of(exit::EXIT),
+ LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
+ LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
+ LintId::of(implicit_return::IMPLICIT_RETURN),
+ LintId::of(indexing_slicing::INDEXING_SLICING),
+ LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
+ LintId::of(integer_division::INTEGER_DIVISION),
+ LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
+ LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
+ LintId::of(map_err_ignore::MAP_ERR_IGNORE),
+ LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
+ LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
+ LintId::of(mem_forget::MEM_FORGET),
+ LintId::of(methods::CLONE_ON_REF_PTR),
+ LintId::of(methods::EXPECT_USED),
+ LintId::of(methods::FILETYPE_IS_FILE),
+ LintId::of(methods::GET_UNWRAP),
+ LintId::of(methods::UNWRAP_USED),
+ LintId::of(misc::FLOAT_CMP_CONST),
+ LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+ LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
+ LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+ LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
+ LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
+ LintId::of(panic_unimplemented::PANIC),
+ LintId::of(panic_unimplemented::TODO),
+ LintId::of(panic_unimplemented::UNIMPLEMENTED),
+ LintId::of(panic_unimplemented::UNREACHABLE),
+ LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
+ LintId::of(shadow::SHADOW_REUSE),
+ LintId::of(shadow::SHADOW_SAME),
+ LintId::of(strings::STRING_ADD),
+ LintId::of(strings::STRING_TO_STRING),
+ LintId::of(strings::STR_TO_STRING),
+ LintId::of(types::RC_BUFFER),
+ 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(write::PRINT_STDERR),
+ LintId::of(write::PRINT_STDOUT),
+ LintId::of(write::USE_DEBUG),
+ ]);
- store.register_late_pass(|| box utils::author::Author);
- store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
- store.register_late_pass(|| box serde_api::SerdeApi);
- let vec_box_size_threshold = conf.vec_box_size_threshold;
- let type_complexity_threshold = conf.type_complexity_threshold;
- store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
- store.register_late_pass(|| box booleans::NonminimalBool);
- store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
- store.register_late_pass(|| box eq_op::EqOp);
- store.register_late_pass(|| box enum_clike::UnportableVariant);
- store.register_late_pass(|| box float_literal::FloatLiteral);
- let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
- store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
- store.register_late_pass(|| box ptr::Ptr);
- store.register_late_pass(|| box ptr_eq::PtrEq);
- store.register_late_pass(|| box needless_bool::NeedlessBool);
- store.register_late_pass(|| box needless_bool::BoolComparison);
- store.register_late_pass(|| box needless_for_each::NeedlessForEach);
- store.register_late_pass(|| box approx_const::ApproxConstant);
- store.register_late_pass(|| box misc::MiscLints);
- store.register_late_pass(|| box eta_reduction::EtaReduction);
- store.register_late_pass(|| box identity_op::IdentityOp);
- store.register_late_pass(|| box erasing_op::ErasingOp);
- store.register_late_pass(|| box mut_mut::MutMut);
- store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
- store.register_late_pass(|| box len_zero::LenZero);
- store.register_late_pass(|| box attrs::Attributes);
- store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
- store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
- store.register_late_pass(|| box unicode::Unicode);
- store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
- store.register_late_pass(|| box strings::StringAdd);
- store.register_late_pass(|| box implicit_return::ImplicitReturn);
- store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
- store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
- store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
- store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
- store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
+ LintId::of(attrs::INLINE_ALWAYS),
+ LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
+ LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
+ LintId::of(bit_mask::VERBOSE_BIT_MASK),
+ LintId::of(bytecount::NAIVE_BYTECOUNT),
+ LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+ LintId::of(casts::CAST_LOSSLESS),
+ LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
+ LintId::of(casts::CAST_POSSIBLE_WRAP),
+ LintId::of(casts::CAST_PRECISION_LOSS),
+ LintId::of(casts::CAST_PTR_ALIGNMENT),
+ LintId::of(casts::CAST_SIGN_LOSS),
+ LintId::of(casts::PTR_AS_PTR),
+ LintId::of(checked_conversions::CHECKED_CONVERSIONS),
+ LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
+ LintId::of(copy_iterator::COPY_ITERATOR),
+ LintId::of(default::DEFAULT_TRAIT_ACCESS),
+ LintId::of(dereference::EXPLICIT_DEREF_METHODS),
+ LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
+ LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
+ LintId::of(doc::DOC_MARKDOWN),
+ LintId::of(doc::MISSING_ERRORS_DOC),
+ LintId::of(doc::MISSING_PANICS_DOC),
+ LintId::of(empty_enum::EMPTY_ENUM),
+ LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
+ LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
+ LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
+ LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+ LintId::of(functions::MUST_USE_CANDIDATE),
+ LintId::of(functions::TOO_MANY_LINES),
+ LintId::of(if_not_else::IF_NOT_ELSE),
+ LintId::of(implicit_hasher::IMPLICIT_HASHER),
+ LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+ LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
+ LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
+ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
+ LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
+ LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
+ LintId::of(let_underscore::LET_UNDERSCORE_DROP),
+ LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
+ LintId::of(literal_representation::UNREADABLE_LITERAL),
+ LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
+ LintId::of(loops::EXPLICIT_ITER_LOOP),
+ LintId::of(macro_use::MACRO_USE_IMPORTS),
+ 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(matches::MATCH_SAME_ARMS),
+ LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
+ LintId::of(matches::MATCH_WILD_ERR_ARM),
+ LintId::of(matches::SINGLE_MATCH_ELSE),
+ LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
+ LintId::of(methods::FILTER_MAP_NEXT),
+ LintId::of(methods::FLAT_MAP_OPTION),
+ LintId::of(methods::IMPLICIT_CLONE),
+ LintId::of(methods::INEFFICIENT_TO_STRING),
+ LintId::of(methods::MAP_FLATTEN),
+ LintId::of(methods::MAP_UNWRAP_OR),
+ 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(non_expressive_names::SIMILAR_NAMES),
+ LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
+ LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
+ LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
+ LintId::of(ranges::RANGE_MINUS_ONE),
+ LintId::of(ranges::RANGE_PLUS_ONE),
+ LintId::of(redundant_else::REDUNDANT_ELSE),
+ LintId::of(ref_option_ref::REF_OPTION_REF),
+ LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
+ LintId::of(shadow::SHADOW_UNRELATED),
+ LintId::of(strings::STRING_ADD_ASSIGN),
+ LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+ LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
+ 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),
+ LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+ LintId::of(unused_async::UNUSED_ASYNC),
+ LintId::of(unused_self::UNUSED_SELF),
+ LintId::of(wildcard_imports::ENUM_GLOB_USE),
+ LintId::of(wildcard_imports::WILDCARD_IMPORTS),
+ LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
+ ]);
- let msrv = conf.msrv.as_ref().and_then(|s| {
- parse_msrv(s, None, None).or_else(|| {
- sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
- None
- })
- });
-
- store.register_late_pass(move || box methods::Methods::new(msrv));
- store.register_late_pass(move || box matches::Matches::new(msrv));
- store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
- store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
- store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
- store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
- store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
- store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
- store.register_late_pass(move || box ranges::Ranges::new(msrv));
- store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
- store.register_late_pass(move || box use_self::UseSelf::new(msrv));
- store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
- store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
- store.register_late_pass(move || box casts::Casts::new(msrv));
- store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
-
- store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
- store.register_late_pass(|| box map_clone::MapClone);
- store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
- store.register_late_pass(|| box shadow::Shadow);
- store.register_late_pass(|| box unit_types::UnitTypes);
- store.register_late_pass(|| box loops::Loops);
- store.register_late_pass(|| box main_recursion::MainRecursion::default());
- store.register_late_pass(|| box lifetimes::Lifetimes);
- store.register_late_pass(|| box entry::HashMapPass);
- store.register_late_pass(|| box minmax::MinMaxPass);
- store.register_late_pass(|| box open_options::OpenOptions);
- store.register_late_pass(|| box zero_div_zero::ZeroDiv);
- store.register_late_pass(|| box mutex_atomic::Mutex);
- store.register_late_pass(|| box needless_update::NeedlessUpdate);
- store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
- store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
- store.register_late_pass(|| box no_effect::NoEffect);
- store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
- store.register_late_pass(|| box transmute::Transmute);
- let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
- store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
- let too_large_for_stack = conf.too_large_for_stack;
- store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
- store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
- store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
- store.register_late_pass(|| box strings::StringLitAsBytes);
- store.register_late_pass(|| box derive::Derive);
- store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
- store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
- store.register_late_pass(|| box empty_enum::EmptyEnum);
- store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
- store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
- store.register_late_pass(|| box regex::Regex::default());
- store.register_late_pass(|| box copies::CopyAndPaste);
- store.register_late_pass(|| box copy_iterator::CopyIterator);
- store.register_late_pass(|| box format::UselessFormat);
- store.register_late_pass(|| box swap::Swap);
- store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
- store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
- let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
- let too_many_arguments_threshold = conf.too_many_arguments_threshold;
- let too_many_lines_threshold = conf.too_many_lines_threshold;
- store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
- let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
- store.register_late_pass(|| box neg_multiply::NegMultiply);
- store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
- store.register_late_pass(|| box mem_forget::MemForget);
- store.register_late_pass(|| box arithmetic::Arithmetic::default());
- store.register_late_pass(|| box assign_ops::AssignOps);
- store.register_late_pass(|| box let_if_seq::LetIfSeq);
- store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
- store.register_late_pass(|| box missing_doc::MissingDoc::new());
- store.register_late_pass(|| box missing_inline::MissingInline);
- store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
- store.register_late_pass(|| box if_let_some_result::OkIfLet);
- store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
- store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
- let enum_variant_size_threshold = conf.enum_variant_size_threshold;
- store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
- store.register_late_pass(|| box explicit_write::ExplicitWrite);
- store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
- let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
- conf.trivial_copy_size_limit,
- conf.pass_by_value_size_limit,
- &sess.target,
- );
- store.register_late_pass(move || box pass_by_ref_or_value);
- store.register_late_pass(|| box ref_option_ref::RefOptionRef);
- store.register_late_pass(|| box try_err::TryErr);
- store.register_late_pass(|| box bytecount::ByteCount);
- store.register_late_pass(|| box infinite_iter::InfiniteIter);
- store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
- store.register_late_pass(|| box useless_conversion::UselessConversion::default());
- store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
- store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
- store.register_late_pass(|| box double_comparison::DoubleComparisons);
- store.register_late_pass(|| box question_mark::QuestionMark);
- store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
- store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
- store.register_late_pass(|| box map_unit_fn::MapUnit);
- store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
- store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
- store.register_late_pass(|| box unwrap::Unwrap);
- store.register_late_pass(|| box duration_subsec::DurationSubsec);
- store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
- store.register_late_pass(|| box non_copy_const::NonCopyConst);
- store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
- store.register_late_pass(|| box redundant_clone::RedundantClone);
- store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
- store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
- store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
- store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
- store.register_late_pass(|| box transmuting_null::TransmutingNull);
- store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
- store.register_late_pass(|| box integer_division::IntegerDivision);
- store.register_late_pass(|| box inherent_to_string::InherentToString);
- let max_trait_bounds = conf.max_trait_bounds;
- store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
- store.register_late_pass(|| box comparison_chain::ComparisonChain);
- store.register_late_pass(|| box mut_key::MutableKeyType);
- store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
- store.register_early_pass(|| box reference::DerefAddrOf);
- store.register_early_pass(|| box reference::RefInDeref);
- store.register_early_pass(|| box double_parens::DoubleParens);
- store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
- store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
- store.register_early_pass(|| box if_not_else::IfNotElse);
- store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
- store.register_early_pass(|| box int_plus_one::IntPlusOne);
- store.register_early_pass(|| box formatting::Formatting);
- store.register_early_pass(|| box misc_early::MiscEarlyLints);
- store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
- store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
- store.register_early_pass(|| box unused_unit::UnusedUnit);
- store.register_late_pass(|| box returns::Return);
- store.register_early_pass(|| box collapsible_if::CollapsibleIf);
- store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
- store.register_early_pass(|| box precedence::Precedence);
- store.register_early_pass(|| box needless_continue::NeedlessContinue);
- store.register_early_pass(|| box redundant_else::RedundantElse);
- store.register_late_pass(|| box create_dir::CreateDir);
- store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
- let cargo_ignore_publish = conf.cargo_ignore_publish;
- store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
- store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
- store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
- let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
- store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
- let literal_representation_threshold = conf.literal_representation_threshold;
- store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
- let enum_variant_name_threshold = conf.enum_variant_name_threshold;
- store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
- store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
- let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
- store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive));
- store.register_late_pass(|| box default::Default::default());
- store.register_late_pass(|| box unused_self::UnusedSelf);
- store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
- store.register_late_pass(|| box exit::Exit);
- store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
- let array_size_threshold = conf.array_size_threshold;
- store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
- store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
- store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
- store.register_early_pass(|| box as_conversions::AsConversions);
- store.register_late_pass(|| box let_underscore::LetUnderscore);
- store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
- store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
- let max_fn_params_bools = conf.max_fn_params_bools;
- let max_struct_bools = conf.max_struct_bools;
- store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
- store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
- let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
- store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
- store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
- store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
- store.register_late_pass(|| box unnamed_address::UnnamedAddress);
- store.register_late_pass(|| box dereference::Dereferencing::default());
- store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
- store.register_late_pass(|| box future_not_send::FutureNotSend);
- store.register_late_pass(|| box if_let_mutex::IfLetMutex);
- store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
- store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
- store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
- store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
- store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
- let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
- store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
- single_char_binding_names_threshold,
- });
- store.register_late_pass(|| box macro_use::MacroUseImports::default());
- store.register_late_pass(|| box map_identity::MapIdentity);
- store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
- store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
- store.register_late_pass(|| box repeat_once::RepeatOnce);
- store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
- store.register_late_pass(|| box self_assignment::SelfAssignment);
- store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
- store.register_late_pass(|| box manual_ok_or::ManualOkOr);
- store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
- store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
- store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
- let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
- store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
- store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
- store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
- store.register_late_pass(|| box strings::StrToString);
- store.register_late_pass(|| box strings::StringToString);
- store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
- store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
- store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
- store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
- store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
- store.register_late_pass(|| box manual_map::ManualMap);
- store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
- store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
- store.register_late_pass(|| box unused_async::UnusedAsync);
-
- store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
- LintId::of(arithmetic::FLOAT_ARITHMETIC),
- LintId::of(arithmetic::INTEGER_ARITHMETIC),
- 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(create_dir::CREATE_DIR),
- LintId::of(dbg_macro::DBG_MACRO),
- LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
- LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
- LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
- LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
- LintId::of(exit::EXIT),
- LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
- LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
- LintId::of(implicit_return::IMPLICIT_RETURN),
- LintId::of(indexing_slicing::INDEXING_SLICING),
- LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
- LintId::of(integer_division::INTEGER_DIVISION),
- LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
- LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
- LintId::of(map_err_ignore::MAP_ERR_IGNORE),
- LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
- LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
- LintId::of(mem_forget::MEM_FORGET),
- LintId::of(methods::CLONE_ON_REF_PTR),
- LintId::of(methods::EXPECT_USED),
- LintId::of(methods::FILETYPE_IS_FILE),
- LintId::of(methods::GET_UNWRAP),
- LintId::of(methods::UNWRAP_USED),
- LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
- LintId::of(misc::FLOAT_CMP_CONST),
- LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
- LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
- LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
- LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
- LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
- LintId::of(panic_unimplemented::PANIC),
- LintId::of(panic_unimplemented::TODO),
- LintId::of(panic_unimplemented::UNIMPLEMENTED),
- LintId::of(panic_unimplemented::UNREACHABLE),
- LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
- LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
- LintId::of(shadow::SHADOW_REUSE),
- LintId::of(shadow::SHADOW_SAME),
- LintId::of(strings::STRING_ADD),
- LintId::of(strings::STRING_TO_STRING),
- LintId::of(strings::STR_TO_STRING),
- LintId::of(types::RC_BUFFER),
- 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(write::PRINT_STDERR),
- LintId::of(write::PRINT_STDOUT),
- LintId::of(write::USE_DEBUG),
- ]);
-
- store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
- LintId::of(attrs::INLINE_ALWAYS),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- LintId::of(bit_mask::VERBOSE_BIT_MASK),
- LintId::of(bytecount::NAIVE_BYTECOUNT),
- LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
- LintId::of(casts::CAST_LOSSLESS),
- LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
- LintId::of(casts::CAST_POSSIBLE_WRAP),
- LintId::of(casts::CAST_PRECISION_LOSS),
- LintId::of(casts::CAST_PTR_ALIGNMENT),
- LintId::of(casts::CAST_SIGN_LOSS),
- LintId::of(casts::PTR_AS_PTR),
- LintId::of(checked_conversions::CHECKED_CONVERSIONS),
- LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
- LintId::of(copy_iterator::COPY_ITERATOR),
- LintId::of(default::DEFAULT_TRAIT_ACCESS),
- LintId::of(dereference::EXPLICIT_DEREF_METHODS),
- LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
- LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
- LintId::of(doc::DOC_MARKDOWN),
- LintId::of(doc::MISSING_ERRORS_DOC),
- LintId::of(doc::MISSING_PANICS_DOC),
- LintId::of(empty_enum::EMPTY_ENUM),
- LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
- LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
- LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
- LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
- LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
- LintId::of(functions::MUST_USE_CANDIDATE),
- LintId::of(functions::TOO_MANY_LINES),
- LintId::of(if_not_else::IF_NOT_ELSE),
- LintId::of(implicit_hasher::IMPLICIT_HASHER),
- LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
- LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
- LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
- LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
- LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
- LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
- LintId::of(let_underscore::LET_UNDERSCORE_DROP),
- LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
- LintId::of(literal_representation::UNREADABLE_LITERAL),
- LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
- LintId::of(loops::EXPLICIT_ITER_LOOP),
- LintId::of(macro_use::MACRO_USE_IMPORTS),
- 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(matches::MATCH_SAME_ARMS),
- LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
- LintId::of(matches::MATCH_WILD_ERR_ARM),
- LintId::of(matches::SINGLE_MATCH_ELSE),
- LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
- LintId::of(methods::FILTER_MAP_NEXT),
- LintId::of(methods::FLAT_MAP_OPTION),
- LintId::of(methods::IMPLICIT_CLONE),
- LintId::of(methods::INEFFICIENT_TO_STRING),
- LintId::of(methods::MAP_FLATTEN),
- LintId::of(methods::MAP_UNWRAP_OR),
- 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_continue::NEEDLESS_CONTINUE),
- LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
- LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
- LintId::of(non_expressive_names::SIMILAR_NAMES),
- LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
- LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
- LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
- LintId::of(ranges::RANGE_MINUS_ONE),
- LintId::of(ranges::RANGE_PLUS_ONE),
- LintId::of(redundant_else::REDUNDANT_ELSE),
- LintId::of(ref_option_ref::REF_OPTION_REF),
- LintId::of(shadow::SHADOW_UNRELATED),
- LintId::of(strings::STRING_ADD_ASSIGN),
- LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
- LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
- 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),
- LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
- LintId::of(unused_async::UNUSED_ASYNC),
- LintId::of(unused_self::UNUSED_SELF),
- LintId::of(wildcard_imports::ENUM_GLOB_USE),
- LintId::of(wildcard_imports::WILDCARD_IMPORTS),
- LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
- ]);
-
- #[cfg(feature = "internal-lints")]
- store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
- LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
- LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
- LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
- LintId::of(utils::internal_lints::DEFAULT_LINT),
- LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
- LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
- LintId::of(utils::internal_lints::INVALID_PATHS),
- LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
- LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
- LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
- LintId::of(utils::internal_lints::PRODUCE_ICE),
- LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
- ]);
+ #[cfg(feature = "internal-lints")]
+ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
+ LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
+ LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
+ LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
+ LintId::of(utils::internal_lints::DEFAULT_LINT),
+ LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
+ LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
+ LintId::of(utils::internal_lints::INVALID_PATHS),
+ LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+ LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
+ LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
+ LintId::of(utils::internal_lints::PRODUCE_ICE),
+ LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+ ]);
store.register_group(true, "clippy::all", Some("clippy"), vec![
LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+ LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::OK_EXPECT),
LintId::of(methods::SKIP_WHILE_NEXT),
LintId::of(methods::STRING_EXTEND_CHARS),
LintId::of(methods::SUSPICIOUS_MAP),
+ LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
+ LintId::of(needless_borrow::NEEDLESS_BORROW),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
- LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(swap::ALMOST_SWAPPED),
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+ LintId::of(needless_borrow::NEEDLESS_BORROW),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
- LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
LintId::of(try_err::TRY_ERR),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+ LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
LintId::of(loops::NEEDLESS_COLLECT),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::ITER_NTH),
+ LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::SINGLE_CHAR_PATTERN),
LintId::of(misc::CMP_OWNED),
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
]);
- store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
- LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
- LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
- LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
- ]);
+ store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
+ LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
+ LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
+ LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
+ ]);
+
+ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
+ LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+ LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
+ LintId::of(disallowed_method::DISALLOWED_METHOD),
+ LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
+ LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
+ LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
+ LintId::of(future_not_send::FUTURE_NOT_SEND),
+ LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+ 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(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
+ LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
+ LintId::of(regex::TRIVIAL_REGEX),
+ LintId::of(strings::STRING_LIT_AS_BYTES),
+ LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+ LintId::of(transmute::USELESS_TRANSMUTE),
+ LintId::of(use_self::USE_SELF),
+ ]);
+
+ #[cfg(feature = "metadata-collector-lint")]
+ {
+ if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
+ store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
+ return;
+ }
+ }
+
+ // all the internal lints
+ #[cfg(feature = "internal-lints")]
+ {
+ store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
+ store.register_early_pass(|| box utils::internal_lints::ProduceIce);
+ store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
+ store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
+ store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+ store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
+ store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
+ store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
+ store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
+ store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+ store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
+ }
+
+ store.register_late_pass(|| box utils::author::Author);
+ store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
+ store.register_late_pass(|| box serde_api::SerdeApi);
+ let vec_box_size_threshold = conf.vec_box_size_threshold;
+ let type_complexity_threshold = conf.type_complexity_threshold;
+ store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
+ store.register_late_pass(|| box booleans::NonminimalBool);
+ store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
+ store.register_late_pass(|| box eq_op::EqOp);
+ store.register_late_pass(|| box enum_clike::UnportableVariant);
+ store.register_late_pass(|| box float_literal::FloatLiteral);
+ let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
+ store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
+ store.register_late_pass(|| box ptr::Ptr);
+ store.register_late_pass(|| box ptr_eq::PtrEq);
+ store.register_late_pass(|| box needless_bool::NeedlessBool);
+ store.register_late_pass(|| box needless_bool::BoolComparison);
+ store.register_late_pass(|| box needless_for_each::NeedlessForEach);
+ store.register_late_pass(|| box approx_const::ApproxConstant);
+ store.register_late_pass(|| box misc::MiscLints);
+ store.register_late_pass(|| box eta_reduction::EtaReduction);
+ store.register_late_pass(|| box identity_op::IdentityOp);
+ store.register_late_pass(|| box erasing_op::ErasingOp);
+ store.register_late_pass(|| box mut_mut::MutMut);
+ store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
+ store.register_late_pass(|| box len_zero::LenZero);
+ store.register_late_pass(|| box attrs::Attributes);
+ store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
+ store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
+ store.register_late_pass(|| box unicode::Unicode);
+ store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
+ store.register_late_pass(|| box strings::StringAdd);
+ store.register_late_pass(|| box implicit_return::ImplicitReturn);
+ store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
+ store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
+ store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+ store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+ store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+
+ let msrv = conf.msrv.as_ref().and_then(|s| {
+ parse_msrv(s, None, None).or_else(|| {
+ sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+ None
+ })
+ });
+
+ let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+ store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv));
+ store.register_late_pass(move || box matches::Matches::new(msrv));
+ store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
+ store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+ store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+ store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+ store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+ store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+ store.register_late_pass(move || box ranges::Ranges::new(msrv));
+ store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
+ store.register_late_pass(move || box use_self::UseSelf::new(msrv));
+ store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+ store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
+ store.register_late_pass(move || box casts::Casts::new(msrv));
+ store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
+
+ store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
+ store.register_late_pass(|| box map_clone::MapClone);
+ store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
+ store.register_late_pass(|| box shadow::Shadow);
+ store.register_late_pass(|| box unit_types::UnitTypes);
+ store.register_late_pass(|| box loops::Loops);
+ store.register_late_pass(|| box main_recursion::MainRecursion::default());
+ store.register_late_pass(|| box lifetimes::Lifetimes);
+ store.register_late_pass(|| box entry::HashMapPass);
+ store.register_late_pass(|| box minmax::MinMaxPass);
+ store.register_late_pass(|| box open_options::OpenOptions);
+ store.register_late_pass(|| box zero_div_zero::ZeroDiv);
+ store.register_late_pass(|| box mutex_atomic::Mutex);
+ store.register_late_pass(|| box needless_update::NeedlessUpdate);
+ store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
+ store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
+ store.register_late_pass(|| box no_effect::NoEffect);
+ store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
+ store.register_late_pass(|| box transmute::Transmute);
+ let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
+ store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
+ let too_large_for_stack = conf.too_large_for_stack;
+ store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+ store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
+ store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
+ store.register_late_pass(|| box strings::StringLitAsBytes);
+ store.register_late_pass(|| box derive::Derive);
+ store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
+ store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
+ store.register_late_pass(|| box empty_enum::EmptyEnum);
+ store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+ store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
+ store.register_late_pass(|| box regex::Regex::default());
+ store.register_late_pass(|| box copies::CopyAndPaste);
+ store.register_late_pass(|| box copy_iterator::CopyIterator);
+ store.register_late_pass(|| box format::UselessFormat);
+ store.register_late_pass(|| box swap::Swap);
+ store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
+ store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
+ let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
+ let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+ let too_many_lines_threshold = conf.too_many_lines_threshold;
+ store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
+ let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
+ store.register_late_pass(|| box neg_multiply::NegMultiply);
+ store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
+ store.register_late_pass(|| box mem_forget::MemForget);
+ store.register_late_pass(|| box arithmetic::Arithmetic::default());
+ store.register_late_pass(|| box assign_ops::AssignOps);
+ store.register_late_pass(|| box let_if_seq::LetIfSeq);
+ store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
+ store.register_late_pass(|| box missing_doc::MissingDoc::new());
+ store.register_late_pass(|| box missing_inline::MissingInline);
+ store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
+ store.register_late_pass(|| box if_let_some_result::OkIfLet);
+ store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
+ store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
+ let enum_variant_size_threshold = conf.enum_variant_size_threshold;
+ store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
+ store.register_late_pass(|| box explicit_write::ExplicitWrite);
+ store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
+ let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
+ conf.trivial_copy_size_limit,
+ conf.pass_by_value_size_limit,
+ conf.avoid_breaking_exported_api,
+ &sess.target,
+ );
+ store.register_late_pass(move || box pass_by_ref_or_value);
+ store.register_late_pass(|| box ref_option_ref::RefOptionRef);
+ store.register_late_pass(|| box try_err::TryErr);
+ store.register_late_pass(|| box bytecount::ByteCount);
+ store.register_late_pass(|| box infinite_iter::InfiniteIter);
+ store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
+ store.register_late_pass(|| box useless_conversion::UselessConversion::default());
+ store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
+ store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
+ store.register_late_pass(|| box double_comparison::DoubleComparisons);
+ store.register_late_pass(|| box question_mark::QuestionMark);
+ store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
+ store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
+ store.register_late_pass(|| box map_unit_fn::MapUnit);
+ store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
+ store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
+ store.register_late_pass(|| box unwrap::Unwrap);
+ store.register_late_pass(|| box duration_subsec::DurationSubsec);
+ store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
+ store.register_late_pass(|| box non_copy_const::NonCopyConst);
+ store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
+ store.register_late_pass(|| box redundant_clone::RedundantClone);
+ store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+ store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+ store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api));
+ store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
+ store.register_late_pass(|| box transmuting_null::TransmutingNull);
+ store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
+ store.register_late_pass(|| box integer_division::IntegerDivision);
+ store.register_late_pass(|| box inherent_to_string::InherentToString);
+ let max_trait_bounds = conf.max_trait_bounds;
+ store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
+ store.register_late_pass(|| box comparison_chain::ComparisonChain);
+ store.register_late_pass(|| box mut_key::MutableKeyType);
+ store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
+ store.register_early_pass(|| box reference::DerefAddrOf);
+ store.register_early_pass(|| box reference::RefInDeref);
+ store.register_early_pass(|| box double_parens::DoubleParens);
+ store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
+ store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
+ store.register_early_pass(|| box if_not_else::IfNotElse);
+ store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
+ store.register_early_pass(|| box int_plus_one::IntPlusOne);
+ store.register_early_pass(|| box formatting::Formatting);
+ store.register_early_pass(|| box misc_early::MiscEarlyLints);
+ store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+ store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
+ store.register_early_pass(|| box unused_unit::UnusedUnit);
+ store.register_late_pass(|| box returns::Return);
+ store.register_early_pass(|| box collapsible_if::CollapsibleIf);
+ store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
+ store.register_early_pass(|| box precedence::Precedence);
+ store.register_early_pass(|| box needless_continue::NeedlessContinue);
+ store.register_early_pass(|| box redundant_else::RedundantElse);
+ store.register_late_pass(|| box create_dir::CreateDir);
+ store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
+ let cargo_ignore_publish = conf.cargo_ignore_publish;
+ store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
+ store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
+ store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
+ let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
+ store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
+ let literal_representation_threshold = conf.literal_representation_threshold;
+ store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
+ let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+ store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api));
+ store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+ let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
+ store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive));
+ store.register_late_pass(|| box default::Default::default());
+ store.register_late_pass(|| box unused_self::UnusedSelf);
+ store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
+ store.register_late_pass(|| box exit::Exit);
+ store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
+ let array_size_threshold = conf.array_size_threshold;
+ store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
+ store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
+ store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
+ store.register_early_pass(|| box as_conversions::AsConversions);
+ store.register_late_pass(|| box let_underscore::LetUnderscore);
+ store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
+ store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
+ let max_fn_params_bools = conf.max_fn_params_bools;
+ let max_struct_bools = conf.max_struct_bools;
+ store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
+ store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
+ let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+ store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
+ store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
+ store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
+ store.register_late_pass(|| box unnamed_address::UnnamedAddress);
+ store.register_late_pass(|| box dereference::Dereferencing::default());
+ store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
+ store.register_late_pass(|| box future_not_send::FutureNotSend);
+ store.register_late_pass(|| box if_let_mutex::IfLetMutex);
+ store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
+ store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+ store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
+ store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+ store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+ let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
+ store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
+ single_char_binding_names_threshold,
+ });
+ store.register_late_pass(|| box macro_use::MacroUseImports::default());
+ store.register_late_pass(|| box map_identity::MapIdentity);
+ store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+ store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
+ store.register_late_pass(|| box repeat_once::RepeatOnce);
+ store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
+ store.register_late_pass(|| box self_assignment::SelfAssignment);
+ store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+ store.register_late_pass(|| box manual_ok_or::ManualOkOr);
+ store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+ store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
+ store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+ let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+ store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+ store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+ store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+ store.register_late_pass(|| box strings::StrToString);
+ store.register_late_pass(|| box strings::StringToString);
+ store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+ store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+ store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+ store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
+ store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
+ store.register_late_pass(|| box manual_map::ManualMap);
+ store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
+ store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+ store.register_late_pass(|| box unused_async::UnusedAsync);
- store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
- LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
- LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
- LintId::of(disallowed_method::DISALLOWED_METHOD),
- LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
- LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
- LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
- LintId::of(future_not_send::FUTURE_NOT_SEND),
- LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
- 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(needless_borrow::NEEDLESS_BORROW),
- LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
- LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
- LintId::of(regex::TRIVIAL_REGEX),
- LintId::of(strings::STRING_LIT_AS_BYTES),
- LintId::of(transmute::USELESS_TRANSMUTE),
- LintId::of(use_self::USE_SELF),
- ]);
}
#[rustfmt::skip]
output_visitor.visit_ty(ty);
}
for lt in named_generics {
- input_visitor.visit_generic_param(lt)
+ input_visitor.visit_generic_param(lt);
}
if input_visitor.abort() || output_visitor.abort() {
// `'b` in `'a: 'b` is useless unless used elsewhere in
// a non-lifetime bound
if let GenericParamKind::Type { .. } = param.kind {
- walk_generic_param(self, param)
+ walk_generic_param(self, param);
}
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit)
+ self.check_lit(cx, lit);
}
}
}
}
};
if should_warn {
- warning_type.display(num_lit.format(), cx, lit.span)
+ warning_type.display(num_lit.format(), cx, lit.span);
}
}
}
}
if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit)
+ self.check_lit(cx, lit);
}
}
}
let hex = format!("{:#X}", val);
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
- warning_type.display(num_lit.format(), cx, lit.span)
+ warning_type.display(num_lit.format(), cx, lit.span);
});
}
}
"to write this more concisely, try",
format!("&{}{}", muta, object),
applicability,
- )
+ );
}
/// Returns `true` if the type of expr is one that provides `IntoIterator` impls
if let ty::BorrowKind::MutBorrow = bk {
if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
}
}
}
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
}
}
}
use super::NEEDLESS_COLLECT;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
// Suggest replacing iter_call with iter_replacement, and removing stmt
let mut span = MultiSpan::from_span(collect_span);
span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
- span_lint_and_then(
+ span_lint_hir_and_then(
cx,
super::NEEDLESS_COLLECT,
+ init_expr.hir_id,
span,
NEEDLESS_COLLECT_MSG,
|diag| {
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
- )
+ );
}
if !matches!(pat.kind, PatKind::Wild) {
}
},
ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
- *state = IncrementVisitorVarState::DontWarn
+ *state = IncrementVisitorVarState::DontWarn;
},
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
- *state = IncrementVisitorVarState::DontWarn
+ *state = IncrementVisitorVarState::DontWarn;
},
_ => (),
}
}
},
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
- self.state = InitializeVisitorState::DontWarn
+ self.state = InitializeVisitorState::DontWarn;
},
_ => (),
}
return;
}
}
- walk_pat(self, pat)
+ walk_pat(self, pat);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
use super::WHILE_IMMUTABLE_CONDITION;
-use crate::consts::constant;
+use clippy_utils::consts::constant;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::usage::mutated_variables;
use if_chain::if_chain;
let mut suggestions = vec![];
for ((root, span), path) in used {
if path.len() == 1 {
- suggestions.push((span, format!("{}::{}", root, path[0])))
+ suggestions.push((span, format!("{}::{}", root, path[0])));
} else {
- suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+ suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
}
}
"remove the attribute and import the macro directly, try",
help,
Applicability::MaybeIncorrect,
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
kind_word,
snippet(cx, pattern.span, "..")))]
.into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
- )
+ );
});
}
}
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
"remove the `map` call",
String::new(),
Applicability::MachineApplicable,
- )
+ );
}
fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability,
- )
+ );
} else {
span_lint_and_sugg(
cx,
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability,
- )
+ );
}
}
-use crate::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, miri_to_const, Constant};
use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
};
"try this",
suggestions.join(" | "),
Applicability::MaybeIncorrect,
- )
+ );
},
};
}
cast,
),
applicability,
- )
+ );
}
}
}
"consider using the scrutinee and body instead",
sugg,
applicability,
- )
+ );
} else {
span_lint_and_sugg(
cx,
match match_source {
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
MatchSource::IfLetDesugar { contains_else_clause } => {
- find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
+ find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
},
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
_ => {},
{
self.res = true;
} else {
- self.visit_expr(self_arg)
+ self.visit_expr(self_arg);
}
}
args.iter().for_each(|arg| self.visit_expr(arg));
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
declare_clippy_lint! {
/// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
}
}
- let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+ let derefs = "*".repeat(derefs_needed);
diag.span_suggestion(
param.span,
"try dereferencing",
.into_iter()
.map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
),
- )
+ );
});
true
}
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
-use std::iter;
use super::CLONE_DOUBLE_REF;
use super::CLONE_ON_COPY;
ty = inner;
n += 1;
}
- let refs: String = iter::repeat('&').take(n + 1).collect();
- let derefs: String = iter::repeat('*').take(n).collect();
+ let refs = "&".repeat(n + 1);
+ let derefs = "*".repeat(n);
let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
diag.span_suggestion(
expr.span,
"try",
"copied".into(),
Applicability::MachineApplicable,
- )
+ );
}
"try",
"filter_map".into(),
Applicability::MachineApplicable,
- )
+ );
}
}
fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+ fn strip_angle_brackets(s: &str) -> Option<&str> {
+ s.strip_prefix('<')?.strip_suffix('>')
+ }
+
let call_site = expr.span.source_callsite();
if_chain! {
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
if let Some((_, elements)) = snippet_split.split_last();
then {
- // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
- if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) {
- // remove the type specifier from the path elements
- let without_ts = elements.iter().filter_map(|e| {
- if e == type_specifier { None } else { Some((*e).to_string()) }
- }).collect::<Vec<_>>();
- // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
- format!("{}{}", without_ts.join("::"), type_specifier)
- } else {
- // type is not explicitly specified so wildcards are needed
- // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
- let ty_str = ty.to_string();
- let start = ty_str.find('<').unwrap_or(0);
- let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
- let nb_wildcard = ty_str[start..end].split(',').count();
- let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
- format!("{}<{}>", elements.join("::"), wildcards)
+ if_chain! {
+ if let [type_specifier, _] = snippet_split.as_slice();
+ if let Some(type_specifier) = strip_angle_brackets(type_specifier);
+ if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
+ then {
+ type_specifier.to_string()
+ } else {
+ // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+ if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+ // remove the type specifier from the path elements
+ let without_ts = elements.iter().filter_map(|e| {
+ if e == type_specifier { None } else { Some((*e).to_string()) }
+ }).collect::<Vec<_>>();
+ // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+ format!("{}{}", without_ts.join("::"), type_specifier)
+ } else {
+ // type is not explicitly specified so wildcards are needed
+ // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+ let ty_str = ty.to_string();
+ let start = ty_str.find('<').unwrap_or(0);
+ let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+ let nb_wildcard = ty_str[start..end].split(',').count();
+ let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+ format!("{}<{}>", elements.join("::"), wildcards)
+ }
+ }
}
} else {
ty.to_string()
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_trait_method;
use rustc_hir as hir;
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{is_expr_path_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TyS};
+use rustc_span::symbol::sym;
+use std::borrow::Cow;
+
+use super::MANUAL_STR_REPEAT;
+
+enum RepeatKind {
+ String,
+ Char(char),
+}
+
+fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
+ if let ty::Adt(_, subs) = ty.kind() {
+ subs.types().next()
+ } else {
+ None
+ }
+}
+
+fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
+ if let ExprKind::Lit(lit) = &e.kind {
+ match lit.node {
+ LitKind::Str(..) => Some(RepeatKind::String),
+ LitKind::Char(c) => Some(RepeatKind::Char(c)),
+ _ => None,
+ }
+ } else {
+ let ty = cx.typeck_results().expr_ty(e);
+ if is_type_diagnostic_item(cx, ty, sym::string_type)
+ || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
+ || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+ {
+ Some(RepeatKind::String)
+ } else {
+ let ty = ty.peel_refs();
+ (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String)
+ }
+ }
+}
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ collect_expr: &Expr<'_>,
+ take_expr: &Expr<'_>,
+ take_self_arg: &Expr<'_>,
+ take_arg: &Expr<'_>,
+) {
+ if_chain! {
+ if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
+ if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type);
+ if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+ if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
+ if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
+ if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
+ if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
+ let ctxt = collect_expr.span.ctxt();
+ if ctxt == take_expr.span.ctxt();
+ if ctxt == take_self_arg.span.ctxt();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+
+ let val_str = match repeat_kind {
+ RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+ RepeatKind::Char('\'') => r#""'""#.into(),
+ RepeatKind::Char('"') => r#""\"""#.into(),
+ RepeatKind::Char(_) =>
+ match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+ Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+ s @ Cow::Borrowed(_) => s,
+ },
+ RepeatKind::String =>
+ Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_STR_REPEAT,
+ collect_expr.span,
+ "manual implementation of `str::repeat` using iterators",
+ "try this",
+ format!("{}.repeat({})", val_str, count_snip),
+ app
+ )
+ }
+ }
+}
mod iter_skip_next;
mod iterator_step_by_zero;
mod manual_saturating_arithmetic;
+mod manual_str_repeat;
mod map_collect_result_unit;
mod map_flatten;
mod map_unwrap_or;
mod skip_while_next;
mod string_extend_chars;
mod suspicious_map;
+mod suspicious_splitn;
mod uninit_assumed_init;
mod unnecessary_filter_map;
mod unnecessary_fold;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
"defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
}
-declare_clippy_lint! {
- /// **What it does:** This is the same as
- /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
- ///
- /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
- ///
- /// **Known problems:** Actually *renaming* the function may break clients if
- /// the function is part of the public interface. In that case, be mindful of
- /// the stability guarantees you've given your users.
- ///
- /// **Example:**
- /// ```rust
- /// # struct X;
- /// impl<'a> X {
- /// pub fn as_str(self) -> &'a str {
- /// "foo"
- /// }
- /// }
- /// ```
- pub WRONG_PUB_SELF_CONVENTION,
- restriction,
- "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
-}
-
declare_clippy_lint! {
/// **What it does:** Checks for usage of `ok().expect(..)`.
///
"replace `.iter().count()` with `.len()`"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for calls to [`splitn`]
+ /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+ /// related functions with either zero or one splits.
+ ///
+ /// **Why is this bad?** These calls don't actually split the value and are
+ /// likely to be intended as a different number.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// // Bad
+ /// let s = "";
+ /// for x in s.splitn(1, ":") {
+ /// // use x
+ /// }
+ ///
+ /// // Good
+ /// let s = "";
+ /// for x in s.splitn(2, ":") {
+ /// // use x
+ /// }
+ /// ```
+ pub SUSPICIOUS_SPLITN,
+ correctness,
+ "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
+}
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for manual implementations of `str::repeat`
+ ///
+ /// **Why is this bad?** These are both harder to read, as well as less performant.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// // Bad
+ /// let x: String = std::iter::repeat('x').take(10).collect();
+ ///
+ /// // Good
+ /// let x: String = "x".repeat(10);
+ /// ```
+ pub MANUAL_STR_REPEAT,
+ perf,
+ "manual implementation of `str::repeat`"
+}
+
pub struct Methods {
+ avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
}
impl Methods {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
- Self { msrv }
+ pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ msrv,
+ }
}
}
EXPECT_USED,
SHOULD_IMPLEMENT_TRAIT,
WRONG_SELF_CONVENTION,
- WRONG_PUB_SELF_CONVENTION,
OK_EXPECT,
MAP_UNWRAP_OR,
RESULT_MAP_OR_INTO_OPTION,
MAP_COLLECT_RESULT_UNIT,
FROM_ITER_INSTEAD_OF_COLLECT,
INSPECT_FOR_EACH,
- IMPLICIT_CLONE
+ IMPLICIT_CLONE,
+ SUSPICIOUS_SPLITN,
+ MANUAL_STR_REPEAT
]);
/// Extracts a method call name, args, and `Span` of the method name.
}
}
- if sig.decl.implicit_self.has_implicit_self() {
+ if sig.decl.implicit_self.has_implicit_self()
+ && !(self.avoid_breaking_exported_api
+ && cx.access_levels.is_exported(impl_item.hir_id()))
+ {
wrong_self_convention::check(
cx,
&name,
- item.vis.node.is_pub(),
self_ty,
first_arg_ty,
first_arg.pat.span,
wrong_self_convention::check(
cx,
&item.ident.name.as_str(),
- false,
self_ty,
first_arg_ty,
first_arg_span,
if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
- zst_offset::check(cx, expr, recv)
+ zst_offset::check(cx, expr, recv);
},
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
+ Some(("take", [take_self_arg, take_arg], _)) => {
+ if meets_msrv(msrv, &msrvs::STR_REPEAT) {
+ manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+ }
+ },
_ => {},
},
("count", []) => match method_call!(recv) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
("filter", [f_arg]) => {
- filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+ filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
_ => {},
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
+ ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
+ suspicious_splitn::check(cx, name, expr, recv, count_arg);
+ },
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv, span);
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
- option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+ option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
_ => {},
},
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
- search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+ search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
--- /dev/null
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::SUSPICIOUS_SPLITN;
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ method_name: &str,
+ expr: &Expr<'_>,
+ self_arg: &Expr<'_>,
+ count_arg: &Expr<'_>,
+) {
+ if_chain! {
+ if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
+ if count <= 1;
+ if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
+ let lang_items = cx.tcx.lang_items();
+ if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
+ then {
+ // Ignore empty slice and string literals when used with a literal count.
+ if (matches!(self_arg.kind, ExprKind::Array([]))
+ || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+ ) && matches!(count_arg.kind, ExprKind::Lit(_))
+ {
+ return;
+ }
+
+ let (msg, note_msg) = if count == 0 {
+ (format!("`{}` called with `0` splits", method_name),
+ "the resulting iterator will always return `None`")
+ } else {
+ (format!("`{}` called with `1` split", method_name),
+ if lang_items.slice_impl() == Some(impl_id) {
+ "the resulting iterator will always return the entire slice followed by `None`"
+ } else {
+ "the resulting iterator will always return the entire string followed by `None`"
+ })
+ };
+
+ span_lint_and_note(
+ cx,
+ SUSPICIOUS_SPLITN,
+ expr.span,
+ &msg,
+ None,
+ note_msg,
+ );
+ }
+ }
+}
ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
ast::LitKind::Int(1, _) => {
- check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
+ check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
},
_ => (),
}
use rustc_span::source_map::Span;
use std::fmt;
-use super::WRONG_PUB_SELF_CONVENTION;
use super::WRONG_SELF_CONVENTION;
#[rustfmt::skip]
// Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
// Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
- (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
+ (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
- (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
+ (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
];
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
item_name: &str,
- is_pub: bool,
self_ty: &'tcx TyS<'tcx>,
first_arg_ty: &'tcx TyS<'tcx>,
first_arg_span: Span,
implements_trait: bool,
is_trait_item: bool,
) {
- let lint = if is_pub {
- WRONG_PUB_SELF_CONVENTION
- } else {
- WRONG_SELF_CONVENTION
- };
if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
convs
.iter()
span_lint_and_help(
cx,
- lint,
+ WRONG_SELF_CONVENTION,
first_arg_span,
&format!(
"{} usually take {}",
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_def_path, match_trait_method, paths};
use if_chain::if_chain;
use rustc_span::source_map::{ExpnKind, Span};
use rustc_span::symbol::sym;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::sugg::Sugg;
use clippy_utils::{
expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
if let Some(sugg) = Sugg::hir_opt(cx, a);
then {
- span_lint_and_then(cx,
+ span_lint_hir_and_then(
+ cx,
SHORT_CIRCUIT_STATEMENT,
+ expr.hir_id,
stmt.span,
"boolean short circuit operator in statement may be clearer using an explicit test",
|diag| {
if in_external_macro(cx.sess(), expr.span) {
return;
}
- double_neg::check(cx, expr)
+ double_neg::check(cx, expr);
}
}
};
unseparated_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)
+ mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
- /* nothing to do */
+ // nothing to do
} else if value != 0 && lit_snip.starts_with('0') {
- zero_prefixed_literal::check(cx, lit, &lit_snip)
+ zero_prefixed_literal::check(cx, lit, &lit_snip);
}
} 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")
+ unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
-use rustc_ast::ast::{self, MetaItem, MetaItemKind};
+use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
- fn has_include(meta: Option<MetaItem>) -> bool {
- if_chain! {
- if let Some(meta) = meta;
- if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.get(0);
- if let Some(name) = meta.ident();
- then {
- name.name == sym::include
- } else {
- false
- }
- }
- }
-
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
return;
}
- let has_doc = attrs.iter().any(|a| {
- a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
- });
+ let has_doc = attrs
+ .iter()
+ .any(|a| a.doc_str().is_some());
if !has_doc {
span_lint(
cx,
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sext;
use if_chain::if_chain;
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
- check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
+ check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method");
},
_ => (),
}
_ if !self.found => self.expr_span = Some(expr.span),
_ => return,
}
- walk_expr(self, expr)
+ walk_expr(self, expr);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
match &p.ty.kind {
TyKind::Path(None, path) => {
if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
then {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
}
},
}
if is_else_clause(cx.tcx, e) {
- snip = snip.blockify()
+ snip = snip.blockify();
}
span_lint_and_sugg(
|h: Sugg<'_>| !h,
"equality checks against false can be replaced by a negation",
));
- check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+ check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
},
BinOpKind::Ne => {
let true_case = Some((
"inequality checks against true can be replaced by a negation",
));
let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
- check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+ check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
},
BinOpKind::Lt => check_comparison(
cx,
snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
),
applicability,
- )
+ );
}
}
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => left_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
(Other, Bool(true)) => right_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
(Bool(false), Other) => left_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
(Other, Bool(false)) => right_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
(Other, Other) => no_literal.map_or((), |(h, m)| {
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
"try simplifying it as shown",
h(left_side, right_side).to_string(),
applicability,
- )
+ );
}),
_ => (),
}
//! This lint is **warn** by default
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_automatically_derived;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
+use clippy_utils::{get_parent_expr, in_macro, path_to_local};
use if_chain::if_chain;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
declare_clippy_lint! {
/// **What it does:** Checks for address of operations (`&`) that are going to
/// let x: &i32 = &5;
/// ```
pub NEEDLESS_BORROW,
- nursery,
+ style,
"taking a reference that is going to be automatically dereferenced"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for `ref` bindings which create a reference to a reference.
+ ///
+ /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust
+ /// // Bad
+ /// let x = Some("");
+ /// if let Some(ref x) = x {
+ /// // use `x` here
+ /// }
+ ///
+ /// // Good
+ /// let x = Some("");
+ /// if let Some(x) = x {
+ /// // use `&x` here
+ /// }
+ /// ```
+ pub REF_BINDING_TO_REFERENCE,
+ pedantic,
+ "`ref` binding to a reference"
+}
+
+impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
#[derive(Default)]
pub struct NeedlessBorrow {
- derived_item: Option<LocalDefId>,
+ /// The body the first local was found in. Used to emit lints when the traversal of the body has
+ /// been finished. Note we can't lint at the end of every body as they can be nested within each
+ /// other.
+ current_body: Option<BodyId>,
+ /// The list of locals currently being checked by the lint.
+ /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+ /// This is needed for or patterns where one of the branches can be linted, but another can not
+ /// be.
+ ///
+ /// e.g. `m!(x) | Foo::Bar(ref x)`
+ ref_locals: FxIndexMap<HirId, Option<RefPat>>,
}
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
+struct RefPat {
+ /// Whether every usage of the binding is dereferenced.
+ always_deref: bool,
+ /// The spans of all the ref bindings for this local.
+ spans: Vec<Span>,
+ /// The applicability of this suggestion.
+ app: Applicability,
+ /// All the replacements which need to be made.
+ replacements: Vec<(Span, String)>,
+}
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if e.span.from_expansion() || self.derived_item.is_some() {
+ if let Some(local) = path_to_local(e) {
+ self.check_local_usage(cx, e, local);
+ }
+
+ if e.span.from_expansion() {
return;
}
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
}
}
}
+
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if pat.span.from_expansion() || self.derived_item.is_some() {
- return;
+ if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+ if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+ // This binding id has been seen before. Add this pattern to the list of changes.
+ if let Some(prev_pat) = opt_prev_pat {
+ if in_macro(pat.span) {
+ // Doesn't match the context of the previous pattern. Can't lint here.
+ *opt_prev_pat = None;
+ } else {
+ prev_pat.spans.push(pat.span);
+ prev_pat.replacements.push((
+ pat.span,
+ snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+ .0
+ .into(),
+ ));
+ }
+ }
+ return;
+ }
+
+ if_chain! {
+ if !in_macro(pat.span);
+ if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+ // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+ if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+ self.current_body = self.current_body.or(cx.enclosing_body);
+ self.ref_locals.insert(
+ id,
+ Some(RefPat {
+ always_deref: true,
+ spans: vec![pat.span],
+ app,
+ replacements: vec![(pat.span, snip.into())],
+ }),
+ );
+ }
+ }
}
- if_chain! {
- if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
- if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
- if mutbl == Mutability::Not;
- if let ty::Ref(_, _, mutbl) = *tam.kind();
- // only lint immutable refs, because borrowed `&mut T` cannot be moved out
- if mutbl == Mutability::Not;
- then {
+ }
+
+ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+ if Some(body.id()) == self.current_body {
+ for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+ let replacements = pat.replacements;
+ let app = pat.app;
span_lint_and_then(
cx,
- NEEDLESS_BORROW,
- pat.span,
+ if pat.always_deref {
+ NEEDLESS_BORROW
+ } else {
+ REF_BINDING_TO_REFERENCE
+ },
+ pat.spans,
"this pattern creates a reference to a reference",
|diag| {
- if let Some(snippet) = snippet_opt(cx, name.span) {
- diag.span_suggestion(
- pat.span,
- "change this to",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- }
- )
+ diag.multipart_suggestion("try this", replacements, app);
+ },
+ );
}
+ self.current_body = None;
}
}
-
- fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- let attrs = cx.tcx.hir().attrs(item.hir_id());
- if is_automatically_derived(attrs) {
- debug_assert!(self.derived_item.is_none());
- self.derived_item = Some(item.def_id);
- }
- }
-
- fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if let Some(id) = self.derived_item {
- if item.def_id == id {
- self.derived_item = None;
+}
+impl NeedlessBorrow {
+ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+ if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+ if let Some(pat) = outer_pat {
+ // Check for auto-deref
+ if !matches!(
+ cx.typeck_results().expr_adjustments(e),
+ [
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ ..
+ ]
+ ) {
+ match get_parent_expr(cx, e) {
+ // Field accesses are the same no matter the number of references.
+ Some(Expr {
+ kind: ExprKind::Field(..),
+ ..
+ }) => (),
+ Some(&Expr {
+ span,
+ kind: ExprKind::Unary(UnOp::Deref, _),
+ ..
+ }) if !in_macro(span) => {
+ // Remove explicit deref.
+ let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((span, snip.into()));
+ },
+ Some(parent) if !in_macro(parent.span) => {
+ // Double reference might be needed at this point.
+ if parent.precedence().order() == PREC_POSTFIX {
+ // Parentheses would be needed here, don't lint.
+ *outer_pat = None;
+ } else {
+ pat.always_deref = false;
+ let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ }
+ },
+ _ if !in_macro(e.span) => {
+ // Double reference might be needed at this point.
+ pat.always_deref = false;
+ let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ },
+ // Edge case for macros. The span of the identifier will usually match the context of the
+ // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+ // macros
+ _ => *outer_pat = None,
+ }
+ }
}
}
}
match expr.kind {
ExprKind::Ret(..) => {
if self.loop_depth > 0 && !self.ret_in_loop {
- self.ret_in_loop = true
+ self.ret_in_loop = true;
}
- self.spans.push(expr.span)
+ self.spans.push(expr.span);
},
ExprKind::Loop(..) => {
types produces code that is hard to read and refactor, please \
consider using the `partial_cmp` method instead, to make it \
clear that the two values could be incomparable"
- )
+ );
}
}
}
+use clippy_utils::consts::{self, Constant};
use clippy_utils::diagnostics::span_lint;
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{self, Constant};
-
declare_clippy_lint! {
/// **What it does:** Checks for multiplication by -1 as a form of negation.
///
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
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(cx, NO_EFFECT, stmt.span, "statement with no effect");
+ span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
} else if let Some(reduced) = reduce_expression(cx, expr) {
let mut snippet = String::new();
for e in reduced {
return;
}
}
- span_lint_and_sugg(
+ span_lint_hir_and_then(
cx,
UNNECESSARY_OPERATION,
+ expr.hir_id,
stmt.span,
"statement can be reduced",
- "replace it with",
- snippet,
- Applicability::MachineApplicable,
+ |diag| {
+ diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable);
+ },
);
}
}
&["args", "arms"],
&["qpath", "path"],
&["lit", "lint"],
+ &["wparam", "lparam"],
];
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
"the method `create` is called more than once",
);
} else {
- create = true
+ create = true;
}
create_arg = create_arg || (arg == Argument::True);
},
"the method `append` is called more than once",
);
} else {
- append = true
+ append = true;
}
append_arg = append_arg || (arg == Argument::True);
},
"the method `truncate` is called more than once",
);
} else {
- truncate = true
+ truncate = true;
}
truncate_arg = truncate_arg || (arg == Argument::True);
},
"the method `read` is called more than once",
);
} else {
- read = true
+ read = true;
}
read_arg = read_arg || (arg == Argument::True);
},
"the method `write` is called more than once",
);
} else {
- write = true
+ write = true;
}
write_arg = write_arg || (arg == Argument::True);
},
pub struct PassByRefOrValue {
ref_min_size: u64,
value_max_size: u64,
+ avoid_breaking_exported_api: bool,
}
impl<'tcx> PassByRefOrValue {
- pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
+ pub fn new(
+ ref_min_size: Option<u64>,
+ value_max_size: u64,
+ avoid_breaking_exported_api: bool,
+ target: &Target,
+ ) -> Self {
let ref_min_size = ref_min_size.unwrap_or_else(|| {
let bit_width = u64::from(target.pointer_width);
// Cap the calculated bit width at 32-bits to reduce
Self {
ref_min_size,
value_max_size,
+ avoid_breaking_exported_api,
}
}
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
+ if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+ return;
+ }
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
let fn_sig = cx.tcx.fn_sig(fn_def_id);
}
if_chain! {
- if !cx.access_levels.is_exported(hir_id);
if is_copy(cx, ty);
if !is_self_ty(input);
if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
];
if_chain! {
- if let ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let ExprKind::Call(fun, args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
"replace it with",
replacement_str,
applicability,
- )
+ );
}
}
}
"replace it with",
replacement,
applicability,
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
self.found_return = true;
}
- ast_visit::walk_expr(self, ex)
+ ast_visit::walk_expr(self, ex);
}
}
Applicability::MachineApplicable,
);
},
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet;
} else {
RetReplacement::Empty
};
- check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+ check_final_expr(cx, &body.value, Some(body.value.span), replacement);
},
FnKind::ItemFn(..) | FnKind::Method(..) => {
if let ExprKind::Block(block, _) = body.value.kind {
if let Some(snippet) = snippet_opt(cx, inner_span) {
diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
}
- })
+ });
},
None => match replacement {
RetReplacement::Empty => {
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
- /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
- /// but is not followed by a semicolon.
+ /// **What it does:** Looks for blocks of expressions and fires if the last expression returns
+ /// `()` but is not followed by a semicolon.
///
- /// **Why is this bad?** The semicolon might be optional but when
- /// extending the block with new code, it doesn't require a change in previous last line.
+ /// **Why is this bad?** The semicolon might be optional but when extending the block with new
+ /// code, it doesn't require a change in previous last line.
///
/// **Known problems:** None.
///
/// }
/// ```
pub SEMICOLON_IF_NOTHING_RETURNED,
- restriction,
+ pedantic,
"add a semicolon if nothing is returned"
}
let mut bindings = Vec::with_capacity(decl.inputs.len());
for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(.., ident, _) = arg.pat.kind {
- bindings.push((ident.name, ident.span))
+ bindings.push((ident.name, ident.span));
}
}
check_expr(cx, &body.value, &mut bindings);
..
} = *local;
if let Some(t) = *ty {
- check_ty(cx, t, bindings)
+ check_ty(cx, t, bindings);
}
if let Some(o) = *init {
check_expr(cx, o, bindings);
}
match expr.kind {
ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
- check_expr(cx, e, bindings)
+ check_expr(cx, e, bindings);
},
ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
// ExprKind::Call
// ExprKind::MethodCall
ExprKind::Array(v) | ExprKind::Tup(v) => {
for e in v {
- check_expr(cx, e, bindings)
+ check_expr(cx, e, bindings);
}
},
ExprKind::If(cond, then, ref otherwise) => {
TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
TyKind::Tup(tup) => {
for t in tup {
- check_ty(cx, t, bindings)
+ check_ty(cx, t, bindings);
}
},
TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
for item in items {
track_uses(
cx,
- &item,
+ item,
&mut imports_reused_with_self,
&mut single_use_usages,
&mut macros,
match &item.kind {
ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
- check_mod(cx, &items);
+ check_mod(cx, items);
},
ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
macros.push(item.ident.name);
) {
match initialization {
InitializationType::Extend(e) | InitializationType::Resize(e) => {
- Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization")
+ Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
},
};
}
fn visit_block(&mut self, block: &'tcx Block<'_>) {
if self.initialization_found {
if let Some(s) = block.stmts.get(0) {
- self.visit_stmt(s)
+ self.visit_stmt(s);
}
self.initialization_found = false;
/// }
/// ```
pub SUSPICIOUS_OPERATION_GROUPINGS,
- style,
+ nursery,
"groupings of binary operations that look suspiciously like typos"
}
"did you mean",
sugg,
applicability,
- )
+ );
}
fn ident_swap_sugg(
impl AddAssign for IdentLocation {
fn add_assign(&mut self, other: Self) {
- *self = *self + other
+ *self = *self + other;
}
}
impl AddAssign for IdentDifference {
fn add_assign(&mut self, other: Self) {
- *self = *self + other
+ *self = *self + other;
}
}
use clippy_utils::{in_macro, SpanlessHash};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Applicability;
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
use rustc_lint::{LateContext, LateLintPass};
hasher.hash_ty(ty);
hasher.finish()
};
- let mut map = FxHashMap::default();
+ let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
let mut applicability = Applicability::MaybeIncorrect;
for bound in gen.where_clause.predicates {
if_chain! {
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{is_expr_path_def_path, paths};
use if_chain::if_chain;
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
match item.kind {
TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
- self.check_ty(cx, ty, CheckTyContext::default())
+ self.check_ty(cx, ty, CheckTyContext::default());
},
TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
TraitItemKind::Type(..) => (),
},
TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
context.is_nested_call = true;
- self.check_ty(cx, ty, context)
+ self.check_ty(cx, ty, context);
},
TyKind::Tup(tys) => {
context.is_nested_call = true;
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Lit(ref lit) = expr.kind {
if let LitKind::Str(_, _) = lit.node {
- check_str(cx, lit.span, expr.hir_id)
+ check_str(cx, lit.span, expr.hir_id);
}
}
}
for c in s {
if c as u32 > 0x7F {
for d in c.escape_unicode() {
- result.push(d)
+ result.push(d);
}
} else {
result.push(c);
use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym;
use rustc_span::Span;
"functions that only return `Ok` or `Some`"
}
-declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+pub struct UnnecessaryWraps {
+ avoid_breaking_exported_api: bool,
+}
+
+impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl UnnecessaryWraps {
+ pub fn new(avoid_breaking_exported_api: bool) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ }
+ }
+}
impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
fn check_fn(
) {
// Abort if public function/method or closure.
match fn_kind {
- FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
- if visibility.node.is_pub() {
+ FnKind::ItemFn(..) | FnKind::Method(..) => {
+ if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
return;
}
},
FnKind::Closure => return,
- FnKind::Method(..) => (),
}
// Abort if the method is implementing a trait or of it a trait method.
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
let mut call = call;
- while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
+ while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
call = &args[0];
} else {
use clippy_utils::diagnostics::span_lint_and_sugg;
use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::{Item, ItemKind};
+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::Ident;
#[derive(Default)]
pub struct UpperCaseAcronyms {
+ avoid_breaking_exported_api: bool,
upper_case_acronyms_aggressive: bool,
}
impl UpperCaseAcronyms {
- pub fn new(aggressive: bool) -> Self {
+ pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
Self {
+ avoid_breaking_exported_api,
upper_case_acronyms_aggressive: aggressive,
}
}
ident
}
-fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
let span = ident.span;
let ident = &ident.as_str();
let corrected = correct_ident(ident);
"consider making the acronym lowercase, except the initial letter",
corrected,
Applicability::MaybeIncorrect,
- )
+ );
}
}
-impl EarlyLintPass for UpperCaseAcronyms {
- fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+impl LateLintPass<'_> for UpperCaseAcronyms {
+ fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
// do not lint public items or in macros
- if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
- if matches!(
- it.kind,
- ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
- ) {
+ if in_external_macro(cx.sess(), it.span)
+ || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+ {
+ return;
+ }
+ match it.kind {
+ ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
- } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+ },
+ ItemKind::Enum(ref enumdef, _) => {
// check enum variants seperately because again we only want to lint on private enums and
// the fn check_variant does not know about the vis of the enum of its variants
enumdef
.variants
.iter()
.for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
- }
+ },
+ _ => {},
}
}
}
fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
self.types_to_skip.push(hir_ty.hir_id);
- walk_ty(self, hir_ty)
+ walk_ty(self, hir_ty);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
}
- walk_ty(self, hir_ty)
+ walk_ty(self, hir_ty);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
LitKind::Str(ref text, _) => {
let str_pat = self.next("s");
println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
- println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str())
+ println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str());
},
}
},
// N.B., this macro is parsed by util/lintlib.py
define_Conf! {
- /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
+ /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
+ (avoid_breaking_exported_api: bool = true),
+ /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
(msrv: Option<String> = None),
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
(blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
.map_or_else(|| PathBuf::from("."), PathBuf::from);
loop {
for config_file_name in &CONFIG_FILE_NAMES {
- let config_file = current.join(config_file_name);
- match fs::metadata(&config_file) {
- // Only return if it's a file to handle the unlikely situation of a directory named
- // `clippy.toml`.
- Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
- // Return the error if it's something other than `NotFound`; otherwise we didn't
- // find the project file yet, and continue searching.
- Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
- _ => {},
+ if let Ok(config_file) = current.join(config_file_name).canonicalize() {
+ match fs::metadata(&config_file) {
+ Err(e) if e.kind() == io::ErrorKind::NotFound => {},
+ Err(e) => return Err(e),
+ Ok(md) if md.is_dir() => {},
+ Ok(_) => return Ok(Some(config_file)),
+ }
}
}
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
IF_CHAIN_STYLE,
if_chain_local_span(cx, local, if_chain_span),
"`let` expression should be inside `then { .. }`",
- )
+ );
}
}
if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
&& is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
{
- span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+ span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
}
}
}
/// }
/// ```
fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
- if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+ if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
// Normal lint
if_chain! {
// item validation
.hir()
.attrs(item.hir_id())
.iter()
- .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string()))
+ .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
.reduce(|mut acc, sym| {
acc.push_str(&sym);
acc.push('\n');
let mut multi_part = false;
for arg in args {
- let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg));
+ let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
if match_type(cx, arg_ty, &paths::LINT) {
// If we found the lint arg, extract the lint name
if let ExprKind::Path(qpath) = &expr.kind;
if let QPath::Resolved(_, path) = qpath;
- let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+ let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
if match_type(self.cx, expr_ty, &paths::LINT);
then {
if let hir::def::Res::Def(DefKind::Static, _) = path.res {
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
- let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+ let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
if_chain! {
if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
.any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
if found_function {
// These functions are all multi part suggestions
- self.add_single_span_suggestion()
+ self.add_single_span_suggestion();
}
},
ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
-use crate::consts::{constant, Constant};
use crate::rustc_target::abi::LayoutOf;
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
"use of `File::read_to_string`",
None,
"consider using `fs::read_to_string` instead",
- )
+ );
}
}
}
Applicability::MachineApplicable,
);
},
- )
+ );
}
}
} else if mac.path == sym!(writeln) {
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
for attr in get_attr(sess, attrs, name) {
if let Some(ref value) = attr.value_str() {
if let Ok(value) = FromStr::from_str(&value.as_str()) {
- f(value)
+ f(value);
} else {
sess.span_err(attr.span, "not a number");
}
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
match e.kind {
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
- ExprKind::Block(ref block, _) => self.block(block),
+ ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
- ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
- ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
- ExprKind::Repeat(ref value, _) => {
+ ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
+ ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
+ ExprKind::Repeat(value, _) => {
let n = match self.typeck_results.expr_ty(e).kind() {
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
_ => span_bug!(e.span, "typeck error"),
};
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
},
- ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
+ ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
}),
- ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
- ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
- ExprKind::Call(ref callee, ref args) => {
+ ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
+ ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+ ExprKind::Call(callee, args) => {
// We only handle a few const functions for now.
if_chain! {
if args.is_empty();
}
}
},
- ExprKind::Index(ref arr, ref index) => self.index(arr, index),
- ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
+ ExprKind::Index(arr, index) => self.index(arr, index),
+ ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
// TODO: add other expressions.
_ => None,
}
)
.ok()
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
- let result = miri_to_const(&result);
+ let result = miri_to_const(result);
if result.is_some() {
self.needed_resolution = true;
}
cx: &LateContext<'_>,
lint: &'static Lint,
hir_id: HirId,
- sp: Span,
+ sp: impl Into<MultiSpan>,
msg: &str,
f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
where
I: IntoIterator<Item = (Span, String)>,
{
- multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
+ multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
}
/// Create a suggestion made from several `span → replacement`.
}
match expr.kind {
- hir::ExprKind::Call(ref path, ref args)
+ hir::ExprKind::Call(path, args)
if matches!(
path.kind,
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
limits: ast::RangeLimits::Closed,
})
},
- hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+ hir::ExprKind::Struct(path, fields, None) => match path {
hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
start: None,
end: None,
// }
// ```
if_chain! {
- if let Some(ref expr) = local.init;
+ if let Some(expr) = local.init;
if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
then {
return true;
expr: &'tcx hir::Expr<'tcx>,
) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> {
if_chain! {
- if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
- if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
+ if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
+ if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
- if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+ if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind;
if block.expr.is_none();
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
- if let hir::StmtKind::Local(ref local) = let_stmt.kind;
- if let hir::StmtKind::Expr(ref expr) = body.kind;
+ if let hir::StmtKind::Local(local) = let_stmt.kind;
+ if let hir::StmtKind::Expr(expr) = body.kind;
then {
return Some((&*local.pat, &iterargs[0], expr, arms[0].span));
}
/// from `vec!`.
pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
if_chain! {
- if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let hir::ExprKind::Call(fun, args) = expr.kind;
if let hir::ExprKind::Path(ref qpath) = fun.kind;
if is_expn_of(fun.span, "vec").is_some();
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
if_chain! {
- if let hir::ExprKind::Box(ref boxed) = args[0].kind;
- if let hir::ExprKind::Array(ref args) = boxed.kind;
+ if let hir::ExprKind::Box(boxed) = args[0].kind;
+ if let hir::ExprKind::Array(args) = boxed.kind;
then {
return Some(VecArgs::Vec(&*args));
}
/// compared
fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
if_chain! {
- if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
+ if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
None
}
- if let ExprKind::Block(ref block, _) = e.kind {
+ if let ExprKind::Block(block, _) = e.kind {
if block.stmts.len() == 1 {
- if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind {
+ if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
// macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
if_chain! {
- if let ExprKind::If(ref clause, _, _) = matchexpr.kind;
+ if let ExprKind::If(clause, _, _) = matchexpr.kind;
if let ExprKind::Unary(UnOp::Not, condition) = clause.kind;
then {
return Some(vec![condition]);
// debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
if_chain! {
- if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
- if let Some(ref matchblock_expr) = matchblock.expr;
+ if let ExprKind::Block(matchblock,_) = matchexpr.kind;
+ if let Some(matchblock_expr) = matchblock.expr;
then {
return ast_matchblock(matchblock_expr);
}
}
} else if let Some(matchblock_expr) = block.expr {
// macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
- return ast_matchblock(&matchblock_expr);
+ return ast_matchblock(matchblock_expr);
}
}
None
use crate::differing_macro_contexts;
use crate::source::snippet_opt;
use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
use rustc_hir::HirIdMap;
use rustc_hir::{
- BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
- GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
- PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+ BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+ InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+ StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
use rustc_middle::ty::TypeckResults;
use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
/// Type used to check whether two ast are the same. This is different from the
/// operator
impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+ (&StmtKind::Local(l), &StmtKind::Local(r)) => {
// This additional check ensures that the type of the locals are equivalent even if the init
// expression or type have some inferred parts.
if let Some(typeck) = self.inner.maybe_typeck_results {
- let l_ty = typeck.pat_ty(&l.pat);
- let r_ty = typeck.pat_ty(&r.pat);
+ let l_ty = typeck.pat_ty(l.pat);
+ let r_ty = typeck.pat_ty(r.pat);
if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
return false;
}
// these only get added if the init and type is equal.
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
&& both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
- && self.eq_pat(&l.pat, &r.pat)
- },
- (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
- self.eq_expr(l, r)
+ && self.eq_pat(l.pat, r.pat)
},
+ (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
_ => false,
}
}
left.eq(right)
},
_ => {
- over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
+ over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
},
}
}
+ pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+ let cx = self.inner.cx;
+ let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+ eval_const(left) == eval_const(right)
+ }
+
#[allow(clippy::similar_names)]
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
&reduce_exprkind(self.inner.cx, &left.kind),
&reduce_exprkind(self.inner.cx, &right.kind),
) {
- (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
+ (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
lb == rb && l_mut == r_mut && self.eq_expr(le, re)
},
(&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
+ (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
+ (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
- (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
+ (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
+ (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|| swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
&& both(le, re, |l, r| self.eq_expr(l, r))
},
- (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
+ (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
(&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
- | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+ (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
},
- (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
+ (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
},
- (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
- self.eq_expr(la, ra) && self.eq_expr(li, ri)
- },
- (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
+ (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+ (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
},
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
- (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+ (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
+ (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
ls == rs
&& self.eq_expr(le, re)
&& over(la, ra, |l, r| {
- self.eq_pat(&l.pat, &r.pat)
+ self.eq_pat(l.pat, r.pat)
&& both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
- && self.eq_expr(&l.body, &r.body)
+ && self.eq_expr(l.body, r.body)
})
},
(&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
- let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
- let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
- let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
- let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
- self.eq_expr(le, re) && ll == rl
+ (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
+ self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
},
(&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
- (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
+ (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
self.eq_qpath(l_path, r_path)
&& both(lo, ro, |l, r| self.eq_expr(l, r))
&& over(lf, rf, |l, r| self.eq_expr_field(l, r))
},
(&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
- (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
+ (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
(&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
- (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
+ (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
_ => false,
};
is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
}
fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
- left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
+ left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
}
fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
match (left, right) {
+ (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
_ => false,
/// Checks whether two patterns are the same.
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
- (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+ (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
+ (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
},
- (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
+ (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
},
(&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
eq
},
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
- (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
- (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
- ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
- },
+ (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+ (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
},
- (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
- (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
+ (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
+ (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r))
&& over(le, re, |l, r| self.eq_pat(l, r))
&& both(li, ri, |l, r| self.eq_pat(l, r))
#[allow(clippy::similar_names)]
fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
match (left, right) {
- (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
+ (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
},
- (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
+ (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
(&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
match (left.res, right.res) {
(Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
(Res::Local(_), _) | (_, Res::Local(_)) => false,
- _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
+ _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
}
}
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
if !(left.parenthesized || right.parenthesized) {
- over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
- && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
+ over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
+ && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
} else if left.parenthesized && right.parenthesized {
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
&& both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
#[allow(clippy::similar_names)]
fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
- (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
- let cx = self.inner.cx;
- let eval_const =
- |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
- self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+ (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+ (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
+ self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
},
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
},
(&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
- (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+ (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
(&TyKind::Infer, &TyKind::Infer) => true,
_ => false,
}
}
fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
- left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
+ left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
}
}
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'tcx>,
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
- s: StableHasher,
+ s: FxHasher,
}
impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
Self {
cx,
maybe_typeck_results: cx.maybe_typeck_results(),
- s: StableHasher::new(),
+ s: FxHasher::default(),
}
}
self.hash_stmt(s);
}
- if let Some(ref e) = b.expr {
+ if let Some(e) = b.expr {
self.hash_expr(e);
}
- match b.rules {
- BlockCheckMode::DefaultBlock => 0,
- BlockCheckMode::UnsafeBlock(_) => 1,
- BlockCheckMode::PushUnsafeBlock(_) => 2,
- BlockCheckMode::PopUnsafeBlock(_) => 3,
- }
- .hash(&mut self.s);
+ std::mem::discriminant(&b.rules).hash(&mut self.s);
}
#[allow(clippy::many_single_char_names, clippy::too_many_lines)]
// const hashing may result in the same hash as some unrelated node, so add a sort of
// discriminant depending on which path we're choosing next
- simple_const.is_some().hash(&mut self.s);
-
- if let Some(e) = simple_const {
- return e.hash(&mut self.s);
+ simple_const.hash(&mut self.s);
+ if simple_const.is_some() {
+ return;
}
std::mem::discriminant(&e.kind).hash(&mut self.s);
match e.kind {
- ExprKind::AddrOf(kind, m, ref e) => {
- match kind {
- BorrowKind::Ref => 0,
- BorrowKind::Raw => 1,
- }
- .hash(&mut self.s);
+ ExprKind::AddrOf(kind, m, e) => {
+ std::mem::discriminant(&kind).hash(&mut self.s);
m.hash(&mut self.s);
self.hash_expr(e);
},
self.hash_name(i.ident.name);
}
},
- ExprKind::Assign(ref l, ref r, _) => {
+ ExprKind::Assign(l, r, _) => {
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::AssignOp(ref o, ref l, ref r) => {
- o.node
- .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::AssignOp(ref o, l, r) => {
+ std::mem::discriminant(&o.node).hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::Block(ref b, _) => {
+ ExprKind::Block(b, _) => {
self.hash_block(b);
},
- ExprKind::Binary(op, ref l, ref r) => {
- op.node
- .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::Binary(op, l, r) => {
+ std::mem::discriminant(&op.node).hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
},
if let Some(i) = i.label {
self.hash_name(i.ident.name);
}
- if let Some(ref j) = *j {
+ if let Some(j) = *j {
self.hash_expr(&*j);
}
},
- ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
+ ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
self.hash_expr(e);
},
- ExprKind::Call(ref fun, args) => {
+ ExprKind::Call(fun, args) => {
self.hash_expr(fun);
self.hash_exprs(args);
},
- ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
+ ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
self.hash_expr(e);
self.hash_ty(ty);
},
ExprKind::Closure(cap, _, eid, _, _) => {
- match cap {
- CaptureBy::Value => 0,
- CaptureBy::Ref => 1,
- }
- .hash(&mut self.s);
+ std::mem::discriminant(&cap).hash(&mut self.s);
// closures inherit TypeckResults
self.hash_expr(&self.cx.tcx.hir().body(eid).value);
},
- ExprKind::Field(ref e, ref f) => {
+ ExprKind::Field(e, ref f) => {
self.hash_expr(e);
self.hash_name(f.name);
},
- ExprKind::Index(ref a, ref i) => {
+ ExprKind::Index(a, i) => {
self.hash_expr(a);
self.hash_expr(i);
},
- ExprKind::InlineAsm(ref asm) => {
+ ExprKind::InlineAsm(asm) => {
for piece in asm.template {
match piece {
InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
ExprKind::Lit(ref l) => {
l.node.hash(&mut self.s);
},
- ExprKind::Loop(ref b, ref i, ..) => {
+ ExprKind::Loop(b, ref i, ..) => {
self.hash_block(b);
if let Some(i) = *i {
self.hash_name(i.ident.name);
}
},
- ExprKind::If(ref cond, ref then, ref else_opt) => {
- let c: fn(_, _, _) -> _ = ExprKind::If;
- c.hash(&mut self.s);
+ ExprKind::If(cond, then, ref else_opt) => {
self.hash_expr(cond);
- self.hash_expr(&**then);
- if let Some(ref e) = *else_opt {
+ self.hash_expr(then);
+ if let Some(e) = *else_opt {
self.hash_expr(e);
}
},
- ExprKind::Match(ref e, arms, ref s) => {
+ ExprKind::Match(e, arms, ref s) => {
self.hash_expr(e);
for arm in arms {
if let Some(ref e) = arm.guard {
self.hash_guard(e);
}
- self.hash_expr(&arm.body);
+ self.hash_expr(arm.body);
}
s.hash(&mut self.s);
},
- ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
+ ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
self.hash_name(path.ident.name);
self.hash_exprs(args);
},
ExprKind::ConstBlock(ref l_id) => {
self.hash_body(l_id.body);
},
- ExprKind::Repeat(ref e, ref l_id) => {
+ ExprKind::Repeat(e, ref l_id) => {
self.hash_expr(e);
self.hash_body(l_id.body);
},
ExprKind::Ret(ref e) => {
- if let Some(ref e) = *e {
+ if let Some(e) = *e {
self.hash_expr(e);
}
},
ExprKind::Path(ref qpath) => {
self.hash_qpath(qpath);
},
- ExprKind::Struct(ref path, fields, ref expr) => {
+ ExprKind::Struct(path, fields, ref expr) => {
self.hash_qpath(path);
for f in fields {
self.hash_name(f.ident.name);
- self.hash_expr(&f.expr);
+ self.hash_expr(f.expr);
}
- if let Some(ref e) = *expr {
+ if let Some(e) = *expr {
self.hash_expr(e);
}
},
ExprKind::Array(v) => {
self.hash_exprs(v);
},
- ExprKind::Unary(lop, ref le) => {
- lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::Unary(lop, le) => {
+ std::mem::discriminant(&lop).hash(&mut self.s);
self.hash_expr(le);
},
}
}
pub fn hash_name(&mut self, n: Symbol) {
- n.as_str().hash(&mut self.s);
+ n.hash(&mut self.s);
}
pub fn hash_qpath(&mut self, p: &QPath<'_>) {
match *p {
- QPath::Resolved(_, ref path) => {
+ QPath::Resolved(_, path) => {
self.hash_path(path);
},
- QPath::TypeRelative(_, ref path) => {
+ QPath::TypeRelative(_, path) => {
self.hash_name(path.ident.name);
},
QPath::LangItem(lang_item, ..) => {
- lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&lang_item).hash(&mut self.s);
},
}
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind {
PatKind::Binding(ann, _, _, pat) => {
- ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&ann).hash(&mut self.s);
if let Some(pat) = pat {
self.hash_pat(pat);
}
if let Some(e) = e {
self.hash_expr(e);
}
- i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&i).hash(&mut self.s);
},
- PatKind::Ref(pat, m) => {
+ PatKind::Ref(pat, mu) => {
self.hash_pat(pat);
- m.hash(&mut self.s);
+ std::mem::discriminant(&mu).hash(&mut self.s);
},
PatKind::Slice(l, m, r) => {
for pat in l {
self.hash_name(f.ident.name);
self.hash_pat(f.pat);
}
- e.hash(&mut self.s)
+ e.hash(&mut self.s);
},
PatKind::Tuple(pats, e) => {
for pat in pats {
_ => {
for seg in path.segments {
self.hash_name(seg.ident.name);
+ self.hash_generic_args(seg.args().args);
}
},
}
match &b.kind {
StmtKind::Local(local) => {
self.hash_pat(local.pat);
- if let Some(ref init) = local.init {
+ if let Some(init) = local.init {
self.hash_expr(init);
}
},
pub fn hash_guard(&mut self, g: &Guard<'_>) {
match g {
- Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
+ Guard::If(expr) | Guard::IfLet(_, expr) => {
self.hash_expr(expr);
},
}
self.hash_body(anon_const.body);
},
TyKind::Ptr(ref mut_ty) => {
- self.hash_ty(&mut_ty.ty);
+ self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::Rptr(lifetime, ref mut_ty) => {
self.hash_lifetime(lifetime);
- self.hash_ty(&mut_ty.ty);
+ self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::BareFn(bfn) => {
bfn.unsafety.hash(&mut self.s);
bfn.abi.hash(&mut self.s);
for arg in bfn.decl.inputs {
- self.hash_ty(&arg);
+ self.hash_ty(arg);
}
+ std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
match bfn.decl.output {
- FnRetTy::DefaultReturn(_) => {
- ().hash(&mut self.s);
- },
- FnRetTy::Return(ref ty) => {
+ FnRetTy::DefaultReturn(_) => {},
+ FnRetTy::Return(ty) => {
self.hash_ty(ty);
},
}
self.hash_ty(ty);
}
},
- TyKind::Path(ref qpath) => match qpath {
- QPath::Resolved(ref maybe_ty, ref path) => {
- if let Some(ref ty) = maybe_ty {
- self.hash_ty(ty);
- }
- for segment in path.segments {
- segment.ident.name.hash(&mut self.s);
- self.hash_generic_args(segment.args().args);
- }
- },
- QPath::TypeRelative(ref ty, ref segment) => {
- self.hash_ty(ty);
- segment.ident.name.hash(&mut self.s);
- },
- QPath::LangItem(lang_item, ..) => {
- lang_item.hash(&mut self.s);
- },
- },
+ TyKind::Path(ref qpath) => self.hash_qpath(qpath),
TyKind::OpaqueDef(_, arg_list) => {
self.hash_generic_args(arg_list);
},
#![feature(box_patterns)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
#![feature(rustc_private)]
#![recursion_limit = "512"]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
use if_chain::if_chain;
use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
/// Checks if an expression references a variable of the given name.
pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
- if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
if let [p] = path.segments {
return p.ident.name == var;
}
pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
match *path {
- QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
- QPath::TypeRelative(_, ref seg) => seg,
+ QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
+ QPath::TypeRelative(_, seg) => seg,
QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
}
}
pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
match *path {
- QPath::Resolved(_, ref path) => path.segments.get(0),
- QPath::TypeRelative(_, ref seg) => Some(seg),
+ QPath::Resolved(_, path) => path.segments.get(0),
+ QPath::TypeRelative(_, seg) => Some(seg),
QPath::LangItem(..) => None,
}
}
/// ```
pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
match *path {
- QPath::Resolved(_, ref path) => match_path(path, segments),
- QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+ QPath::Resolved(_, path) => match_path(path, segments),
+ QPath::TypeRelative(ty, segment) => match ty.kind {
TyKind::Path(ref inner_path) => {
if let [prefix @ .., end] = segments {
if match_qpath(inner_path, prefix) {
/// If the expression is a path to a local, returns the canonical `HirId` of the local.
pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
- if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
if let Res::Local(id) = path.res {
return Some(id);
}
let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() {
// method chains are stored last -> first
- if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
+ if let ExprKind::MethodCall(path, _, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
if args.iter().any(|e| e.span.from_expansion()) {
return None;
}
- matched.push(&**args); // build up `matched` backwards
- current = &args[0] // go to parent expression
+ matched.push(args); // build up `matched` backwards
+ current = &args[0]; // go to parent expression
} else {
return None;
}
match pat.kind {
PatKind::Binding(.., ref spname, _) => Some(spname.name),
PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
- PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
+ PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
_ => None,
}
}
kind: ImplItemKind::Fn(_, eid),
..
}) => match cx.tcx.hir().body(eid).value.kind {
- ExprKind::Block(ref block, _) => Some(block),
+ ExprKind::Block(block, _) => Some(block),
_ => None,
},
_ => None,
/// Checks if an expression is constructing a tuple-like enum variant or struct
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let ExprKind::Call(ref fun, _) = expr.kind {
+ if let ExprKind::Call(fun, _) = expr.kind {
if let ExprKind::Path(ref qp) = fun.kind {
let res = cx.qpath_res(qp, fun.hir_id);
return match res {
match pat.kind {
PatKind::Wild => false,
PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
- PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+ PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
PatKind::Lit(..) | PatKind::Range(..) => true,
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
- PatKind::Or(ref pats) => {
+ PatKind::Or(pats) => {
// TODO: should be the honest check, that pats is exhaustive set
are_refutable(cx, pats.iter().map(|pat| &**pat))
},
- PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
- PatKind::Struct(ref qpath, ref fields, _) => {
+ PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+ PatKind::Struct(ref qpath, fields, _) => {
is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
},
- PatKind::TupleStruct(ref qpath, ref pats, _) => {
+ PatKind::TupleStruct(ref qpath, pats, _) => {
is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
},
- PatKind::Slice(ref head, ref middle, ref tail) => {
+ PatKind::Slice(head, ref middle, tail) => {
match &cx.typeck_results().node_type(pat.hir_id).kind() {
rustc_ty::Slice(..) => {
// [..] is the only irrefutable slice pattern.
/// the function once on the given pattern.
pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
if let PatKind::Or(pats) = pat.kind {
- pats.iter().copied().for_each(f)
+ pats.iter().copied().for_each(f);
} else {
- f(pat)
+ f(pat);
}
}
/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
/// themselves.
pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
- while let ExprKind::Block(ref block, ..) = expr.kind {
+ while let ExprKind::Block(block, ..) = expr.kind {
match (block.stmts.is_empty(), block.expr.as_ref()) {
(true, Some(e)) => expr = e,
_ => break,
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
if_chain! {
- if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
+ if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
if let Res::SelfTy(..) = path.res;
then {
return true
pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
if_chain! {
- if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
+ if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
if is_lang_ctor(cx, path, ResultOk);
if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
if path_to_local_id(arm.body, hir_id);
}
}
- if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
+ if let ExprKind::Match(_, arms, ref source) = expr.kind {
// desugared from a `?` operator
if let MatchSource::TryDesugar = *source {
return Some(expr);
path: &[&str],
) -> Option<&'tcx [Expr<'tcx>]> {
if_chain! {
- if let ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let ExprKind::Call(fun, args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
if match_def_path(cx, fun_def_id, path);
then {
- return Some(&args)
+ return Some(args)
}
};
None
let mut conds = Vec::new();
let mut blocks: Vec<&Block<'_>> = Vec::new();
- while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
- conds.push(&**cond);
- if let ExprKind::Block(ref block, _) = then_expr.kind {
+ while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
+ conds.push(cond);
+ if let ExprKind::Block(block, _) = then_expr.kind {
blocks.push(block);
} else {
panic!("ExprKind::If node is not an ExprKind::Block");
}
- if let Some(ref else_expr) = *else_expr {
+ if let Some(else_expr) = *else_expr {
expr = else_expr;
} else {
break;
// final `else {..}`
if !blocks.is_empty() {
- if let ExprKind::Block(ref block, _) = expr.kind {
- blocks.push(&**block);
+ if let ExprKind::Block(block, _) = expr.kind {
+ blocks.push(block);
}
}
// check if expr is calling method or function with #[must_use] attribute
pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let did = match expr.kind {
- ExprKind::Call(ref path, _) => if_chain! {
+ ExprKind::Call(path, _) => if_chain! {
if let ExprKind::Path(ref qpath) = path.kind;
if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
then {
_ => None,
};
- did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
+ did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
}
/// Gets the node where an expression is either used, or it's type is unified with another branch.
Hash: Fn(&T) -> u64,
Eq: Fn(&T, &T) -> bool,
{
- if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
- return vec![(&exprs[0], &exprs[1])];
+ match exprs {
+ [a, b] if eq(a, b) => return vec![(a, b)],
+ _ if exprs.len() <= 2 => return vec![],
+ _ => {},
}
let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
- let mut map: FxHashMap<_, Vec<&_>> =
- FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+ let mut map: UnhashMap<u64, Vec<&_>> =
+ UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
for expr in exprs {
match map.entry(hash(expr)) {
1,34,0 { TRY_FROM }
1,30,0 { ITERATOR_FIND_MAP }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
+ 1,16,0 { STR_REPEAT }
}
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
- let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
+ let (unsuffixed, suffix) = split_suffix(src, lit_kind);
let float = matches!(lit_kind, LitKind::Float(..));
Some(NumericLiteral::new(unsuffixed, suffix, float))
} else {
if self.abort {
return;
}
- if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
+ if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
if args.len() == 1 && match_var(&args[0], self.name) {
if seg.ident.name.as_str() == "capacity" {
self.abort = true;
}
fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
- get_pat_name(&arg.pat)
+ get_pat_name(arg.pat)
}
cursor = proj_base;
match elem {
ProjectionElem::Field(..) => {
- let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty;
+ let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No union field accesses in `const fn`
if def.is_union() {
#![deny(clippy::missing_docs_in_private_items)]
use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite};
+use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{ast, token};
use rustc_ast_pretty::pprust::token_kind_to_string;
use rustc_hir as hir;
use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, SyntaxContext};
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::Display;
Self::hir_from_snippet(expr, snippet)
}
+ /// Same as `hir`, but first walks the span up to the given context. This will result in the
+ /// macro call, rather then the expansion, if the span is from a child context. If the span is
+ /// not from a child context, it will be used directly instead.
+ ///
+ /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
+ /// node would result in `box []`. If given the context of the address of expression, this
+ /// function will correctly get a snippet of `vec![]`.
+ pub fn hir_with_context(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ ctxt: SyntaxContext,
+ default: &'a str,
+ applicability: &mut Applicability,
+ ) -> Self {
+ let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
+
+ if in_macro {
+ Sugg::NonParen(snippet)
+ } else {
+ Self::hir_from_snippet(expr, snippet)
+ }
+ }
+
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
/// function variants of `Sugg`, since these use different snippet functions.
fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
if let Some(non_whitespace_offset) = non_whitespace_offset {
remove_span = remove_span
- .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
+ .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
}
}
// Returns whether the type has #[must_use] attribute
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() {
- ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
- ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
- ty::Slice(ref ty)
- | ty::Array(ref ty, _)
- | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
- | ty::Ref(_, ref ty, _) => {
+ ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+ ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+ ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
// for the Array case we don't need to care for the len == 0 case
// because we don't want to lint functions returning empty arrays
is_must_use_ty(cx, *ty)
},
- ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+ ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
ty::Opaque(ref def_id, _) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
- if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+ if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
return true;
}
}
ty::Dynamic(binder, _) => {
for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
- if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+ if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
return true;
}
}
/// Returns the base type for HIR references and pointers.
pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
match ty.kind {
- TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
+ TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
_ => ty,
}
}
//FIXME: This causes false negatives. We can't get the `NodeId` from
//`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
//`while`-body, not just the ones in the condition.
- self.skip = true
+ self.skip = true;
},
_ => {},
}
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
if let ty::BorrowKind::MutBorrow = bk {
- self.update(&cmt)
+ self.update(cmt);
}
}
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
- self.update(&cmt)
+ self.update(cmt);
}
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
}
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
- intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+ intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
}
}
+/// A type which can be visited.
pub trait Visitable<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V);
+ /// Calls the corresponding `visit_*` function on the visitor.
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
}
-impl Visitable<'tcx> for &'tcx Expr<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_expr(self)
- }
-}
-impl Visitable<'tcx> for &'tcx Block<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_block(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_stmt(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_body(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_arm(self)
- }
+macro_rules! visitable_ref {
+ ($t:ident, $f:ident) => {
+ impl Visitable<'tcx> for &'tcx $t<'tcx> {
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ visitor.$f(self);
+ }
+ }
+ };
}
+visitable_ref!(Block, visit_block);
/// Calls the given function for each break expression.
pub fn visit_break_exprs<'tcx>(
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
if let ExprKind::Break(dest, sub_expr) = e.kind {
- self.0(e, dest, sub_expr)
+ self.0(e, dest, sub_expr);
}
walk_expr(self, e);
}
self.found = true;
}
} else {
- walk_expr(self, e)
+ walk_expr(self, e);
}
}
}
# Assuming the current directory corresponds to the Clippy repository
$ git checkout $SHA
$ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version
-$ git push upstream master --tags # `upstream` is the `rust-lang/rust-clippy` remote
+$ git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote
```
After this, the release should be available on the Clippy [release page].
+++ /dev/null
-[package]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-authors = ["The Rust Clippy Developers"]
-license = "MIT OR Apache-2.0"
-description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang/rust-clippy"
-edition = "2018"
-
-[lib]
-name = "clippy_mini_macro_test"
-proc-macro = true
-
-[dependencies]
+++ /dev/null
-#![feature(proc_macro_quote)]
-#![deny(rust_2018_idioms)]
-// FIXME: Remove this attribute once the weird failure is gone.
-#![allow(unused_extern_crates)]
-extern crate proc_macro;
-
-use proc_macro::{quote, TokenStream};
-
-#[proc_macro_derive(ClippyMiniMacroTest)]
-/// # Panics
-///
-/// Panics if the macro derivation fails
-pub fn mini_macro(_: TokenStream) -> TokenStream {
- quote!(
- #[allow(unused)]
- fn needless_take_by_value(s: String) {
- println!("{}", s.len());
- }
- #[allow(unused)]
- fn needless_loop(items: &[u8]) {
- for i in 0..items.len() {
- println!("{}", items[i]);
- }
- }
- fn line_wrapper() {
- println!("{}", line!());
- }
- )
-}
[toolchain]
-channel = "nightly-2021-05-20"
+channel = "nightly-2021-06-03"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
}
#[must_use]
-pub fn get_channel() -> Option<String> {
+pub fn get_channel() -> String {
match env::var("CFG_RELEASE_CHANNEL") {
- Ok(channel) => Some(channel),
+ Ok(channel) => channel,
Err(_) => {
// if that failed, try to ask rustc -V, do some parsing and find out
match std::process::Command::new("rustc")
{
Some(rustc_output) => {
if rustc_output.contains("beta") {
- Some(String::from("beta"))
+ String::from("beta")
} else if rustc_output.contains("stable") {
- Some(String::from("stable"))
+ String::from("stable")
} else {
// default to nightly if we fail to parse
- Some(String::from("nightly"))
+ String::from("nightly")
}
},
// default to nightly
- None => Some(String::from("nightly")),
+ None => String::from("nightly"),
}
},
}
--- /dev/null
+# default config for tests, overrides clippy.toml at the project root
use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;
-use std::env::{self, set_var, var};
-use std::ffi::OsStr;
+use std::env::{self, remove_var, set_var, var_os};
+use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
config
}
-fn run_mode(cfg: &mut compiletest::Config) {
+fn run_ui(cfg: &mut compiletest::Config) {
cfg.mode = TestMode::Ui;
cfg.src_base = Path::new("tests").join("ui");
+ // use tests/clippy.toml
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
compiletest::run_tests(cfg);
}
continue;
}
let dir_path = dir.path();
- set_var("CARGO_MANIFEST_DIR", &dir_path);
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
for file in fs::read_dir(&dir_path)? {
let file = file?;
let file_path = file.path();
let tests = compiletest::make_tests(config);
- let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
let res = run_tests(config, tests);
- set_var("CARGO_MANIFEST_DIR", &manifest_dir);
match res {
Ok(true) => {},
Ok(false) => panic!("Some tests failed"),
Some("main.rs") => {},
_ => continue,
}
- set_var("CLIPPY_CONF_DIR", case.path());
+ let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
let paths = compiletest::common::TestPaths {
file: file_path,
base: config.src_base.clone(),
let tests = compiletest::make_tests(config);
let current_dir = env::current_dir().unwrap();
- let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
let res = run_tests(config, &config.filters, tests);
env::set_current_dir(current_dir).unwrap();
- set_var("CLIPPY_CONF_DIR", conf_dir);
match res {
Ok(true) => {},
fn compile_test() {
prepare_env();
let mut config = default_config();
- run_mode(&mut config);
+ run_ui(&mut config);
run_ui_toml(&mut config);
run_ui_cargo(&mut config);
run_internal_tests(&mut config);
}
+
+/// Restores an env var on drop
+#[must_use]
+struct VarGuard {
+ key: &'static str,
+ value: Option<OsString>,
+}
+
+impl VarGuard {
+ fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+ let value = var_os(key);
+ set_var(key, val);
+ Self { key, value }
+ }
+}
+
+impl Drop for VarGuard {
+ fn drop(&mut self) {
+ match self.value.as_deref() {
+ None => remove_var(self.key),
+ Some(value) => set_var(self.key, value),
+ }
+ }
+}
#[ignore]
#[cfg(feature = "metadata-collector-lint")]
fn run_metadata_collection_lint() {
+ use std::fs::File;
+ use std::time::SystemTime;
+
+ // Setup for validation
+ let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
+ let start_time = SystemTime::now();
+
+ // Run collection as is
std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
run_clippy_for_project("clippy_lints");
+
+ // Check if cargo caching got in the way
+ if let Ok(file) = File::open(metadata_output_path) {
+ if let Ok(metadata) = file.metadata() {
+ if let Ok(last_modification) = metadata.modified() {
+ if last_modification > start_time {
+ // The output file has been modified. Most likely by a hungry
+ // metadata collection monster. So We'll return.
+ return;
+ }
+ }
+ }
+ }
+
+ // Force cargo to invalidate the caches
+ filetime::set_file_mtime(
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
+ filetime::FileTime::now(),
+ )
+ .unwrap();
+
+ // Running the collection again
+ run_clippy_for_project("clippy_lints");
}
fn run_clippy_for_project(project: &str) {
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
error: aborting due to previous error
}
}
}
+
+#[proc_macro_derive(ClippyMiniMacroTest)]
+pub fn mini_macro(_: TokenStream) -> TokenStream {
+ quote!(
+ #[allow(unused)]
+ fn needless_take_by_value(s: String) {
+ println!("{}", s.len());
+ }
+ #[allow(unused)]
+ fn needless_loop(items: &[u8]) {
+ for i in 0..items.len() {
+ println!("{}", items[i]);
+ }
+ }
+ fn line_wrapper() {
+ println!("{}", line!());
+ }
+ )
+}
--- /dev/null
+pub fn warn<T>(_: T) {}
+
+macro_rules! define_macro {
+ ($d:tt $lower:ident $upper:ident) => {
+ #[macro_export]
+ macro_rules! $upper {
+ ($arg:tt) => {
+ $crate::$lower($arg)
+ };
+ }
+ };
+}
+
+define_macro! {$ warn WARNING}
--- /dev/null
+// aux-build:ice-7272-aux.rs
+
+#![allow(clippy::no_effect)]
+
+extern crate ice_7272_aux;
+
+use ice_7272_aux::*;
+
+pub fn main() {
+ || WARNING!("Style changed!");
+ || "}{";
+}
+++ /dev/null
-#[macro_use]
-extern crate clippy_mini_macro_test;
-
-#[deny(warnings)]
-fn main() {
- let x = Foo;
- println!("{:?}", x);
-}
-
-#[derive(ClippyMiniMacroTest, Debug)]
-struct Foo;
0
}
-pub struct A;
+struct A;
impl A {
pub fn as_ref(self) -> &'static str {
#[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)]
fn main() {}
LL | #[warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^
-error: aborting due to 14 previous errors
+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
+ |
+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: aborting due to 16 previous errors
-#![feature(non_ascii_idents)]
-#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![warn(clippy::enum_variant_names)]
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
enum FakeCallType {
WithOut,
}
-#[allow(clippy::pub_enum_variant_names)]
-mod allowed {
+#[allow(clippy::enum_variant_names)]
+pub mod allowed {
pub enum PubAllowed {
SomeThis,
SomeThat,
error: variant name ends with the enum's name
- --> $DIR/enum_variants.rs:16:5
+ --> $DIR/enum_variants.rs:15:5
|
LL | cFoo,
| ^^^^
= note: `-D clippy::enum-variant-names` implied by `-D warnings`
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:27:5
+ --> $DIR/enum_variants.rs:26:5
|
LL | FoodGood,
| ^^^^^^^^
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:28:5
+ --> $DIR/enum_variants.rs:27:5
|
LL | FoodMiddle,
| ^^^^^^^^^^
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:29:5
+ --> $DIR/enum_variants.rs:28:5
|
LL | FoodBad,
| ^^^^^^^
error: all variants have the same prefix: `Food`
- --> $DIR/enum_variants.rs:26:1
+ --> $DIR/enum_variants.rs:25:1
|
LL | / enum Food {
LL | | FoodGood,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `CallType`
- --> $DIR/enum_variants.rs:36:1
+ --> $DIR/enum_variants.rs:35:1
|
LL | / enum BadCallType {
LL | | CallTypeCall,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `Constant`
- --> $DIR/enum_variants.rs:48:1
+ --> $DIR/enum_variants.rs:47:1
|
LL | / enum Consts {
LL | | ConstantInt,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `With`
- --> $DIR/enum_variants.rs:82:1
+ --> $DIR/enum_variants.rs:81:1
|
LL | / enum Seallll {
LL | | WithOutCake,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `Prefix`
- --> $DIR/enum_variants.rs:88:1
+ --> $DIR/enum_variants.rs:87:1
|
LL | / enum NonCaps {
LL | | Prefixçš„,
|
= help: remove the prefixes and use full paths to the variants instead of glob imports
-error: all variants have the same prefix: `With`
- --> $DIR/enum_variants.rs:94:1
- |
-LL | / pub enum PubSeall {
-LL | | WithOutCake,
-LL | | WithOutTea,
-LL | | WithOut,
-LL | | }
- | |_^
- |
- = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
- = help: remove the prefixes and use full paths to the variants instead of glob imports
-
error: all variants have the same postfix: `IData`
- --> $DIR/enum_variants.rs:137:1
+ --> $DIR/enum_variants.rs:136:1
|
LL | / enum IDataRequest {
LL | | PutIData(String),
= help: remove the postfixes and use full paths to the variants instead of glob imports
error: all variants have the same postfix: `HIData`
- --> $DIR/enum_variants.rs:143:1
+ --> $DIR/enum_variants.rs:142:1
|
LL | / enum HIDataRequest {
LL | | PutHIData(String),
|
= help: remove the postfixes and use full paths to the variants instead of glob imports
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
// See #515
let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+ // issue #7224
+ let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
}
trait TestTrait {
// See #515
let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+ // issue #7224
+ let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
}
trait TestTrait {
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
error: redundant closure
- --> $DIR/eta.rs:89:51
+ --> $DIR/eta.rs:92:51
|
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
| ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
= note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
error: redundant closure
- --> $DIR/eta.rs:91:51
+ --> $DIR/eta.rs:94:51
|
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
error: redundant closure
- --> $DIR/eta.rs:94:42
+ --> $DIR/eta.rs:97:42
|
LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
| ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
error: redundant closure
- --> $DIR/eta.rs:99:29
+ --> $DIR/eta.rs:102:29
|
LL | let e = Some("str").map(|s| s.to_string());
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
error: redundant closure
- --> $DIR/eta.rs:101:27
+ --> $DIR/eta.rs:104:27
|
LL | let e = Some('a').map(|s| s.to_uppercase());
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
error: redundant closure
- --> $DIR/eta.rs:104:65
+ --> $DIR/eta.rs:107:65
|
LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
error: redundant closure
- --> $DIR/eta.rs:187:27
+ --> $DIR/eta.rs:190:27
|
LL | let a = Some(1u8).map(|a| foo_ptr(a));
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
error: redundant closure
- --> $DIR/eta.rs:192:27
+ --> $DIR/eta.rs:195:27
|
LL | let a = Some(1u8).map(|a| closure(a));
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
use std::iter::FromIterator;
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+ todo!()
+ }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+ iter.into_iter().copied().collect::<Self>()
+ }
+}
+
fn main() {
let iter_expr = std::iter::repeat(5).take(5);
let _ = iter_expr.collect::<Vec<_>>();
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
use std::iter::FromIterator;
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+ todo!()
+ }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+ <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+ }
+}
+
fn main() {
let iter_expr = std::iter::repeat(5).take(5);
let _ = Vec::from_iter(iter_expr);
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:11:13
+ --> $DIR/from_iter_instead_of_collect.rs:19:9
|
-LL | let _ = Vec::from_iter(iter_expr);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+LL | <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
|
= note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:13:13
+ --> $DIR/from_iter_instead_of_collect.rs:25:13
+ |
+LL | let _ = Vec::from_iter(iter_expr);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> $DIR/from_iter_instead_of_collect.rs:27:13
|
LL | let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:18:19
+ --> $DIR/from_iter_instead_of_collect.rs:32:19
|
LL | assert_eq!(a, Vec::from_iter(0..3));
| ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:19:19
+ --> $DIR/from_iter_instead_of_collect.rs:33:19
|
LL | assert_eq!(a, Vec::<i32>::from_iter(0..3));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:21:17
+ --> $DIR/from_iter_instead_of_collect.rs:35:17
|
LL | let mut b = VecDeque::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:24:17
+ --> $DIR/from_iter_instead_of_collect.rs:38:17
|
LL | let mut b = VecDeque::<i32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:29:21
+ --> $DIR/from_iter_instead_of_collect.rs:43:21
|
LL | let mut b = collections::VecDeque::<i32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:34:14
+ --> $DIR/from_iter_instead_of_collect.rs:48:14
|
LL | let bm = BTreeMap::from_iter(values.iter().cloned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:35:19
+ --> $DIR/from_iter_instead_of_collect.rs:49:19
|
LL | let mut bar = BTreeMap::from_iter(bm.range(0..2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:38:19
+ --> $DIR/from_iter_instead_of_collect.rs:52:19
|
LL | let mut bts = BTreeSet::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:42:17
+ --> $DIR/from_iter_instead_of_collect.rs:56:17
|
LL | let _ = collections::BTreeSet::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:43:17
+ --> $DIR/from_iter_instead_of_collect.rs:57:17
|
LL | let _ = collections::BTreeSet::<u32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:46:15
+ --> $DIR/from_iter_instead_of_collect.rs:60:15
|
LL | for _i in Vec::from_iter([1, 2, 3].iter()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:47:15
+ --> $DIR/from_iter_instead_of_collect.rs:61:15
|
LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:63:34
|
LL | println!("{}", unsafe { *p });
|
= note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:64:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:65:33
|
LL | unsafe { std::ptr::read(p) };
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:76:30
|
LL | println!("{}", unsafe { *p });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:77:31
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:78:29
|
LL | unsafe { std::ptr::read(p) };
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:87:34
|
LL | println!("{}", unsafe { *p });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:88:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:89:33
|
LL | unsafe { std::ptr::read(p) };
// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
// run-rustfix
// ignore-32bit
extern crate macro_use_helper as mac;
#[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
mod a {
use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
// run-rustfix
// ignore-32bit
extern crate macro_use_helper as mac;
#[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
mod a {
#[macro_use]
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:18:5
+ --> $DIR/macro_use_imports.rs:19: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:20:5
+ --> $DIR/macro_use_imports.rs:25: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::nested::string_add;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:22:5
+ --> $DIR/macro_use_imports.rs:21: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 mini_mac::ClippyMiniMacroTest;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:24:5
+ --> $DIR/macro_use_imports.rs:23: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 mac::{inner::foofoo, inner::try_err};`
error: aborting due to 4 previous errors
--- /dev/null
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+ let _: String = "test".repeat(10);
+ let _: String = "x".repeat(10);
+ let _: String = "'".repeat(10);
+ let _: String = "\"".repeat(10);
+
+ let x = "test";
+ let count = 10;
+ let _ = x.repeat(count + 2);
+
+ macro_rules! m {
+ ($e:expr) => {{ $e }};
+ }
+ // FIXME: macro args are fine
+ let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+ let x = &x;
+ let _: String = (*x).repeat(count);
+
+ macro_rules! repeat_m {
+ ($e:expr) => {{ repeat($e) }};
+ }
+ // Don't lint, repeat is from a macro.
+ let _: String = repeat_m!("test").take(count).collect();
+
+ let x: Box<str> = Box::from("test");
+ let _: String = x.repeat(count);
+
+ #[derive(Clone)]
+ struct S;
+ impl FromIterator<Box<S>> for String {
+ fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+ Self::new()
+ }
+ }
+ // Don't lint, wrong box type
+ let _: String = repeat(Box::new(S)).take(count).collect();
+
+ let _: String = Cow::Borrowed("test").repeat(count);
+
+ let x = "x".to_owned();
+ let _: String = x.repeat(count);
+
+ let x = 'x';
+ // Don't lint, not char literal
+ let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+ #![clippy::msrv = "1.15"]
+ // `str::repeat` was stabilized in 1.16. Do not lint this
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+ let _: String = "test".repeat(10);
+}
--- /dev/null
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+ let _: String = std::iter::repeat("test").take(10).collect();
+ let _: String = std::iter::repeat('x').take(10).collect();
+ let _: String = std::iter::repeat('\'').take(10).collect();
+ let _: String = std::iter::repeat('"').take(10).collect();
+
+ let x = "test";
+ let count = 10;
+ let _ = repeat(x).take(count + 2).collect::<String>();
+
+ macro_rules! m {
+ ($e:expr) => {{ $e }};
+ }
+ // FIXME: macro args are fine
+ let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+ let x = &x;
+ let _: String = repeat(*x).take(count).collect();
+
+ macro_rules! repeat_m {
+ ($e:expr) => {{ repeat($e) }};
+ }
+ // Don't lint, repeat is from a macro.
+ let _: String = repeat_m!("test").take(count).collect();
+
+ let x: Box<str> = Box::from("test");
+ let _: String = repeat(x).take(count).collect();
+
+ #[derive(Clone)]
+ struct S;
+ impl FromIterator<Box<S>> for String {
+ fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+ Self::new()
+ }
+ }
+ // Don't lint, wrong box type
+ let _: String = repeat(Box::new(S)).take(count).collect();
+
+ let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+
+ let x = "x".to_owned();
+ let _: String = repeat(x).take(count).collect();
+
+ let x = 'x';
+ // Don't lint, not char literal
+ let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+ #![clippy::msrv = "1.15"]
+ // `str::repeat` was stabilized in 1.16. Do not lint this
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
--- /dev/null
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:10:21
+ |
+LL | let _: String = std::iter::repeat("test").take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+ |
+ = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:11:21
+ |
+LL | let _: String = std::iter::repeat('x').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:12:21
+ |
+LL | let _: String = std::iter::repeat('/'').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:13:21
+ |
+LL | let _: String = std::iter::repeat('"').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:17:13
+ |
+LL | let _ = repeat(x).take(count + 2).collect::<String>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:26:21
+ |
+LL | let _: String = repeat(*x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:35:21
+ |
+LL | let _: String = repeat(x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:47:21
+ |
+LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:50:21
+ |
+LL | let _: String = repeat(x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:65:21
+ |
+LL | let _: String = std::iter::repeat("test").take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+
+error: aborting due to 10 previous errors
+
#![warn(clippy::missing_docs_in_private_items)]
-#![feature(external_doc)]
-#![doc(include = "../../README.md")]
+#![doc = include_str!("../../README.md")]
fn main() {}
pub fn foo() {}
/// dox
pub fn foo1() {}
- fn foo2() {}
+ #[must_use = "yep"]
+ fn foo2() -> u32 {
+ 1
+ }
#[allow(clippy::missing_docs_in_private_items)]
pub fn foo3() {}
}
| ^^^^^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:70:5
+ --> $DIR/missing-doc-impl.rs:71:5
|
-LL | fn foo2() {}
- | ^^^^^^^^^^^^
+LL | / fn foo2() -> u32 {
+LL | | 1
+LL | | }
+ | |_____^
error: aborting due to 15 previous errors
pub struct Foobar;
}
-#[cfg(test)]
-mod test {
- #[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
- }
-}
-
fn main() {}
let vec = Vec::new();
let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
- if let Some(cake) = Some(&5) {}
let garbl = match 42 {
44 => &a,
45 => {
impl<'a> Trait for &'a str {}
fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
- let mut v = Vec::<String>::new();
- let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- let _ = v.iter().filter(|&a| a.is_empty());
-
- let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
- Str(&'a str),
-}
let vec = Vec::new();
let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
- if let Some(ref cake) = Some(&5) {}
let garbl = match 42 {
44 => &a,
45 => {
impl<'a> Trait for &'a str {}
fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
- let mut v = Vec::<String>::new();
- let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- let _ = v.iter().filter(|&ref a| a.is_empty());
-
- let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
- Str(&'a str),
-}
|
= note: `-D clippy::needless-borrow` implied by `-D warnings`
-error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow.rs:21:17
- |
-LL | if let Some(ref cake) = Some(&5) {}
- | ^^^^^^^^ help: change this to: `cake`
-
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:28:15
+ --> $DIR/needless_borrow.rs:27:15
|
LL | 46 => &&a,
| ^^^ help: change this to: `&a`
-error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow.rs:51:31
- |
-LL | let _ = v.iter().filter(|&ref a| a.is_empty());
- | ^^^^^ help: change this to: `a`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
--- /dev/null
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::needless_borrow)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m1 {
+ ($e:expr) => {
+ f1($e);
+ };
+}
+macro_rules! m3 {
+ ($i:ident) => {
+ Some(ref $i)
+ };
+}
+macro_rules! if_chain {
+ (if $e:expr; $($rest:tt)*) => {
+ if $e {
+ if_chain!($($rest)*)
+ }
+ };
+
+ (if let $p:pat = $e:expr; $($rest:tt)*) => {
+ if let $p = $e {
+ if_chain!($($rest)*)
+ }
+ };
+
+ (then $b:block) => {
+ $b
+ };
+}
+
+#[allow(dead_code)]
+fn main() {
+ let x = String::new();
+
+ // Ok, reference to a String.
+ let _: &String = match Some(x.clone()) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Ok, reference to a &mut String
+ let _: &&mut String = match Some(&mut x.clone()) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Ok, the pattern is from a macro
+ let _: &String = match Some(&x) {
+ m3!(x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &String = match Some(&x) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String.
+ let _: &String = match Some(&x) {
+ Some(ref x) => *x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &String = match Some(&x) {
+ Some(ref x) => {
+ f1(x);
+ f1(*x);
+ x
+ },
+ None => return,
+ };
+
+ // Err, reference to a &String
+ match Some(&x) {
+ Some(ref x) => m1!(x),
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _ = |&ref x: &&String| {
+ let _: &String = x;
+ };
+
+ // Err, reference to a &String
+ let (ref y,) = (&x,);
+ let _: &String = *y;
+
+ let y = &&x;
+ // Ok, different y
+ let _: &String = *y;
+
+ let x = (0, 0);
+ // Err, reference to a &u32. Don't suggest adding a reference to the field access.
+ let _: u32 = match Some(&x) {
+ Some(ref x) => x.0,
+ None => return,
+ };
+
+ enum E {
+ A(&'static u32),
+ B(&'static u32),
+ }
+ // Err, reference to &u32.
+ let _: &u32 = match E::A(&0) {
+ E::A(ref x) | E::B(ref x) => *x,
+ };
+
+ // Err, reference to &String.
+ if_chain! {
+ if true;
+ if let Some(ref x) = Some(&String::new());
+ then {
+ f1(x);
+ }
+ }
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ let _: &String = x;
+ *x
+}
+
+trait T1 {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &String = x;
+ }
+}
+
+struct S;
+impl T1 for S {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &String = *x;
+ }
+}
+
+// Ok - used to error due to rustc bug
+#[allow(dead_code)]
+#[derive(Debug)]
+enum Foo<'a> {
+ Str(&'a str),
+}
--- /dev/null
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:60: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
+ |
+LL | Some(ref x) => *x,
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => x,
+ | ^ ^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:72:14
+ |
+LL | Some(ref x) => {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => {
+LL | f1(x);
+LL | f1(x);
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:82: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
+ |
+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
+ |
+LL | let (ref y,) = (&x,);
+ | ^^^^^
+ |
+help: try this
+ |
+LL | let (y,) = (&x,);
+LL | let _: &String = y;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:102: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
+ |
+LL | E::A(ref x) | E::B(ref x) => *x,
+ | ^^^^^ ^^^^^
+ |
+help: try this
+ |
+LL | E::A(x) | E::B(x) => x,
+ | ^ ^ ^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:118: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
+ |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL | let _: &String = x;
+LL | x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:133: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
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &String = x;
+ |
+
+error: aborting due to 12 previous errors
+
-use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
+use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
fn main() {
let sample = [1; 5];
buffer.len()
}
}
+
+fn allow_test() {
+ #[allow(clippy::needless_collect)]
+ let v = [1].iter().collect::<Vec<_>>();
+ v.into_iter().collect::<HashSet<_>>();
+}
let s: String = "foo".into();
FooString { s: s };
+ #[allow(clippy::no_effect)]
+ 0;
+
// Do not warn
get_number();
unsafe { unsafe_fn() };
--- /dev/null
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::ref_binding_to_reference)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m2 {
+ ($e:expr) => {
+ f1(*$e);
+ };
+}
+macro_rules! m3 {
+ ($i:ident) => {
+ Some(ref $i)
+ };
+}
+
+#[allow(dead_code)]
+fn main() {
+ let x = String::new();
+
+ // Ok, the pattern is from a macro
+ let _: &&String = match Some(&x) {
+ m3!(x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &&String = match Some(&x) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &&String = match Some(&x) {
+ Some(ref x) => {
+ f1(x);
+ f1(*x);
+ x
+ },
+ None => return,
+ };
+
+ // Err, reference to a &String
+ match Some(&x) {
+ Some(ref x) => m2!(x),
+ None => return,
+ }
+
+ // Err, reference to a &String
+ let _ = |&ref x: &&String| {
+ let _: &&String = x;
+ };
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ let _: &&String = x;
+ *x
+}
+
+trait T1 {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &&String = x;
+ }
+}
+
+struct S;
+impl T1 for S {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &&String = x;
+ }
+}
--- /dev/null
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:31:14
+ |
+LL | Some(ref x) => x,
+ | ^^^^^
+ |
+ = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
+help: try this
+ |
+LL | Some(x) => &x,
+ | ^ ^^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:37:14
+ |
+LL | Some(ref x) => {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => {
+LL | f1(x);
+LL | f1(x);
+LL | &x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:47:14
+ |
+LL | Some(ref x) => m2!(x),
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => m2!(&x),
+ | ^ ^^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:52:15
+ |
+LL | let _ = |&ref x: &&String| {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | let _ = |&x: &&String| {
+LL | let _: &&String = &x;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:58:12
+ |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL | let _: &&String = &x;
+LL | x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:65:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &&String = &x;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:73:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &&String = &x;
+ |
+
+error: aborting due to 7 previous errors
+
let rx1: i32;
let tx_cake: i32;
let rx_cake: i32;
+
+ // names often used in win32 code (for example WindowProc)
+ let wparam: i32;
+ let lparam: i32;
}
fn foo() {
| ^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:81:16
+ --> $DIR/similar_names.rs:85:16
|
LL | bpple: sprang,
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:80:16
+ --> $DIR/similar_names.rs:84:16
|
LL | apple: spring,
| ^^^^^^
x.rsplit('x');
x.split_terminator('x');
x.rsplit_terminator('x');
- x.splitn(0, 'x');
- x.rsplitn(0, 'x');
+ x.splitn(2, 'x');
+ x.rsplitn(2, 'x');
x.matches('x');
x.rmatches('x');
x.match_indices('x');
x.rsplit("x");
x.split_terminator("x");
x.rsplit_terminator("x");
- x.splitn(0, "x");
- x.rsplitn(0, "x");
+ x.splitn(2, "x");
+ x.rsplitn(2, "x");
x.matches("x");
x.rmatches("x");
x.match_indices("x");
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:28:17
|
-LL | x.splitn(0, "x");
+LL | x.splitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:29:18
|
-LL | x.rsplitn(0, "x");
+LL | x.rsplitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
--- /dev/null
+#![warn(clippy::suspicious_splitn)]
+
+fn main() {
+ let _ = "a,b,c".splitn(3, ',');
+ let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1);
+ let _ = "".splitn(0, ',');
+ let _ = [].splitn(0, |&x: &u32| x == 1);
+
+ let _ = "a,b".splitn(0, ',');
+ let _ = "a,b".rsplitn(0, ',');
+ let _ = "a,b".splitn(1, ',');
+ let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+ let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+ let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+ let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+
+ const X: usize = 0;
+ let _ = "a,b".splitn(X + 1, ',');
+ let _ = "a,b".splitn(X, ',');
+}
--- /dev/null
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:9:13
+ |
+LL | let _ = "a,b".splitn(0, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
+ = note: the resulting iterator will always return `None`
+
+error: `rsplitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:10:13
+ |
+LL | let _ = "a,b".rsplitn(0, ',');
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:11:13
+ |
+LL | let _ = "a,b".splitn(1, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:12:13
+ |
+LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn_mut` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:13:13
+ |
+LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:14:13
+ |
+LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `rsplitn_mut` called with `1` split
+ --> $DIR/suspicious_splitn.rs:15:13
+ |
+LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:18:13
+ |
+LL | let _ = "a,b".splitn(X + 1, ',');
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:19:13
+ |
+LL | let _ = "a,b".splitn(X, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: aborting due to 9 previous errors
+
LL | fn trait_method(&self, _foo: &Foo);
| ^^^^ help: consider passing by value instead: `Foo`
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:80:37
- |
-LL | fn trait_method2(&self, _color: &Color);
- | ^^^^^^ help: consider passing by value instead: `Color`
-
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
--> $DIR/trivially_copy_pass_by_ref.rs:108:21
|
LL | fn foo(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
unimplemented!()
}
-struct A;
+pub struct A;
impl A {
// should not be linted
// run-rustfix
+// aux-build:proc_macro_derive.rs
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]
#[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
// Test for proc-macro attribute
#[derive(ClippyMiniMacroTest)]
// run-rustfix
+// aux-build:proc_macro_derive.rs
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]
#[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
// Test for proc-macro attribute
#[derive(ClippyMiniMacroTest)]
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:23:18
+ --> $DIR/unseparated_prefix_literals.rs:24:18
|
LL | let _fail1 = 1234i32;
| ^^^^^^^ help: add an underscore: `1234_i32`
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:24:18
+ --> $DIR/unseparated_prefix_literals.rs:25:18
|
LL | let _fail2 = 1234u32;
| ^^^^^^^ help: add an underscore: `1234_u32`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:25:18
+ --> $DIR/unseparated_prefix_literals.rs:26:18
|
LL | let _fail3 = 1234isize;
| ^^^^^^^^^ help: add an underscore: `1234_isize`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:26:18
+ --> $DIR/unseparated_prefix_literals.rs:27:18
|
LL | let _fail4 = 1234usize;
| ^^^^^^^^^ help: add an underscore: `1234_usize`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:27:18
+ --> $DIR/unseparated_prefix_literals.rs:28:18
|
LL | let _fail5 = 0x123isize;
| ^^^^^^^^^^ help: add an underscore: `0x123_isize`
error: float type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:31:19
+ --> $DIR/unseparated_prefix_literals.rs:32:19
|
LL | let _failf1 = 1.5f32;
| ^^^^^^ help: add an underscore: `1.5_f32`
error: float type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:32:19
+ --> $DIR/unseparated_prefix_literals.rs:33:19
|
LL | let _failf2 = 1f32;
| ^^^^ help: add an underscore: `1_f32`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:15:9
+ --> $DIR/unseparated_prefix_literals.rs:16:9
|
LL | 42usize
| ^^^^^^^ help: add an underscore: `42_usize`
= note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:40:16
+ --> $DIR/unseparated_prefix_literals.rs:41:16
|
LL | assert_eq!(4897u32, 32223);
| ^^^^^^^ help: add an underscore: `4897_u32`
// edition:2018
#![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]
fn main() {}
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:18:17
+ --> $DIR/wrong_self_convention.rs:17: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:24:21
+ --> $DIR/wrong_self_convention.rs:23: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:36:15
+ --> $DIR/wrong_self_convention.rs:35: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:38:17
+ --> $DIR/wrong_self_convention.rs:37: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:40:15
+ --> $DIR/wrong_self_convention.rs:39: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:42:15
+ --> $DIR/wrong_self_convention.rs:41: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:44:17
+ --> $DIR/wrong_self_convention.rs:43: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:46:19
+ --> $DIR/wrong_self_convention.rs:45: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:47:21
+ --> $DIR/wrong_self_convention.rs:46: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:48:19
+ --> $DIR/wrong_self_convention.rs:47: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:49:19
+ --> $DIR/wrong_self_convention.rs:48: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:50:21
+ --> $DIR/wrong_self_convention.rs:49: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:95:19
+ --> $DIR/wrong_self_convention.rs:94: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:98:25
+ --> $DIR/wrong_self_convention.rs:97: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:100:19
+ --> $DIR/wrong_self_convention.rs:99: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:104:21
+ --> $DIR/wrong_self_convention.rs:103: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:119:19
+ --> $DIR/wrong_self_convention.rs:118: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:122:25
+ --> $DIR/wrong_self_convention.rs:121: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:124:19
+ --> $DIR/wrong_self_convention.rs:123: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:128:21
+ --> $DIR/wrong_self_convention.rs:127: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:146:25
+ --> $DIR/wrong_self_convention.rs:145: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:152:21
+ --> $DIR/wrong_self_convention.rs:151: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:176:22
+ --> $DIR/wrong_self_convention.rs:175: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:185:19
+ --> $DIR/wrong_self_convention.rs:184:19
|
LL | fn to_u64(self) -> u64 {
| ^^^^
// edition:2018
#![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]
fn main() {}
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:56:29
+ --> $DIR/wrong_self_convention2.rs:55: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:65:25
+ --> $DIR/wrong_self_convention2.rs:64:25
|
LL | fn from_be_self(self) -> Self;
| ^^^^
+++ /dev/null
-#!/usr/bin/bash
-
-# This run `kcov` on Clippy. The coverage report will be at
-# `./target/cov/index.html`.
-# `compile-test` is special. `kcov` does not work directly on it so these files
-# are compiled manually.
-
-tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;)
-tmpdir=$(mktemp -d)
-
-cargo test --no-run --verbose
-
-for t in $tests; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/$t" \
- cargo test --test "$t"
-done
-
-for t in ./tests/compile-fail/*.rs; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/compile-fail-$(basename "$t")" \
- cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-for t in ./tests/run-pass/*.rs; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/run-pass-$(basename "$t")" \
- cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-kcov --verify --merge target/cov "$tmpdir"/*
jsonpath_lib = "0.2"
getopts = "0.2"
regex = "1.4"
-lazy_static = "1.4"
-shlex = "0.1"
-serde = "1.0"
+shlex = "1.0"
serde_json = "1.0"
fs-err = "2.5.0"
+once_cell = "1.0"
use jsonpath_lib::select;
-use lazy_static::lazy_static;
+use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::borrow::Cow;
}
}
-lazy_static! {
- static ref LINE_PATTERN: Regex = RegexBuilder::new(
+static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
+ RegexBuilder::new(
r#"
\s(?P<invalid>!?)@(?P<negated>!?)
(?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
(?P<args>.*)$
- "#
+ "#,
)
.ignore_whitespace(true)
.unicode(true)
.build()
- .unwrap();
-}
+ .unwrap()
+});
fn print_err(msg: &str, lineno: usize) {
eprintln!("Invalid command: {} on line {}", msg, lineno)
if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ]
then
echo "Downloading linkchecker source..."
+ nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ")
+ url="https://raw.githubusercontent.com/rust-lang/rust"
mkdir linkchecker
- curl -o linkchecker/Cargo.toml \
- https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml
- curl -o linkchecker/main.rs \
- https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs
+ curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml
+ curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs
fi
echo "Building book \"$book_name\"..."
check_path="linkcheck/$book_name"
fi
echo "Running linkchecker on \"$check_path\"..."
-cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path"
+cargo run --release --manifest-path=linkchecker/Cargo.toml -- "$check_path"
if [ "$iterative" = "0" ]
then
//! A few exceptions are allowed as there's known bugs in rustdoc, but this
//! should catch the majority of "broken link" cases.
-use std::collections::hash_map::Entry;
+use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
+use std::io::ErrorKind;
use std::path::{Component, Path, PathBuf};
use std::rc::Rc;
+use std::time::Instant;
use once_cell::sync::Lazy;
use regex::Regex;
-use crate::Redirect::*;
-
// Add linkcheck exceptions here
// If at all possible you should use intra-doc links to avoid linkcheck issues. These
// are cases where that does not work
}
fn main() {
- let docs = env::args_os().nth(1).unwrap();
+ let docs = env::args_os().nth(1).expect("doc path should be first argument");
let docs = env::current_dir().unwrap().join(docs);
- let mut errors = false;
- walk(&mut HashMap::new(), &docs, &docs, &mut errors);
- if errors {
- panic!("found some broken links");
+ let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
+ let mut report = Report {
+ errors: 0,
+ start: Instant::now(),
+ html_files: 0,
+ html_redirects: 0,
+ links_checked: 0,
+ links_ignored_external: 0,
+ links_ignored_exception: 0,
+ intra_doc_exceptions: 0,
+ };
+ checker.walk(&docs, &mut report);
+ report.report();
+ if report.errors != 0 {
+ println!("found some broken links");
+ std::process::exit(1);
}
}
-#[derive(Debug)]
-pub enum LoadError {
- IOError(std::io::Error),
- BrokenRedirect(PathBuf, std::io::Error),
- IsRedirect,
+struct Checker {
+ root: PathBuf,
+ cache: Cache,
}
-enum Redirect {
- SkipRedirect,
- FromRedirect(bool),
+struct Report {
+ errors: u32,
+ start: Instant,
+ html_files: u32,
+ html_redirects: u32,
+ links_checked: u32,
+ links_ignored_external: u32,
+ links_ignored_exception: u32,
+ intra_doc_exceptions: u32,
}
-struct FileEntry {
- source: Rc<String>,
- ids: HashSet<String>,
+/// A cache entry.
+enum FileEntry {
+ /// An HTML file.
+ ///
+ /// This includes the contents of the HTML file, and an optional set of
+ /// HTML IDs. The IDs are used for checking fragments. The are computed
+ /// as-needed. The source is discarded (replaced with an empty string)
+ /// after the file has been checked, to conserve on memory.
+ HtmlFile { source: Rc<String>, ids: RefCell<HashSet<String>> },
+ /// This file is an HTML redirect to the given local path.
+ Redirect { target: PathBuf },
+ /// This is not an HTML file.
+ OtherFile,
+ /// This is a directory.
+ Dir,
+ /// The file doesn't exist.
+ Missing,
}
-type Cache = HashMap<PathBuf, FileEntry>;
+/// A cache to speed up file access.
+type Cache = HashMap<String, FileEntry>;
fn small_url_encode(s: &str) -> String {
s.replace("<", "%3C")
.replace("\"", "%22")
}
-impl FileEntry {
- fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
- if self.ids.is_empty() {
- with_attrs_in_source(contents, " id", |fragment, i, _| {
- let frag = fragment.trim_start_matches("#").to_owned();
- let encoded = small_url_encode(&frag);
- if !self.ids.insert(frag) {
- *errors = true;
- println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
- }
- // Just in case, we also add the encoded id.
- self.ids.insert(encoded);
- });
- }
- }
-}
-
-fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
- for entry in t!(dir.read_dir()).map(|e| t!(e)) {
- let path = entry.path();
- let kind = t!(entry.file_type());
- if kind.is_dir() {
- walk(cache, root, &path, errors);
- } else {
- let pretty_path = check(cache, root, &path, errors);
- if let Some(pretty_path) = pretty_path {
- let entry = cache.get_mut(&pretty_path).unwrap();
- // we don't need the source anymore,
- // so drop to reduce memory-usage
- entry.source = Rc::new(String::new());
+impl Checker {
+ /// Primary entry point for walking the filesystem to find HTML files to check.
+ fn walk(&mut self, dir: &Path, report: &mut Report) {
+ for entry in t!(dir.read_dir()).map(|e| t!(e)) {
+ let path = entry.path();
+ let kind = t!(entry.file_type());
+ if kind.is_dir() {
+ self.walk(&path, report);
+ } else {
+ self.check(&path, report);
}
}
}
-}
-
-fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
- if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
- entry.1.is_empty() || entry.1.contains(&link)
- } else {
- false
- }
-}
-fn is_exception(file: &Path, link: &str) -> bool {
- if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
- entry.1.contains(&link)
- } else {
- // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
- //
- // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
- // calculated in `check` function is outside `build/<triple>/doc` dir.
- // So the `strip_prefix` method just returns the old absolute broken path.
- if file.ends_with("std/primitive.slice.html") {
- if link.ends_with("primitive.slice.html") {
- return true;
+ /// Checks a single file.
+ fn check(&mut self, file: &Path, report: &mut Report) {
+ let (pretty_path, entry) = self.load_file(file, report);
+ let source = match entry {
+ FileEntry::Missing => panic!("missing file {:?} while walking", file),
+ FileEntry::Dir => unreachable!("never with `check` path"),
+ FileEntry::OtherFile => return,
+ FileEntry::Redirect { .. } => return,
+ FileEntry::HtmlFile { source, ids } => {
+ parse_ids(&mut ids.borrow_mut(), &pretty_path, source, report);
+ source.clone()
}
- }
- false
- }
-}
-
-fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> {
- // Ignore non-HTML files.
- if file.extension().and_then(|s| s.to_str()) != Some("html") {
- return None;
- }
+ };
- let res = load_file(cache, root, file, SkipRedirect);
- let (pretty_file, contents) = match res {
- Ok(res) => res,
- Err(_) => return None,
- };
- {
- cache.get_mut(&pretty_file).unwrap().parse_ids(&pretty_file, &contents, errors);
- }
+ // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
+ with_attrs_in_source(&source, " href", |url, i, base| {
+ // Ignore external URLs
+ if url.starts_with("http:")
+ || url.starts_with("https:")
+ || url.starts_with("javascript:")
+ || url.starts_with("ftp:")
+ || url.starts_with("irc:")
+ || url.starts_with("data:")
+ {
+ report.links_ignored_external += 1;
+ return;
+ }
+ report.links_checked += 1;
+ let (url, fragment) = match url.split_once('#') {
+ None => (url, None),
+ Some((url, fragment)) => (url, Some(fragment)),
+ };
+ // NB: the `splitn` always succeeds, even if the delimiter is not present.
+ let url = url.splitn(2, '?').next().unwrap();
+
+ // Once we've plucked out the URL, parse it using our base url and
+ // then try to extract a file path.
+ let mut path = file.to_path_buf();
+ if !base.is_empty() || !url.is_empty() {
+ path.pop();
+ for part in Path::new(base).join(url).components() {
+ match part {
+ Component::Prefix(_) | Component::RootDir => {
+ // Avoid absolute paths as they make the docs not
+ // relocatable by making assumptions on where the docs
+ // are hosted relative to the site root.
+ report.errors += 1;
+ println!(
+ "{}:{}: absolute path - {}",
+ pretty_path,
+ i + 1,
+ Path::new(base).join(url).display()
+ );
+ return;
+ }
+ Component::CurDir => {}
+ Component::ParentDir => {
+ path.pop();
+ }
+ Component::Normal(s) => {
+ path.push(s);
+ }
+ }
+ }
+ }
- // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
- with_attrs_in_source(&contents, " href", |url, i, base| {
- // Ignore external URLs
- if url.starts_with("http:")
- || url.starts_with("https:")
- || url.starts_with("javascript:")
- || url.starts_with("ftp:")
- || url.starts_with("irc:")
- || url.starts_with("data:")
- {
- return;
- }
- let (url, fragment) = match url.split_once('#') {
- None => (url, None),
- Some((url, fragment)) => (url, Some(fragment)),
- };
- // NB: the `splitn` always succeeds, even if the delimiter is not present.
- let url = url.splitn(2, '?').next().unwrap();
-
- // Once we've plucked out the URL, parse it using our base url and
- // then try to extract a file path.
- let mut path = file.to_path_buf();
- if !base.is_empty() || !url.is_empty() {
- path.pop();
- for part in Path::new(base).join(url).components() {
- match part {
- Component::Prefix(_) | Component::RootDir => {
- // Avoid absolute paths as they make the docs not
- // relocatable by making assumptions on where the docs
- // are hosted relative to the site root.
- *errors = true;
+ let (target_pretty_path, target_entry) = self.load_file(&path, report);
+ let (target_source, target_ids) = match target_entry {
+ FileEntry::Missing => {
+ if is_exception(file, &target_pretty_path) {
+ report.links_ignored_exception += 1;
+ } else {
+ report.errors += 1;
println!(
- "{}:{}: absolute path - {}",
- pretty_file.display(),
+ "{}:{}: broken link - `{}`",
+ pretty_path,
i + 1,
- Path::new(base).join(url).display()
+ target_pretty_path
);
- return;
- }
- Component::CurDir => {}
- Component::ParentDir => {
- path.pop();
}
- Component::Normal(s) => {
- path.push(s);
- }
- }
- }
- }
-
- // Alright, if we've found a file name then this file had better
- // exist! If it doesn't then we register and print an error.
- if path.exists() {
- if path.is_dir() {
- // Links to directories show as directory listings when viewing
- // the docs offline so it's best to avoid them.
- *errors = true;
- let pretty_path = path.strip_prefix(root).unwrap_or(&path);
- println!(
- "{}:{}: directory link - {}",
- pretty_file.display(),
- i + 1,
- pretty_path.display()
- );
- return;
- }
- if let Some(extension) = path.extension() {
- // Ignore none HTML files.
- if extension != "html" {
return;
}
- }
- let res = load_file(cache, root, &path, FromRedirect(false));
- let (pretty_path, contents) = match res {
- Ok(res) => res,
- Err(LoadError::IOError(err)) => {
- panic!("error loading {}: {}", path.display(), err);
- }
- Err(LoadError::BrokenRedirect(target, _)) => {
- *errors = true;
+ FileEntry::Dir => {
+ // Links to directories show as directory listings when viewing
+ // the docs offline so it's best to avoid them.
+ report.errors += 1;
println!(
- "{}:{}: broken redirect to {}",
- pretty_file.display(),
+ "{}:{}: directory link to `{}` \
+ (directory links should use index.html instead)",
+ pretty_path,
i + 1,
- target.display()
+ target_pretty_path
);
return;
}
- Err(LoadError::IsRedirect) => unreachable!(),
+ FileEntry::OtherFile => return,
+ FileEntry::Redirect { target } => {
+ let t = target.clone();
+ drop(target);
+ let (target, redir_entry) = self.load_file(&t, report);
+ match redir_entry {
+ FileEntry::Missing => {
+ report.errors += 1;
+ println!(
+ "{}:{}: broken redirect from `{}` to `{}`",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target
+ );
+ return;
+ }
+ FileEntry::Redirect { target } => {
+ // Redirect to a redirect, this link checker
+ // currently doesn't support this, since it would
+ // require cycle checking, etc.
+ report.errors += 1;
+ println!(
+ "{}:{}: redirect from `{}` to `{}` \
+ which is also a redirect (not supported)",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target.display()
+ );
+ return;
+ }
+ FileEntry::Dir => {
+ report.errors += 1;
+ println!(
+ "{}:{}: redirect from `{}` to `{}` \
+ which is a directory \
+ (directory links should use index.html instead)",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target
+ );
+ return;
+ }
+ FileEntry::OtherFile => return,
+ FileEntry::HtmlFile { source, ids } => (source, ids),
+ }
+ }
+ FileEntry::HtmlFile { source, ids } => (source, ids),
};
+ // Alright, if we've found an HTML file for the target link. If
+ // this is a fragment link, also check that the `id` exists.
if let Some(ref fragment) = fragment {
// Fragments like `#1-6` are most likely line numbers to be
// interpreted by javascript, so we're ignoring these
return;
}
- let entry = &mut cache.get_mut(&pretty_path).unwrap();
- entry.parse_ids(&pretty_path, &contents, errors);
+ parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
+
+ if target_ids.borrow().contains(*fragment) {
+ return;
+ }
- if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment))
- {
- *errors = true;
- print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1);
- println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
+ if is_exception(file, &format!("#{}", fragment)) {
+ report.links_ignored_exception += 1;
+ } else {
+ report.errors += 1;
+ print!("{}:{}: broken link fragment ", pretty_path, i + 1);
+ println!("`#{}` pointing to `{}`", fragment, pretty_path);
};
}
- } else {
- let pretty_path = path.strip_prefix(root).unwrap_or(&path);
- if !is_exception(file, pretty_path.to_str().unwrap()) {
- *errors = true;
- print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
- println!("{}", pretty_path.display());
+ });
+
+ // Search for intra-doc links that rustdoc didn't warn about
+ // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
+ // NOTE: only looks at one line at a time; in practice this should find most links
+ for (i, line) in source.lines().enumerate() {
+ for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
+ if is_intra_doc_exception(file, &broken_link[1]) {
+ report.intra_doc_exceptions += 1;
+ } else {
+ report.errors += 1;
+ print!("{}:{}: broken intra-doc link - ", pretty_path, i + 1);
+ println!("{}", &broken_link[0]);
+ }
}
}
- });
-
- // Search for intra-doc links that rustdoc didn't warn about
- // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
- // NOTE: only looks at one line at a time; in practice this should find most links
- for (i, line) in contents.lines().enumerate() {
- for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
- if !is_intra_doc_exception(file, &broken_link[1]) {
- *errors = true;
- print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1);
- println!("{}", &broken_link[0]);
- }
+ // we don't need the source anymore,
+ // so drop to reduce memory-usage
+ match self.cache.get_mut(&pretty_path).unwrap() {
+ FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+ _ => unreachable!("must be html file"),
}
}
- Some(pretty_file)
-}
-fn load_file(
- cache: &mut Cache,
- root: &Path,
- file: &Path,
- redirect: Redirect,
-) -> Result<(PathBuf, Rc<String>), LoadError> {
- let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));
-
- let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) {
- Entry::Occupied(entry) => (None, entry.get().source.clone()),
- Entry::Vacant(entry) => {
- let contents = match fs::read_to_string(file) {
- Ok(s) => Rc::new(s),
- Err(err) => {
- return Err(if let FromRedirect(true) = redirect {
- LoadError::BrokenRedirect(file.to_path_buf(), err)
+ /// Load a file from disk, or from the cache if available.
+ fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
+ let pretty_path =
+ file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();
+
+ let entry =
+ self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) {
+ Ok(metadata) if metadata.is_dir() => FileEntry::Dir,
+ Ok(_) => {
+ if file.extension().and_then(|s| s.to_str()) != Some("html") {
+ FileEntry::OtherFile
} else {
- LoadError::IOError(err)
- });
+ report.html_files += 1;
+ load_html_file(file, report)
+ }
}
- };
-
- let maybe = maybe_redirect(&contents);
- if maybe.is_some() {
- if let SkipRedirect = redirect {
- return Err(LoadError::IsRedirect);
+ Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
+ Err(e) => {
+ panic!("unexpected read error for {}: {}", file.display(), e);
}
- } else {
- entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new() });
- }
- (maybe, contents)
+ });
+ (pretty_path, entry)
+ }
+}
+
+impl Report {
+ fn report(&self) {
+ println!("checked links in: {:.1}s", self.start.elapsed().as_secs_f64());
+ println!("number of HTML files scanned: {}", self.html_files);
+ println!("number of HTML redirects found: {}", self.html_redirects);
+ println!("number of links checked: {}", self.links_checked);
+ println!("number of links ignored due to external: {}", self.links_ignored_external);
+ println!("number of links ignored due to exceptions: {}", self.links_ignored_exception);
+ println!("number of intra doc links ignored: {}", self.intra_doc_exceptions);
+ println!("errors found: {}", self.errors);
+ }
+}
+
+fn load_html_file(file: &Path, report: &mut Report) -> FileEntry {
+ let source = match fs::read_to_string(file) {
+ Ok(s) => Rc::new(s),
+ Err(err) => {
+ // This usually should not fail since `metadata` was already
+ // called successfully on this file.
+ panic!("unexpected read error for {}: {}", file.display(), err);
}
};
- match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
- Some(redirect_file) => load_file(cache, root, &redirect_file, FromRedirect(true)),
- None => Ok((pretty_file, contents)),
+ match maybe_redirect(&source) {
+ Some(target) => {
+ report.html_redirects += 1;
+ let target = file.parent().unwrap().join(target);
+ FileEntry::Redirect { target }
+ }
+ None => FileEntry::HtmlFile { source: source.clone(), ids: RefCell::new(HashSet::new()) },
+ }
+}
+
+fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
+ if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+ entry.1.is_empty() || entry.1.contains(&link)
+ } else {
+ false
}
}
+fn is_exception(file: &Path, link: &str) -> bool {
+ if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+ entry.1.contains(&link)
+ } else {
+ // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+ //
+ // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+ // calculated in `check` function is outside `build/<triple>/doc` dir.
+ // So the `strip_prefix` method just returns the old absolute broken path.
+ if file.ends_with("std/primitive.slice.html") {
+ if link.ends_with("primitive.slice.html") {
+ return true;
+ }
+ }
+ false
+ }
+}
+
+/// If the given HTML file contents is an HTML redirect, this returns the
+/// destination path given in the redirect.
fn maybe_redirect(source: &str) -> Option<String> {
const REDIRECT: &str = "<p>Redirecting to <a href=";
let mut lines = source.lines();
- let redirect_line = lines.nth(6)?;
+ let redirect_line = lines.nth(7)?;
redirect_line.find(REDIRECT).map(|i| {
let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
})
}
-fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
+fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
let mut base = "";
- for (i, mut line) in contents.lines().enumerate() {
+ for (i, mut line) in source.lines().enumerate() {
while let Some(j) = line.find(attr) {
let rest = &line[j + attr.len()..];
// The base tag should always be the first link in the document so
}
}
}
+
+fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) {
+ if ids.is_empty() {
+ with_attrs_in_source(source, " id", |fragment, i, _| {
+ let frag = fragment.trim_start_matches("#").to_owned();
+ let encoded = small_url_encode(&frag);
+ if !ids.insert(frag) {
+ report.errors += 1;
+ println!("{}:{}: id is not unique: `{}`", file, i, fragment);
+ }
+ // Just in case, we also add the encoded id.
+ ids.insert(encoded);
+ });
+ }
+}
--- /dev/null
+<html>
+<body>
+<a href="bar.html">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a href="#somefrag">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a href="../bar.html#somefrag">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="redir-bad.html">bad redir</a>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=sometarget">
+</head>
+<body>
+ <p>Redirecting to <a href="sometarget">sometarget</a>...</p>
+ <script>location.replace("sometarget" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+use std::path::Path;
+use std::process::{Command, ExitStatus};
+
+fn run(dirname: &str) -> (ExitStatus, String, String) {
+ let output = Command::new(env!("CARGO_BIN_EXE_linkchecker"))
+ .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"))
+ .arg(dirname)
+ .output()
+ .unwrap();
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ let stderr = String::from_utf8(output.stderr).unwrap();
+ (output.status, stdout, stderr)
+}
+
+fn broken_test(dirname: &str, expected: &str) {
+ let (status, stdout, stderr) = run(dirname);
+ assert!(!status.success());
+ if !stdout.contains(expected) {
+ panic!(
+ "stdout did not contain expected text: {}\n\
+ --- stdout:\n\
+ {}\n\
+ --- stderr:\n\
+ {}\n",
+ expected, stdout, stderr
+ );
+ }
+}
+
+fn valid_test(dirname: &str) {
+ let (status, stdout, stderr) = run(dirname);
+ if !status.success() {
+ panic!(
+ "test did not succeed as expected\n\
+ --- stdout:\n\
+ {}\n\
+ --- stderr:\n\
+ {}\n",
+ stdout, stderr
+ );
+ }
+}
+
+#[test]
+fn valid() {
+ valid_test("valid/inner");
+}
+
+#[test]
+fn basic_broken() {
+ broken_test("basic_broken", "bar.html");
+}
+
+#[test]
+fn broken_fragment_local() {
+ broken_test("broken_fragment_local", "#somefrag");
+}
+
+#[test]
+fn broken_fragment_remote() {
+ broken_test("broken_fragment_remote/inner", "#somefrag");
+}
+
+#[test]
+fn broken_redir() {
+ broken_test("broken_redir", "sometarget");
+}
+
+#[test]
+fn directory_link() {
+ broken_test("directory_link", "somedir");
+}
+
+#[test]
+fn redirect_loop() {
+ broken_test("redirect_loop", "redir-bad.html");
+}
--- /dev/null
+<html>
+<body>
+ <a href="somedir">dir link</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="redir-bad.html">loop link</a>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=redir-bad.html">
+</head>
+<body>
+ <p>Redirecting to <a href="redir-bad.html">redir-bad.html</a>...</p>
+ <script>location.replace("redir-bad.html" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+
+ <h2 id="barfrag">Bar</h2>
+
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="#localfrag">test local frag</a>
+ <a href="../outer.html">remote link</a>
+ <a href="../outer.html#somefrag">remote link with fragment</a>
+ <a href="bar.html">this book</a>
+ <a href="bar.html#barfrag">this book with fragment</a>
+ <a href="https://example.com/doesnotexist">external links not validated</a>
+ <a href="redir.html#redirfrag">Redirect</a>
+
+ <h2 id="localfrag">Local</h2>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=xxx">
+</head>
+<body>
+ <p>Redirecting to <a href="xxx">xxx</a>...</p>
+ <script>location.replace("xxx" + location.search + location.hash);</script>
+ These files are skipped, but probably shouldn't be.
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <h2 id="redirfrag">Redir</h2>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=redir-target.html">
+</head>
+<body>
+ <p>Redirecting to <a href="redir-target.html">redir-target.html</a>...</p>
+ <script>location.replace("redir-target.html" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a id="somefrag"></a>
+</body>
+</html>
-Subproject commit 3a249581280ea0181cf3ae0d2028ee8b88d3d1e4
+Subproject commit 5dde0fe6de2941c9ef16bc1e9d91ecf20ac5ee8b
-Subproject commit 097d8908339e20435078233a55a1a3335fe7c2eb
+Subproject commit 9ed6f96f2ff85753c5a6ac290ee88ecb2831ab2e
-Subproject commit b82458818d44dfe5b4b5db38d8113e3f3194506e
+Subproject commit f4383981249d3f2964f2c667f3349f8ff15b77c4
// This is more convenient that setting fields one by one.
options.parseArguments([
"--no-screenshot",
+ // This option shows what puppeteer "code" is run
+ // "--debug",
+ // This option disable the headless mode, allowing you to see what's going on.
+ // "--no-headless",
+ // The text isn't rendered by default because of a lot of small differences
+ // between hosts.
+ // "--show-text",
"--variable", "DOC_PATH", opts["doc_folder"],
]);
} catch (error) {
"ar",
"autocfg",
"bitflags",
- "byteorder",
"cfg-if",
"cranelift-bforest",
"cranelift-codegen",
"cranelift-native",
"cranelift-object",
"crc32fast",
- "errno",
- "errno-dragonfly",
- "gcc",
"gimli",
"hashbrown",
"indexmap",
"log",
"mach",
"object",
- "proc-macro2",
- "quote",
"regalloc",
"region",
"rustc-hash",
"smallvec",
- "syn",
"target-lexicon",
- "thiserror",
- "thiserror-impl",
- "unicode-xid",
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
- "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
- "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
- "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
- "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
- "E0729",
+ "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
+ "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
+ "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
+ "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
];
// Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
fn check_error_code_explanation(
f: &str,
.expect("failed to canonicalize error explanation file path");
match read_to_string(&path) {
Ok(content) => {
- if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
- && !check_if_error_code_is_test_in_explanation(&content, &err_code)
- {
+ let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
+ if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
errors.push(format!(
"`{}` doesn't use its own error code in compile_fail example",
path.display(),
));
+ } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
+ errors.push(format!(
+ "`{}` has a compile_fail example with its own error code, it shouldn't \
+ be listed in IGNORE_EXPLANATION_CHECK!",
+ path.display(),
+ ));
}
if check_error_code_explanation(&content, error_codes, err_code) {
errors.push(format!(
for (err_code, nb) in &error_codes {
if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+ } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
+ errors.push(format!(
+ "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
+ err_code
+ ));
}
}
}
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1371;
-const ISSUES_ENTRY_LIMIT: usize = 2558;
+const ISSUES_ENTRY_LIMIT: usize = 2559;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source");
let doc_targets: HashSet<_> = doc_targets_md
.lines()
- .filter(|line| line.starts_with('`') && line.contains('|'))
+ .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|'))
.map(|line| line.split('`').skip(1).next().expect("expected target code span"))
.collect();
"regression-from-stable-to-stable",
"regression-from-stable-to-beta",
"regression-from-stable-to-nightly",
- "I-unsound 💥",
+ "I-unsound",
]
exclude_labels = [
"P-*",