diff options
1541 files changed, 22450 insertions, 13056 deletions
diff --git a/.gitattributes b/.gitattributes index 82599b14503..51a670b5fbe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,11 +16,3 @@ config.toml.example linguist-language=TOML *.ico binary *.woff binary *.woff2 binary - -# Needed as part of converting rustfmt to a subtree, can hopefully be removed later. -src/tools/rustfmt/tests/source/issue-3494/crlf.rs -text -src/tools/rustfmt/tests/source/comment_crlf_newline.rs -text -src/tools/rustfmt/tests/source/configs/enum_discrim_align_threshold/40.rs -text -src/tools/rustfmt/tests/target/issue-3494/crlf.rs -text -src/tools/rustfmt/tests/target/comment_crlf_newline.rs -text -src/tools/rustfmt/tests/target/configs/enum_discrim_align_threshold/40.rs -text diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa9d97ba477..36362635b15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -259,6 +259,11 @@ jobs: - name: x86_64-gnu os: ubuntu-latest-xl env: {} + - name: x86_64-gnu-stable + env: + IMAGE: x86_64-gnu + RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable + os: ubuntu-latest-xl - name: x86_64-gnu-aux os: ubuntu-latest-xl env: {} diff --git a/.mailmap b/.mailmap index cd617ca2f42..213aa6eff66 100644 --- a/.mailmap +++ b/.mailmap @@ -43,6 +43,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com> Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org> Brian Dawn <brian.t.dawn@gmail.com> Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com> +Noah Lev <camelidcamel@gmail.com> Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com> Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com> Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com> diff --git a/Cargo.lock b/Cargo.lock index da65b376d19..2f06506eaa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,6 +278,7 @@ dependencies = [ "humantime 2.0.1", "ignore", "im-rc", + "itertools 0.10.0", "jobserver", "lazy_static", "lazycell", @@ -292,8 +293,8 @@ dependencies = [ "pretty_env_logger", "rand 0.8.3", "rustc-workspace-hack", - "rustfix", - "semver 0.10.0", + "rustfix 0.6.0", + "semver 1.0.3", "serde", "serde_ignored", "serde_json", @@ -441,9 +442,9 @@ version = "0.1.0" [[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", ] @@ -551,10 +552,10 @@ name = "clippy" 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", @@ -567,10 +568,6 @@ dependencies = [ ] [[package]] -name = "clippy-mini-macro-test" -version = "0.2.0" - -[[package]] name = "clippy_dev" version = "0.0.1" dependencies = [ @@ -655,9 +652,9 @@ dependencies = [ [[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", @@ -675,7 +672,7 @@ dependencies = [ "libc", "miow 0.3.6", "regex", - "rustfix", + "rustfix 0.5.1", "serde", "serde_json", "tracing", @@ -699,7 +696,7 @@ dependencies = [ "log", "miow 0.3.6", "regex", - "rustfix", + "rustfix 0.5.1", "serde", "serde_derive", "serde_json", @@ -1716,6 +1713,15 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1743,11 +1749,10 @@ dependencies = [ "fs-err", "getopts", "jsonpath_lib", - "lazy_static", + "once_cell", "regex", - "serde", "serde_json", - "shlex 0.1.1", + "shlex", ] [[package]] @@ -2128,16 +2133,16 @@ dependencies = [ "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", @@ -2149,9 +2154,9 @@ dependencies = [ [[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" @@ -2195,9 +2200,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.0.39" +version = "0.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdf618de5c9c98d4a7b2e0d1f1e44f82a19196cfd94040bb203621c25d28d98" +checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08" dependencies = [ "macro-utils", ] @@ -2289,6 +2294,7 @@ dependencies = [ "hex 0.4.2", "libc", "log", + "measureme", "rand 0.8.3", "rustc-workspace-hack", "rustc_version", @@ -2354,6 +2360,17 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2845,9 +2862,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.46" +version = "2.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1" +checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb" dependencies = [ "bitflags", "clap", @@ -3071,7 +3088,7 @@ dependencies = [ "anyhow", "cargo", "cargo-util", - "cargo_metadata 0.8.2", + "cargo_metadata 0.12.0", "clippy_lints", "crossbeam-channel", "difference", @@ -3204,9 +3221,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_arena" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676" +checksum = "550ca1a0925d31a0af089b18c89f5adf3b286e319e3e1f1a5204c21bd2f17371" dependencies = [ "rustc-ap-rustc_data_structures", "smallvec", @@ -3214,9 +3231,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b" +checksum = "4aa53b68080df17994a54747f7c37b0686288a670efb9ba3b382ce62e744aed2" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -3231,9 +3248,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1" +checksum = "0ae71e68fada466a4b2c39c79ca6aee3226587abe6787170d2f6c92237569565" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_span", @@ -3242,9 +3259,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77" +checksum = "faa484d6e0ca32d1d82303647275c696f745599b3d97e686f396ceef5b99d7ae" dependencies = [ "arrayvec", "bitflags", @@ -3274,9 +3291,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_errors" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a" +checksum = "5f85ba19cca320ad797e3a29c35cab9bddfff0e7adbde336a436249e54cee7b1" dependencies = [ "annotate-snippets", "atty", @@ -3294,9 +3311,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_feature" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507" +checksum = "97d538adab96b8b2b1ca9fcd4c8c47d4e23e862a23d1a38b6c15cd8fd52b34b1" dependencies = [ "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", @@ -3304,21 +3321,21 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_fs_util" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6" +checksum = "8ad6f13d240944fa8f360d2f3b849a7cadaec75e477829e7dde61e838deda83d" [[package]] name = "rustc-ap-rustc_graphviz" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6" +checksum = "08b3451153cc5828c02cc4f1a0df146d25ac4b3382a112e25fd9d3f5bff15cdc" [[package]] name = "rustc-ap-rustc_index" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3" +checksum = "cd39a9f01b442c629bdff5778cb3dd29b7c2ea4afe62d5ab61d216bd1b556692" dependencies = [ "arrayvec", "rustc-ap-rustc_macros", @@ -3327,18 +3344,18 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_lexer" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df" +checksum = "a5de290c44a90e671d2cd730062b9ef73d11155da7e44e7741d633e1e51e616e" dependencies = [ "unicode-xid", ] [[package]] name = "rustc-ap-rustc_lint_defs" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47" +checksum = "69570b4beb61088926b131579865bbe70d124d30778c46307a62ec8b310ae462" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_data_structures", @@ -3351,9 +3368,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_macros" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c" +checksum = "86bd877df37f15c5a44d9679d1b5207ebc95f3943fbc336eeac670195ac58610" dependencies = [ "proc-macro2", "quote", @@ -3363,9 +3380,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa" +checksum = "02502d8522ba31d0bcad28a78822b68c1b6ba947a2b4aa6a2341b30594379b80" dependencies = [ "bitflags", "rustc-ap-rustc_ast", @@ -3383,9 +3400,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_serialize" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4" +checksum = "5f741f8e9aee6323fbe127329490608a5a250cc0072ac91e684ef62518cdb1ff" dependencies = [ "indexmap", "smallvec", @@ -3393,9 +3410,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_session" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a" +checksum = "dba61eca749f4fced4427ad1cc7f23342cfc6527c3bcc624e3aa56abc1f81298" dependencies = [ "bitflags", "getopts", @@ -3415,9 +3432,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_span" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214" +checksum = "a642e8d6fc883f34e0778e079f8242ac40c6614a6b7a0ef61681333e847f5e62" dependencies = [ "cfg-if 0.1.10", "md-5", @@ -3435,9 +3452,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_target" -version = "718.0.0" +version = "722.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862" +checksum = "80feebd8c323b80dd73a395fa7fabba9e2098b6277670ff89c473f618ffa07de" dependencies = [ "bitflags", "rustc-ap-rustc_data_structures", @@ -3676,6 +3693,7 @@ dependencies = [ "rustc_incremental", "rustc_index", "rustc_llvm", + "rustc_metadata", "rustc_middle", "rustc_serialize", "rustc_session", @@ -3695,7 +3713,7 @@ dependencies = [ "itertools 0.9.0", "jobserver", "libc", - "object", + "object 0.25.2", "pathdiff", "rustc_apfloat", "rustc_ast", @@ -3876,6 +3894,7 @@ dependencies = [ "rand 0.7.3", "rustc_ast", "rustc_data_structures", + "rustc_errors", "rustc_fs_util", "rustc_graphviz", "rustc_hir", @@ -4536,6 +4555,18 @@ dependencies = [ ] [[package]] +name = "rustfix" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0be05fc0675ef4f47119dc39cfc46636bb77d4fc4ef1bd851b9c3f7697f32a" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + +[[package]] name = "rustfmt-config_proc_macro" version = "0.2.0" dependencies = [ @@ -4673,6 +4704,15 @@ dependencies = [ ] [[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" @@ -4794,12 +4834,6 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" @@ -4902,7 +4936,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", - "object", + "object 0.22.0", "panic_abort", "panic_unwind", "profiler_builtins", @@ -5031,9 +5065,9 @@ dependencies = [ [[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", diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index c648147d108..7eeec4aa86b 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -35,7 +35,6 @@ #![forbid(unsafe_code)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #[macro_use] extern crate alloc; diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b3bac1d7ecd..93d7a597681 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -623,12 +623,13 @@ impl Pat { PatKind::Ident(_, _, Some(p)) => p.walk(it), // Walk into each field of struct. - PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)), + PatKind::Struct(_, _, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)), // Sequence of patterns. - PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) | PatKind::Or(s) => { - s.iter().for_each(|p| p.walk(it)) - } + PatKind::TupleStruct(_, _, s) + | PatKind::Tuple(s) + | PatKind::Slice(s) + | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)), // Trivial wrappers over inner patterns. PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), @@ -701,10 +702,10 @@ pub enum PatKind { /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. - Struct(Path, Vec<PatField>, /* recovered */ bool), + Struct(Option<QSelf>, Path, Vec<PatField>, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - TupleStruct(Path, Vec<P<Pat>>), + TupleStruct(Option<QSelf>, Path, Vec<P<Pat>>), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. @@ -1247,6 +1248,7 @@ pub enum StructRest { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StructExpr { + pub qself: Option<QSelf>, pub path: Path, pub fields: Vec<ExprField>, pub rest: StructRest, diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs index 945a44ab663..d586426d70e 100644 --- a/compiler/rustc_ast/src/ast_like.rs +++ b/compiler/rustc_ast/src/ast_like.rs @@ -82,7 +82,8 @@ impl AstLike for crate::token::Nonterminal { Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtVis(vis) => vis.tokens_mut(), - _ => panic!("Called tokens_mut on {:?}", self), + Nonterminal::NtBlock(block) => block.tokens_mut(), + Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None, } } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index ffec28a395f..7c79b4aab3c 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -10,15 +10,13 @@ )] #![feature(box_syntax)] #![feature(box_patterns)] -#![cfg_attr(bootstrap, feature(const_fn))] // For the `transmute` in `P::new` -#![cfg_attr(not(bootstrap), feature(const_fn_unsize))] // 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] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 071d41ea2b2..0b6099fd330 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1139,7 +1139,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { visit_opt(sub, |sub| vis.visit_pat(sub)); } PatKind::Lit(e) => vis.visit_expr(e), - PatKind::TupleStruct(path, elems) => { + PatKind::TupleStruct(qself, path, elems) => { + vis.visit_qself(qself); vis.visit_path(path); visit_vec(elems, |elem| vis.visit_pat(elem)); } @@ -1147,7 +1148,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { vis.visit_qself(qself); vis.visit_path(path); } - PatKind::Struct(path, fields, _etc) => { + PatKind::Struct(qself, path, fields, _etc) => { + vis.visit_qself(qself); vis.visit_path(path); fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); } @@ -1333,7 +1335,8 @@ pub fn noop_visit_expr<T: MutVisitor>( } ExprKind::MacCall(mac) => vis.visit_mac_call(mac), ExprKind::Struct(se) => { - let StructExpr { path, fields, rest } = se.deref_mut(); + let StructExpr { qself, path, fields, rest } = se.deref_mut(); + vis.visit_qself(qself); vis.visit_path(path); fields.flat_map_in_place(|field| vis.flat_map_expr_field(field)); match rest { diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 2d463a4588c..5d994dbad4d 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -218,8 +218,7 @@ impl AttrAnnotatedTokenStream { AttrAnnotatedTokenTree::Attributes(data) => { let mut outer_attrs = Vec::new(); let mut inner_attrs = Vec::new(); - let attrs: Vec<_> = data.attrs.clone().into(); - for attr in attrs { + for attr in &data.attrs { match attr.style { crate::AttrStyle::Outer => { assert!( @@ -264,7 +263,7 @@ impl AttrAnnotatedTokenStream { // so we never reach this code. let mut builder = TokenStreamBuilder::new(); - for inner_attr in &inner_attrs { + for inner_attr in inner_attrs { builder.push(inner_attr.tokens().to_tokenstream()); } builder.push(delim_tokens.clone()); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index f1a99bc51c9..1ebfcf36711 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -497,7 +497,10 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { match pattern.kind { - PatKind::TupleStruct(ref path, ref elems) => { + PatKind::TupleStruct(ref opt_qself, ref path, ref elems) => { + if let Some(ref qself) = *opt_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, pattern.id); walk_list!(visitor, visit_pat, elems); } @@ -507,7 +510,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } visitor.visit_path(path, pattern.id) } - PatKind::Struct(ref path, ref fields, _) => { + PatKind::Struct(ref opt_qself, ref path, ref fields, _) => { + if let Some(ref qself) = *opt_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, pattern.id); walk_list!(visitor, visit_pat_field, fields); } @@ -740,6 +746,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_anon_const(count) } ExprKind::Struct(ref se) => { + if let Some(ref qself) = se.qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(&se.path, expression.id); walk_list!(visitor, visit_expr_field, &se.fields); match &se.rest { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 866f2180bb6..b9dcd083c0b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -237,7 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Struct( self.arena.alloc(self.lower_qpath( e.id, - &None, + &se.qself, &se.path, ParamMode::Optional, ImplTraitContext::disallowed(), @@ -1041,10 +1041,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// It is not a complete check, but just tries to reject most paths early /// if they are not tuple structs. /// Type checking will take care of the full validation later. - fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> { - // For tuple struct destructuring, it must be a non-qualified path (like in patterns). - if let ExprKind::Path(None, path) = &expr.kind { - // Does the path resolves to something disallowed in a tuple struct/variant pattern? + fn extract_tuple_struct_path<'a>( + &mut self, + expr: &'a Expr, + ) -> Option<(&'a Option<QSelf>, &'a Path)> { + if let ExprKind::Path(qself, path) = &expr.kind { + // Does the path resolve to something disallowed in a tuple struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { if partial_res.unresolved_segments() == 0 && !partial_res.base_res().expected_in_tuple_struct_pat() @@ -1052,7 +1054,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return None; } } - return Some(path); + return Some((qself, path)); } None } @@ -1088,7 +1090,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Tuple structs. ExprKind::Call(callee, args) => { - if let Some(path) = self.extract_tuple_struct_path(callee) { + if let Some((qself, path)) = self.extract_tuple_struct_path(callee) { let (pats, rest) = self.destructure_sequence( args, "tuple struct or variant", @@ -1097,7 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let qpath = self.lower_qpath( callee.id, - &None, + qself, path, ParamMode::Optional, ImplTraitContext::disallowed(), @@ -1122,7 +1124,7 @@ impl<'hir> LoweringContext<'_, 'hir> { })); let qpath = self.lower_qpath( lhs.id, - &None, + &se.qself, &se.path, ParamMode::Optional, ImplTraitContext::disallowed(), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 56f97054f96..0ff1efd8165 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -31,7 +31,6 @@ //! 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"] @@ -44,7 +43,7 @@ use rustc_ast::walk_list; 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; @@ -199,7 +198,7 @@ pub trait ResolverAstLowering { 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>; @@ -502,14 +501,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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(); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2451409aac8..66e623528f3 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -21,10 +21,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); } PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref path, ref pats) => { + PatKind::TupleStruct(ref qself, ref path, ref pats) => { let qpath = self.lower_qpath( pattern.id, - &None, + qself, path, ParamMode::Optional, ImplTraitContext::disallowed(), @@ -47,10 +47,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); break hir::PatKind::Path(qpath); } - PatKind::Struct(ref path, ref fields, etc) => { + PatKind::Struct(ref qself, ref path, ref fields, etc) => { let qpath = self.lower_qpath( pattern.id, - &None, + qself, path, ParamMode::Optional, ImplTraitContext::disallowed(), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba2da769497..357a2e65cf7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -889,35 +889,32 @@ fn validate_generic_param_order( ) { let mut max_param: Option<ParamKindOrd> = None; let mut out_of_order = FxHashMap::default(); - let mut param_idents = vec![]; + let mut param_idents = Vec::with_capacity(generics.len()); - for param in generics { - let ident = Some(param.ident.to_string()); - let (kind, bounds, span) = (¶m.kind, Some(&*param.bounds), param.ident.span); + for (idx, param) in generics.iter().enumerate() { + let ident = param.ident; + let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); let (ord_kind, ident) = match ¶m.kind { - GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident), - GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident), + GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), + GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()), GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { let ty = pprust::ty_to_string(ty); let unordered = sess.features_untracked().unordered_const_ty_params(); - (ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty))) + (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty)) } }; - if let Some(ident) = ident { - param_idents.push((kind, ord_kind, bounds, param_idents.len(), ident)); - } - let max_param = &mut max_param; + param_idents.push((kind, ord_kind, bounds, idx, ident)); match max_param { - Some(max_param) if *max_param > ord_kind => { - let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![])); + Some(max_param) if max_param > ord_kind => { + let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![])); entry.1.push(span); } - Some(_) | None => *max_param = Some(ord_kind), + Some(_) | None => max_param = Some(ord_kind), }; } - let mut ordered_params = "<".to_string(); if !out_of_order.is_empty() { + let mut ordered_params = "<".to_string(); param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); let mut first = true; for (kind, _, bounds, _, ident) in param_idents { @@ -925,12 +922,12 @@ fn validate_generic_param_order( ordered_params += ", "; } ordered_params += &ident; - if let Some(bounds) = bounds { - if !bounds.is_empty() { - ordered_params += ": "; - ordered_params += &pprust::bounds_to_string(&bounds); - } + + if !bounds.is_empty() { + ordered_params += ": "; + ordered_params += &pprust::bounds_to_string(&bounds); } + match kind { GenericParamKind::Type { default: Some(default) } => { ordered_params += " = "; @@ -938,37 +935,40 @@ fn validate_generic_param_order( } GenericParamKind::Type { default: None } => (), GenericParamKind::Lifetime => (), - // FIXME(const_generics_defaults) - GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (), + GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { + ordered_params += " = "; + ordered_params += &pprust::expr_to_string(&*default.value); + } + GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), } first = false; } - } - ordered_params += ">"; - for (param_ord, (max_param, spans)) in &out_of_order { - let mut err = - handler.struct_span_err( + ordered_params += ">"; + + for (param_ord, (max_param, spans)) in &out_of_order { + let mut err = handler.struct_span_err( spans.clone(), &format!( "{} parameters must be declared prior to {} parameters", param_ord, max_param, ), ); - err.span_suggestion( - span, - &format!( - "reorder the parameters: lifetimes, {}", - if sess.features_untracked().const_generics { - "then consts and types" - } else { - "then types, then consts" - } - ), - ordered_params.clone(), - Applicability::MachineApplicable, - ); - err.emit(); + err.span_suggestion( + span, + &format!( + "reorder the parameters: lifetimes, {}", + if sess.features_untracked().unordered_const_ty_params() { + "then consts and types" + } else { + "then types, then consts" + } + ), + ordered_params.clone(), + Applicability::MachineApplicable, + ); + err.emit(); + } } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 4996c2195ef..3f98944d850 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -318,7 +318,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }} gate_doc!( - include => external_doc cfg => doc_cfg masked => doc_masked notable_trait => doc_notable_trait @@ -706,6 +705,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { "async closures are unstable", "to use an async block, remove the `||`: `async {`" ); + gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); gate_all!(generators, "yield syntax is experimental"); gate_all!(raw_ref_op, "raw address of syntax is experimental"); gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index c9e2d202da9..26da18b571c 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -6,7 +6,6 @@ #![feature(bindings_after_at)] #![feature(iter_is_partitioned)] -#![feature(box_syntax)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 67b66284f66..6bd543ff150 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,6 +1,5 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index da9d89745a8..93facd255df 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -955,12 +955,12 @@ impl<'a> State<'a> { 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(); @@ -1397,12 +1397,7 @@ impl<'a> State<'a> { } } - 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(); @@ -1451,6 +1446,7 @@ impl<'a> State<'a> { } ast::VariantData::Struct(ref fields, ..) => { self.print_where_clause(&generics.where_clause); + self.nbsp(); self.print_record_struct_body(fields, span); } } @@ -1717,11 +1713,16 @@ impl<'a> State<'a> { fn print_expr_struct( &mut self, + qself: &Option<ast::QSelf>, path: &ast::Path, fields: &[ast::ExprField], rest: &ast::StructRest, ) { - self.print_path(path, true, 0); + if let Some(qself) = qself { + self.print_qpath(path, qself, true); + } else { + self.print_path(path, true, 0); + } self.s.word("{"); self.commasep_cmnt( Consistent, @@ -1878,7 +1879,7 @@ impl<'a> State<'a> { self.print_expr_repeat(element, count); } ast::ExprKind::Struct(ref se) => { - self.print_expr_struct(&se.path, &se.fields, &se.rest); + self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest); } ast::ExprKind::Tup(ref exprs) => { self.print_expr_tup(exprs); @@ -2344,8 +2345,12 @@ impl<'a> State<'a> { self.print_pat(p); } } - PatKind::TupleStruct(ref path, ref elts) => { - self.print_path(path, true, 0); + PatKind::TupleStruct(ref qself, ref path, ref elts) => { + if let Some(qself) = qself { + self.print_qpath(path, qself, true); + } else { + self.print_path(path, true, 0); + } self.popen(); self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.pclose(); @@ -2359,8 +2364,12 @@ impl<'a> State<'a> { PatKind::Path(Some(ref qself), ref path) => { self.print_qpath(path, qself, false); } - PatKind::Struct(ref path, ref fields, etc) => { - self.print_path(path, true, 0); + PatKind::Struct(ref qself, ref path, ref fields, etc) => { + if let Some(qself) = qself { + self.print_qpath(path, qself, true); + } else { + self.print_path(path, true, 0); + } self.nbsp(); self.word_space("{"); self.commasep_cmnt( diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index ab68d24e4b3..3fb11f77872 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,8 +4,6 @@ //! 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; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 17b7793c7dd..2393e0b9ebf 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,7 +9,6 @@ #![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"] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e845f9ec55a..99544ddb66e 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -254,6 +254,10 @@ pub fn expand_test_or_bench( "allow_fail", cx.expr_bool(sp, should_fail(&cx.sess, &item)), ), + // compile_fail: true | false + field("compile_fail", cx.expr_bool(sp, false)), + // no_run: true | false + field("no_run", cx.expr_bool(sp, false)), // should_panic: ... field( "should_panic", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index e6792def567..a6f5925149b 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -26,12 +26,6 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -39,18 +33,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[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", @@ -60,13 +53,12 @@ dependencies = [ "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", @@ -74,18 +66,18 @@ dependencies = [ [[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", @@ -95,15 +87,14 @@ dependencies = [ [[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", @@ -113,20 +104,19 @@ dependencies = [ [[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", @@ -134,8 +124,8 @@ dependencies = [ [[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", @@ -155,37 +145,10 @@ dependencies = [ ] [[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", ] @@ -242,33 +205,15 @@ dependencies = [ [[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" @@ -323,49 +268,12 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 2789207c655..fd149af4547 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -9,15 +9,15 @@ crate-type = ["dylib"] [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" @@ -25,11 +25,11 @@ libloading = { version = "0.6.0", optional = true } 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" } @@ -70,13 +70,5 @@ debug = false 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 diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index e058a972ead..923deb9aec4 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[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" @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.40" +version = "0.1.43" dependencies = [ "rustc-std-workspace-core", ] @@ -132,9 +132,9 @@ dependencies = [ [[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", ] @@ -195,9 +195,9 @@ dependencies = [ [[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", diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index f7fcef10774..54b7a94750c 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -32,7 +32,7 @@ popd 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 diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch index 7daea99f579..7daea99f579 100644 --- a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch deleted file mode 100644 index b4acc4f5b73..00000000000 --- a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch +++ /dev/null @@ -1,35 +0,0 @@ -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 - diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 77ba72df8ef..7d608df9253 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -187,20 +187,6 @@ unsafe fn test_mm_slli_si128() { ); 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")] @@ -295,7 +281,7 @@ unsafe fn test_mm_extract_epi8() { 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); } diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch index 8cfffe580a1..ba0eaacd828 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch @@ -39,46 +39,6 @@ index a35897e..f0bf645 100644 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 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 5442e3345aa..9fe6e093a7b 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-04-28" +channel = "nightly-2021-05-26" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 4821a07ac5d..43c4887669c 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -24,18 +24,6 @@ index 5bd1147cad5..10d68a2ff14 100644 + [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 @@ -44,11 +32,12 @@ index d95b5b7f17f..00b6f0e3635 100644 [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 diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index 3afcea8f06b..0d99d2c507c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -116,6 +116,7 @@ function extended_sysroot_tests() { 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 diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index fc0823302e0..22897c43e7e 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -160,7 +160,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { }; 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(), @@ -254,6 +254,15 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } } } + + fn inject_dll_import_lib( + &mut self, + _lib_name: &str, + _dll_imports: &[rustc_middle::middle::cstore::DllImport], + _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir, + ) { + bug!("injecting dll imports is not supported"); + } } impl<'a> ArArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 3ec5c14ff17..ec3e17e5b75 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -110,11 +110,6 @@ pub(crate) fn codegen_fn<'tcx>( // 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(); @@ -125,10 +120,14 @@ pub(crate) fn codegen_fn<'tcx>( // 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() @@ -870,7 +869,7 @@ pub(crate) fn codegen_operand<'tcx>( 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]; diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index c12d6d0f141..488ff6e1349 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -347,19 +347,10 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { 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); diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs index e59a0cb0a23..eef3c8c8d6e 100644 --- a/compiler/rustc_codegen_cranelift/src/config.rs +++ b/compiler/rustc_codegen_cranelift/src/config.rs @@ -48,6 +48,12 @@ pub struct BackendConfig { /// 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. /// @@ -74,6 +80,8 @@ impl Default for BackendConfig { 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"), } @@ -93,6 +101,7 @@ impl BackendConfig { 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)), diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c0f2920652f..3ba12c4e96d 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -2,11 +2,13 @@ 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; @@ -175,6 +177,7 @@ pub(crate) fn codegen_const_value<'tcx>( 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); @@ -373,8 +376,19 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant 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(); @@ -436,12 +450,89 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( 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 + } } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 24d933728db..6676d88602c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -73,9 +73,8 @@ fn reuse_workproduct_for_cgu( 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) { @@ -145,7 +144,13 @@ fn module_codegen( } } } - 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; @@ -172,21 +177,6 @@ pub(crate) fn run_aot( metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> { - use rustc_span::symbol::sym; - - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != sym::windows && subsystem != sym::console { - tcx.sess.fatal(&format!( - "invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem - )); - } - subsystem.to_string() - }); - let mut work_products = FxHashMap::default(); let cgus = if tcx.sess.opts.output_types.should_codegen() { @@ -275,9 +265,8 @@ pub(crate) fn run_aot( .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); @@ -303,12 +292,10 @@ pub(crate) fn run_aot( Box::new(( CodegenResults { - crate_name: tcx.crate_name(LOCAL_CRATE), modules, allocator_module, metadata_module, metadata, - windows_subsystem, linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()), crate_info: CrateInfo::new(tcx), }, @@ -352,8 +339,7 @@ fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) { .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"); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 632e86da736..4a99cb727c8 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -45,6 +45,7 @@ fn create_jit_module<'tcx>( &mut jit_module, &mut cx.unwind_context, true, + true, ); (jit_module, cx) @@ -206,7 +207,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { 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() { diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 4ab4c2957ca..09c5e6031c7 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -24,14 +24,22 @@ pub(crate) fn codegen_inline_asm<'tcx>( 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)); @@ -42,10 +50,14 @@ pub(crate) fn codegen_inline_asm<'tcx>( } _ => 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!(), diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs index 9de12e759bc..d02dfd93c3e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs @@ -12,6 +12,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>( ) -> (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(); @@ -25,6 +26,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>( 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); @@ -43,6 +45,11 @@ pub(crate) fn codegen_cpuid_call<'tcx>( 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); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 435737f3a51..52896fc7127 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -8,8 +8,8 @@ mod simd; 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; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index ff6e1856059..6aadaf8a7ca 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -14,6 +14,7 @@ extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; +extern crate rustc_metadata; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -28,8 +29,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_errors::ErrorReported; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader}; -use rustc_middle::ty::query::Providers; +use rustc_middle::middle::cstore::EncodedMetadata; use rustc_session::config::OutputFilenames; use rustc_session::Session; @@ -164,17 +164,14 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> { - Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader) - } - - fn provide(&self, _providers: &mut Providers) {} - fn provide_extern(&self, _providers: &mut Providers) {} - fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> { vec![] } + fn print_version(&self) { + println!("Cranelift version: {}", cranelift_codegen::VERSION); + } + fn codegen_crate( &self, tcx: TyCtxt<'_>, @@ -222,7 +219,7 @@ impl CodegenBackend for CraneliftCodegenBackend { sess, &codegen_results, outputs, - &codegen_results.crate_name.as_str(), + &codegen_results.crate_info.local_crate_name.as_str(), ); Ok(()) @@ -256,6 +253,8 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar 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 => { @@ -277,21 +276,23 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar 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) } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index d1958c5f96b..8fd1e4f5811 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -14,6 +14,7 @@ pub(crate) fn maybe_create_entry_wrapper( 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)) => ( @@ -26,8 +27,12 @@ pub(crate) fn maybe_create_entry_wrapper( 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; } diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index ab238244d68..db24bf65eb5 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -10,7 +10,7 @@ pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) use std::io::Write; let metadata = tcx.encode_metadata(); - let mut compressed = tcx.metadata_encoding_version(); + let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); object.add_rustc_section( diff --git a/compiler/rustc_codegen_cranelift/src/toolchain.rs b/compiler/rustc_codegen_cranelift/src/toolchain.rs index 484a9b699a0..f86236ef3ea 100644 --- a/compiler/rustc_codegen_cranelift/src/toolchain.rs +++ b/compiler/rustc_codegen_cranelift/src/toolchain.rs @@ -2,9 +2,8 @@ use std::path::PathBuf; -use rustc_middle::bug; +use rustc_codegen_ssa::back::link::linker_and_flavor; use rustc_session::Session; -use rustc_target::spec::LinkerFlavor; /// Tries to infer the path of a binary for the target toolchain from the linker name. pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf { @@ -30,89 +29,3 @@ pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf { linker } - -// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931 -fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { - fn infer_from( - sess: &Session, - linker: Option<PathBuf>, - flavor: Option<LinkerFlavor>, - ) -> Option<(PathBuf, LinkerFlavor)> { - match (linker, flavor) { - (Some(linker), Some(flavor)) => Some((linker, flavor)), - // only the linker flavor is known; use the default linker for the selected flavor - (None, Some(flavor)) => Some(( - PathBuf::from(match flavor { - LinkerFlavor::Em => { - if cfg!(windows) { - "emcc.bat" - } else { - "emcc" - } - } - LinkerFlavor::Gcc => { - if cfg!(any(target_os = "solaris", target_os = "illumos")) { - // On historical Solaris systems, "cc" may have - // been Sun Studio, which is not flag-compatible - // with "gcc". This history casts a long shadow, - // and many modern illumos distributions today - // ship GCC as "gcc" without also making it - // available as "cc". - "gcc" - } else { - "cc" - } - } - LinkerFlavor::Ld => "ld", - LinkerFlavor::Msvc => "link.exe", - LinkerFlavor::Lld(_) => "lld", - LinkerFlavor::PtxLinker => "rust-ptx-linker", - }), - flavor, - )), - (Some(linker), None) => { - let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| { - sess.fatal("couldn't extract file stem from specified linker") - }); - - let flavor = if stem == "emcc" { - LinkerFlavor::Em - } else if stem == "gcc" - || stem.ends_with("-gcc") - || stem == "clang" - || stem.ends_with("-clang") - { - LinkerFlavor::Gcc - } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") { - LinkerFlavor::Ld - } else if stem == "link" || stem == "lld-link" { - LinkerFlavor::Msvc - } else if stem == "lld" || stem == "rust-lld" { - LinkerFlavor::Lld(sess.target.lld_flavor) - } else { - // fall back to the value in the target spec - sess.target.linker_flavor - }; - - Some((linker, flavor)) - } - (None, None) => None, - } - } - - // linker and linker flavor specified via command line have precedence over what the target - // specification specifies - if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) { - return ret; - } - - if let Some(ret) = infer_from( - sess, - sess.target.linker.clone().map(PathBuf::from), - Some(sess.target.linker_flavor), - ) { - return ret; - } - - bug!("Not enough information provided to determine how to invoke the linker"); -} diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 819c8b51558..21d3e68dbc7 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -21,7 +21,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { } 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]); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 9a572c3501f..171f39805f8 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -561,6 +561,7 @@ impl<'tcx> CPlace<'tcx> { dst_align, src_align, true, + MemFlags::trusted(), ); } CValueInner::ByRef(_, Some(_)) => todo!(), diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 4999cb3c7ab..d0eb6913acc 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -27,6 +27,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } rustc_llvm = { path = "../rustc_llvm" } +rustc_metadata = { path = "../rustc_metadata" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 0aef77129d8..ecf62ed213d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -288,6 +288,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::SpirV => {} InlineAsmArch::Wasm32 => {} + InlineAsmArch::Bpf => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -593,6 +594,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk", InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -661,6 +664,7 @@ fn modifier_to_llvm( }, InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None, + InlineAsmRegClass::Bpf(_) => None, InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } @@ -708,6 +712,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(), + InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(), InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { bug!("LLVM backend does not support SPIR-V") } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 261affe2c42..64416bced31 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -8,9 +8,11 @@ use std::ptr; use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind}; +use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_middle::middle::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -61,6 +63,17 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> } } +/// Map machine type strings to values of LLVM's MachineTypes enum. +fn llvm_machine_type(cpu: &str) -> LLVMMachineType { + match cpu { + "x86_64" => LLVMMachineType::AMD64, + "x86" => LLVMMachineType::I386, + "aarch64" => LLVMMachineType::ARM64, + "arm" => LLVMMachineType::ARM, + _ => panic!("unsupported cpu type {}", cpu), + } +} + impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Creates a new static archive, ready for modifying the archive specified /// by `config`. @@ -175,6 +188,74 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { self.config.sess.fatal(&format!("failed to build archive: {}", e)); } } + + fn inject_dll_import_lib( + &mut self, + lib_name: &str, + dll_imports: &[DllImport], + tmpdir: &MaybeTempDir, + ) { + let output_path = { + let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf(); + output_path.push(format!("{}_imports", lib_name)); + output_path.with_extension("lib") + }; + + // we've checked for \0 characters in the library name already + let dll_name_z = CString::new(lib_name).unwrap(); + // All import names are Rust identifiers and therefore cannot contain \0 characters. + // FIXME: when support for #[link_name] implemented, ensure that import.name values don't + // have any \0 characters + let import_name_vector: Vec<CString> = dll_imports + .iter() + .map(if self.config.sess.target.arch == "x86" { + |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap() + } else { + |import: &DllImport| CString::new(import.name.to_string()).unwrap() + }) + .collect(); + + let output_path_z = rustc_fs_util::path_to_c_string(&output_path); + + tracing::trace!("invoking LLVMRustWriteImportLibrary"); + tracing::trace!(" dll_name {:#?}", dll_name_z); + tracing::trace!(" output_path {}", output_path.display()); + tracing::trace!( + " import names: {}", + dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "), + ); + + let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector + .iter() + .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr())) + .collect(); + let result = unsafe { + crate::llvm::LLVMRustWriteImportLibrary( + dll_name_z.as_ptr(), + output_path_z.as_ptr(), + ffi_exports.as_ptr(), + ffi_exports.len(), + llvm_machine_type(&self.config.sess.target.arch) as u16, + !self.config.sess.target.is_like_msvc, + ) + }; + + if result == crate::llvm::LLVMRustResult::Failure { + self.config.sess.fatal(&format!( + "Error creating import library for {}: {}", + lib_name, + llvm::last_error().unwrap_or("unknown LLVM error".to_string()) + )); + } + + self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + self.config.sess.fatal(&format!( + "failed to add native library {}: {}", + output_path.display(), + e + )); + }); + } } impl<'a> LlvmArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index b296db64ee9..cc3cbea4def 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -63,7 +63,7 @@ pub fn write_compressed_metadata<'tcx>( let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }; let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); - let mut compressed = tcx.metadata_encoding_version(); + let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); let llmeta = common::bytes_in_context(metadata_llcx, &compressed); @@ -218,27 +218,3 @@ pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { 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, - } -} diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index bc9d99ed4a1..c8cf0116c64 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -69,6 +69,7 @@ impl abi::HasDataLayout for Builder<'_, '_, '_> { } impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { + #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.cx.tcx } @@ -81,6 +82,7 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { } impl HasTargetSpec for Builder<'_, '_, 'tcx> { + #[inline] fn target_spec(&self) -> &Target { &self.cx.target_spec() } @@ -98,6 +100,7 @@ impl abi::LayoutOf for Builder<'_, '_, 'tcx> { impl Deref for Builder<'_, 'll, 'tcx> { type Target = CodegenCx<'ll, 'tcx>; + #[inline] fn deref(&self) -> &Self::Target { self.cx } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index b26969a5012..bb16c90cd12 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -14,7 +14,6 @@ use tracing::debug; 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. @@ -181,7 +180,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value 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); } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 245842df1b0..e50d5506e22 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,7 +17,6 @@ use rustc_middle::mir::mono::MonoItem; 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 { @@ -283,8 +282,8 @@ impl CodegenCx<'ll, 'tcx> { } } - if self.tcx.sess.relocation_model() == RelocModel::Static { - unsafe { + unsafe { + if self.should_assume_dso_local(g, true) { llvm::LLVMRustSetDSOLocal(g, true); } } @@ -370,9 +369,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { 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); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f5c54b11c08..6aa952462fa 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -765,18 +765,21 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { } 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 } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0db6659f8e2..1e70664e64d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, '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, } @@ -1486,13 +1485,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { _ => 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 } => { @@ -1507,7 +1502,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, self.layout, variant_info, - NoTag, + None, self_metadata, self.span, ); @@ -1539,13 +1534,26 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .. } => { 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() @@ -1574,7 +1582,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: if fallback { - String::new() + format!("variant{}", i.as_u32()) } else { variant_info.variant_name() }, @@ -1599,77 +1607,135 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { 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() @@ -1681,7 +1747,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - OptimizedTag, + Some(NicheTag), self_metadata, self.span, ); @@ -1697,19 +1763,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { 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(), @@ -1771,14 +1825,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } -// 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)] @@ -1859,7 +1909,7 @@ fn describe_enum_variant( 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>) { @@ -1882,12 +1932,11 @@ fn describe_enum_variant( 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), @@ -1918,7 +1967,7 @@ fn describe_enum_variant( 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, @@ -2048,9 +2097,9 @@ fn prepare_enum_metadata( 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)) } }; @@ -2062,7 +2111,7 @@ fn prepare_enum_metadata( unsafe { llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + None, enum_name.as_ptr().cast(), enum_name.len(), file_metadata, @@ -2088,7 +2137,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: discriminant_type_metadata, - containing_scope, common_members: vec![], span, }), @@ -2241,7 +2289,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: None, - containing_scope, common_members: outer_fields, span, }), @@ -2437,7 +2484,7 @@ fn create_union_stub( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + Some(containing_scope), union_type_name.as_ptr().cast(), union_type_name.len(), unknown_file_metadata(cx), diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8eef06f018f..776cb2ee99b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -13,7 +13,6 @@ #![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}; @@ -30,8 +29,8 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ErrorReported, FatalError, Handler}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::middle::cstore::EncodedMetadata; +use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -249,13 +248,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_features(sess) } - fn metadata_loader(&self) -> Box<MetadataLoaderDyn> { - Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader) - } - - fn provide(&self, _providers: &mut ty::query::Providers) {} - fn provide_extern(&self, _providers: &mut ty::query::Providers) {} - fn codegen_crate<'tcx>( &self, tcx: TyCtxt<'tcx>, @@ -305,7 +297,7 @@ impl CodegenBackend for LlvmCodegenBackend { sess, &codegen_results, outputs, - &codegen_results.crate_name.as_str(), + &codegen_results.crate_info.local_crate_name.as_str(), ); Ok(()) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 966be4a53fd..91923251018 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -29,6 +29,31 @@ pub enum LLVMRustResult { Success, Failure, } + +// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp. +#[repr(C)] +pub struct LLVMRustCOFFShortExport { + pub name: *const c_char, +} + +impl LLVMRustCOFFShortExport { + pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport { + LLVMRustCOFFShortExport { name } + } +} + +/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h. +/// +/// We include only architectures supported on Windows. +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum LLVMMachineType { + AMD64 = 0x8664, + I386 = 0x14c, + ARM64 = 0xaa64, + ARM = 0x01c0, +} + // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? @@ -72,7 +97,7 @@ pub enum Linkage { // LLVMRustVisibility #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum Visibility { Default = 0, Hidden = 1, @@ -583,11 +608,6 @@ extern "C" { pub type PassManagerBuilder; } extern "C" { - pub type ObjectFile; -} -#[repr(C)] -pub struct SectionIterator<'a>(InvariantOpaque<'a>); -extern "C" { pub type Pass; } extern "C" { @@ -1035,6 +1055,7 @@ extern "C" { 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; @@ -1702,35 +1723,6 @@ extern "C" { 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. @@ -2037,7 +2029,7 @@ extern "C" { pub fn LLVMRustDIBuilderCreateUnionType( Builder: &DIBuilder<'a>, - Scope: &'a DIScope, + Scope: Option<&'a DIScope>, Name: *const c_char, NameLen: size_t, File: &'a DIFile, @@ -2236,12 +2228,6 @@ extern "C" { 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); pub fn LLVMContextSetDiagnosticHandler( @@ -2304,6 +2290,15 @@ extern "C" { ) -> &'a mut RustArchiveMember<'a>; pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>); + pub fn LLVMRustWriteImportLibrary( + ImportName: *const c_char, + Path: *const c_char, + Exports: *const LLVMRustCOFFShortExport, + NumExports: usize, + Machine: u16, + MinGW: bool, + ) -> LLVMRustResult; + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine); pub fn LLVMRustBuildOperandBundleDef( diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index bb9c6d47373..38d56f87211 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -150,50 +150,6 @@ impl Attribute { } } -// 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 { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 387062a671d..0dd3d2ae15b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,5 +1,5 @@ use crate::back::write::create_informational_target_machine; -use crate::llvm; +use crate::{llvm, llvm_util}; use libc::c_int; use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxHashSet; @@ -84,6 +84,17 @@ unsafe fn configure_llvm(sess: &Session) { if !sess.opts.debugging_opts.no_generate_arange_section { add("-generate-arange-section", false); } + + // FIXME(nagisa): disable the machine outliner by default in LLVM versions 11, where it was + // introduced and up. + // + // This should remain in place until https://reviews.llvm.org/D103167 is fixed. If LLVM + // has been upgraded since, consider adjusting the version check below to contain an upper + // bound. + if llvm_util::get_version() >= (11, 0, 0) { + add("-enable-machine-outliner=never", false); + } + match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index fc1f364e9c6..93456443aa0 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -37,7 +37,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { 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); } } @@ -85,7 +85,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { 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); } } @@ -95,28 +95,48 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } 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; } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 68f40d5f863..9bd5764f073 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -9,7 +9,7 @@ test = false [dependencies] bitflags = "1.2.1" -cc = "1.0.67" +cc = "1.0.68" itertools = "0.9" tracing = "0.1" libc = "0.2.50" @@ -24,7 +24,7 @@ rustc_middle = { path = "../rustc_middle" } 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" } @@ -35,6 +35,6 @@ rustc_target = { path = "../rustc_target" } 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"] diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c197d48d4ea..63f457bb979 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,3 +1,5 @@ +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_middle::middle::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -57,4 +59,11 @@ pub trait ArchiveBuilder<'a> { fn update_symbols(&mut self); fn build(self); + + fn inject_dll_import_lib( + &mut self, + lib_name: &str, + dll_imports: &[DllImport], + tmpdir: &MaybeTempDir, + ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e330b5e703b..6c9ec9e7b0d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,11 +1,11 @@ -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::temp_dir::MaybeTempDir; 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::{DllImport, LibSource}; use rustc_middle::middle::dependency_format::Linkage; -use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; +use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; @@ -14,6 +14,7 @@ use rustc_session::utils::NativeLibKind; /// 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}; @@ -28,8 +29,12 @@ use crate::{ }; 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::cmp::Ordering; use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; @@ -278,9 +283,9 @@ pub fn each_linked_rlib( /// 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)); @@ -339,6 +344,12 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } + for (raw_dylib_name, raw_dylib_imports) in + collate_raw_dylibs(&codegen_results.crate_info.used_libraries) + { + ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); + } + // After adding all files to the archive, we need to update the // symbol table of the archive. ab.update_symbols(); @@ -366,9 +377,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // 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 @@ -385,8 +398,188 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } } + return 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(), + }; - ab + 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() + } + } +} + +/// Extract all symbols defined in raw-dylib libraries, collated by library name. +/// +/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library, +/// then the CodegenResults value contains one NativeLib instance for each block. However, the +/// linker appears to expect only a single import library for each library used, so we need to +/// collate the symbols together by library name before generating the import libraries. +fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> { + let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default(); + + for lib in used_libraries { + if lib.kind == NativeLibKind::RawDylib { + let name = lib.name.unwrap_or_else(|| + bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier") + ); + let name = if matches!(lib.verbatim, Some(true)) { + name.to_string() + } else { + format!("{}.dll", name) + }; + dylib_table + .entry(name) + .or_default() + .extend(lib.dll_imports.iter().map(|import| import.name)); + } + } + + // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out + // what we should do if we have two DllImport values with the same name but different + // ordinals. + let mut result = dylib_table + .into_iter() + .map(|(lib_name, imported_names)| { + let mut names = imported_names + .iter() + .map(|name| DllImport { name: *name, ordinal: None }) + .collect::<Vec<_>>(); + names.sort_unstable_by(|a: &DllImport, b: &DllImport| { + match a.name.as_str().cmp(&b.name.as_str()) { + Ordering::Equal => a.ordinal.cmp(&b.ordinal), + x => x, + } + }); + (lib_name, names) + }) + .collect::<Vec<_>>(); + result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| { + a.0.cmp(&b.0) + }); + result } /// Create a static archive. @@ -714,14 +907,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( } } - fn escape_string(s: &[u8]) -> String { - str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { - let mut x = "Non-UTF-8 output: ".to_string(); - x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); - x - }) - } - match prog { Ok(prog) => { if !prog.status.success() { @@ -863,9 +1048,50 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // ... and otherwise we're processing a `*.dwp` packed dwarf file. SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename), } + + if sess.target.is_like_osx { + if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) { + strip_symbols_in_osx(sess, &out_filename, option); + } + } +} + +fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) { + let prog = Command::new("strip").arg(option).arg(out_filename).output(); + match prog { + Ok(prog) => { + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + sess.struct_warn(&format!( + "stripping debug info with `strip` failed: {}", + prog.status + )) + .note(&escape_string(&output)) + .emit(); + } + } + Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)), + } +} + +fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> { + match strip { + Strip::Debuginfo => Some("-S"), + Strip::Symbols => Some("-x"), + Strip::None => None, + } } -fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { +fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); + x + }) +} + +fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { // On macOS the runtimes are distributed as dylibs which should be linked to // both executables and dynamic shared objects. Everywhere else the runtimes // are currently distributed as static liraries which should be linked to @@ -954,7 +1180,8 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum)) } -fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { +// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use +pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { fn infer_from( sess: &Session, linker: Option<PathBuf>, @@ -989,6 +1216,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { LinkerFlavor::Msvc => "link.exe", LinkerFlavor::Lld(_) => "lld", LinkerFlavor::PtxLinker => "rust-ptx-linker", + LinkerFlavor::BpfLinker => "bpf-linker", }), flavor, )), @@ -1005,6 +1233,8 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { || stem.ends_with("-clang") { LinkerFlavor::Gcc + } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") { + LinkerFlavor::Lld(LldFlavor::Wasm) } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") { LinkerFlavor::Ld } else if stem == "link" || stem == "lld-link" { @@ -1484,55 +1714,6 @@ fn add_local_crate_metadata_objects( } } -/// Link native libraries corresponding to the current crate and all libraries corresponding to -/// all its dependency crates. -/// FIXME: Consider combining this with the functions above adding object files for the local crate. -fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>( - cmd: &mut dyn Linker, - sess: &'a Session, - crate_type: CrateType, - codegen_results: &CodegenResults, - tmpdir: &Path, -) { - // Take careful note of the ordering of the arguments we pass to the linker - // here. Linkers will assume that things on the left depend on things to the - // right. Things on the right cannot depend on things on the left. This is - // all formally implemented in terms of resolving symbols (libs on the right - // resolve unknown symbols of libs on the left, but not vice versa). - // - // For this reason, we have organized the arguments we pass to the linker as - // such: - // - // 1. The local object that LLVM just generated - // 2. Local native libraries - // 3. Upstream rust libraries - // 4. Upstream native libraries - // - // The rationale behind this ordering is that those items lower down in the - // list can't depend on items higher up in the list. For example nothing can - // depend on what we just generated (e.g., that'd be a circular dependency). - // Upstream rust libraries are not allowed to depend on our local native - // libraries as that would violate the structure of the DAG, in that - // scenario they are required to link to them as well in a shared fashion. - // - // Note that upstream rust libraries may contain native dependencies as - // well, but they also can't depend on what we just started to add to the - // link line. And finally upstream native libraries can't depend on anything - // in this DAG so far because they're only dylibs and dylibs can only depend - // on other dylibs (e.g., other native deps). - // - // If -Zlink-native-libraries=false is set, then the assumption is that an - // external build system already has the native dependencies defined, and it - // will provide them to the linker itself. - if sess.opts.debugging_opts.link_native_libraries { - add_local_native_libraries(cmd, sess, codegen_results); - } - add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir); - if sess.opts.debugging_opts.link_native_libraries { - add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); - } -} - /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { // The default library location, we need this to find the runtime. @@ -1567,36 +1748,27 @@ fn add_rpath_args( ) { // FIXME (#2397): At some point we want to rpath our guesses as to // where extern libraries might live, based on the - // addl_lib_search_paths + // add_lib_search_paths if sess.opts.cg.rpath { - let target_triple = sess.opts.target_triple.triple(); - let mut get_install_prefix_lib_path = || { - let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX"); - let tlib = rustc_target::target_rustlib_path(&sess.sysroot, target_triple).join("lib"); - let mut path = PathBuf::from(install_prefix); - path.push(&tlib); - - path - }; let mut rpath_config = RPathConfig { used_crates: &codegen_results.crate_info.used_crates_dynamic, out_filename: out_filename.to_path_buf(), has_rpath: sess.target.has_rpath, is_like_osx: sess.target.is_like_osx, linker_is_gnu: sess.target.linker_is_gnu, - get_install_prefix_lib_path: &mut get_install_prefix_lib_path, }; cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); } } /// Produce the linker command line containing linker path and arguments. -/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line -/// by the user without creating a custom target specification. -/// `OBJECT-FILES` specify whether the arguments can add object files. -/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user -/// or by the target spec can be inserted here. -/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not. +/// +/// When comments in the function say "order-(in)dependent" they mean order-dependence between +/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies +/// to specific libraries passed after it, and `-o` (output file, order-independent) applies +/// to the linking process as a whole. +/// Order-independent options may still override each other in order-dependent fashion, +/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`. fn linker_with_args<'a, B: ArchiveBuilder<'a>>( path: &Path, flavor: LinkerFlavor, @@ -1614,16 +1786,153 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor); let link_output_kind = link_output_kind(sess, crate_type); - // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT + // ------------ Early order-dependent options ------------ + + // If we're building something like a dynamic library then some platforms + // need to make sure that all symbols are exported correctly from the + // dynamic library. + // Must be passed before any libraries to prevent the symbols to export from being thrown away, + // at least on some platforms (e.g. windows-gnu). + cmd.export_symbols(tmpdir, crate_type); + + // Can be used for adding custom CRT objects or overriding order-dependent options above. + // FIXME: In practice built-in target specs use this for arbitrary order-independent options, + // introduce a target spec option for order-independent linker options and migrate built-in + // specs to it. add_pre_link_args(cmd, sess, flavor); - // NO-OPT-OUT, OBJECT-FILES-NO + // ------------ Object code and libraries, order-dependent ------------ + + // Pre-link CRT objects. + add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); + + // Sanitizer libraries. + add_sanitizer_libraries(sess, crate_type, cmd); + + // Object code from the current crate. + // Take careful note of the ordering of the arguments we pass to the linker + // here. Linkers will assume that things on the left depend on things to the + // right. Things on the right cannot depend on things on the left. This is + // all formally implemented in terms of resolving symbols (libs on the right + // resolve unknown symbols of libs on the left, but not vice versa). + // + // For this reason, we have organized the arguments we pass to the linker as + // such: + // + // 1. The local object that LLVM just generated + // 2. Local native libraries + // 3. Upstream rust libraries + // 4. Upstream native libraries + // + // The rationale behind this ordering is that those items lower down in the + // list can't depend on items higher up in the list. For example nothing can + // depend on what we just generated (e.g., that'd be a circular dependency). + // Upstream rust libraries are not supposed to depend on our local native + // libraries as that would violate the structure of the DAG, in that + // scenario they are required to link to them as well in a shared fashion. + // (The current implementation still doesn't prevent it though, see the FIXME below.) + // + // Note that upstream rust libraries may contain native dependencies as + // well, but they also can't depend on what we just started to add to the + // link line. And finally upstream native libraries can't depend on anything + // in this DAG so far because they can only depend on other native libraries + // and such dependencies are also required to be specified. + add_local_crate_regular_objects(cmd, codegen_results); + add_local_crate_metadata_objects(cmd, crate_type, codegen_results); + add_local_crate_allocator_objects(cmd, codegen_results); + + // Avoid linking to dynamic libraries unless they satisfy some undefined symbols + // at the point at which they are specified on the command line. + // Must be passed before any (dynamic) libraries to have effect on them. + // On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections` + // so it will ignore unreferenced ELF sections from relocatable objects. + // For that reason, we put this flag after metadata objects as they would otherwise be removed. + // FIXME: Support more fine-grained dead code removal on Solaris/illumos + // and move this option back to the top. + cmd.add_as_needed(); + + // FIXME: Move this below to other native libraries + // (or alternatively link all native libraries after their respective crates). + // This change is somewhat breaking in practice due to local static libraries being linked + // as whole-archive (#85144), so removing whole-archive may be a pre-requisite. + if sess.opts.debugging_opts.link_native_libraries { + add_local_native_libraries(cmd, sess, codegen_results); + } + + // Rust libraries. + add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir); + + // Native libraries linked with `#[link]` attributes at and `-l` command line options. + // If -Zlink-native-libraries=false is set, then the assumption is that an + // external build system already has the native dependencies defined, and it + // will provide them to the linker itself. + if sess.opts.debugging_opts.link_native_libraries { + add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); + } + + // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make + // command line shorter, reset it to default here before adding more libraries. + cmd.reset_per_library_state(); + + // FIXME: Built-in target specs occasionally use this for linking system libraries, + // eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)` + // and remove the option. + add_late_link_args(cmd, sess, flavor, crate_type, codegen_results); + + // ------------ Arbitrary order-independent options ------------ + + // Add order-independent options determined by rustc from its compiler options, + // target properties and source code. + add_order_independent_options( + cmd, + sess, + link_output_kind, + crt_objects_fallback, + flavor, + crate_type, + codegen_results, + out_filename, + tmpdir, + ); + + // Can be used for arbitrary order-independent options. + // In practice may also be occasionally used for linking native libraries. + // Passed after compiler-generated options to support manual overriding when necessary. + add_user_defined_link_args(cmd, sess); + + // ------------ Object code and libraries, order-dependent ------------ + + // Post-link CRT objects. + add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); + + // ------------ Late order-dependent options ------------ + + // Doesn't really make sense. + // FIXME: In practice built-in target specs use this for arbitrary order-independent options, + // introduce a target spec option for order-independent linker options, migrate built-in specs + // to it and remove the option. + add_post_link_args(cmd, sess, flavor); + + cmd.take_cmd() +} + +fn add_order_independent_options( + cmd: &mut dyn Linker, + sess: &Session, + link_output_kind: LinkOutputKind, + crt_objects_fallback: bool, + flavor: LinkerFlavor, + crate_type: CrateType, + codegen_results: &CodegenResults, + out_filename: &Path, + tmpdir: &Path, +) { + add_gcc_ld_path(cmd, sess, flavor); + add_apple_sdk(cmd, sess, flavor); - // NO-OPT-OUT add_link_script(cmd, sess, tmpdir, crate_type); - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER if sess.target.is_like_fuchsia && crate_type == CrateType::Executable { let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" @@ -1633,30 +1942,17 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); } - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER if sess.target.eh_frame_header { cmd.add_eh_frame_header(); } - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER // Make the binary compatible with data execution prevention schemes. cmd.add_no_exec(); - // NO-OPT-OUT, OBJECT-FILES-NO - // Avoid linking to dynamic libraries unless they satisfy some undefined symbols - // at the point at which they are specified on the command line. - // Must be passed before any dynamic libraries. - cmd.add_as_needed(); - - // NO-OPT-OUT, OBJECT-FILES-NO if crt_objects_fallback { cmd.no_crt_objects(); } - // NO-OPT-OUT, OBJECT-FILES-YES - add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); - - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER if sess.target.is_like_emscripten { cmd.arg("-s"); cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { @@ -1666,45 +1962,32 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( }); } - // OBJECT-FILES-YES, AUDIT-ORDER - link_sanitizers(sess, crate_type, cmd); + if flavor == LinkerFlavor::PtxLinker { + // Provide the linker with fallback to internal `target-cpu`. + cmd.arg("--fallback-arch"); + cmd.arg(&codegen_results.linker_info.target_cpu); + } else if flavor == LinkerFlavor::BpfLinker { + cmd.arg("--cpu"); + cmd.arg(&codegen_results.linker_info.target_cpu); + cmd.arg("--cpu-features"); + cmd.arg(match &sess.opts.cg.target_feature { + feat if !feat.is_empty() => feat, + _ => &sess.target.options.features, + }); + } - // OBJECT-FILES-NO, AUDIT-ORDER - // Linker plugins should be specified early in the list of arguments - // FIXME: How "early" exactly? cmd.linker_plugin_lto(); - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Order-dependent, at least relatively to other args adding searh directories. add_library_search_dirs(cmd, sess, crt_objects_fallback); - // OBJECT-FILES-YES - add_local_crate_regular_objects(cmd, codegen_results); - - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER cmd.output_filename(out_filename); - // OBJECT-FILES-NO, AUDIT-ORDER if crate_type == CrateType::Executable && sess.target.is_like_windows { - if let Some(ref s) = codegen_results.windows_subsystem { + if let Some(ref s) = codegen_results.crate_info.windows_subsystem { cmd.subsystem(s); } } - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // If we're building something like a dynamic library then some platforms - // need to make sure that all symbols are exported correctly from the - // dynamic library. - cmd.export_symbols(tmpdir, crate_type); - - // OBJECT-FILES-YES - add_local_crate_metadata_objects(cmd, crate_type, codegen_results); - - // OBJECT-FILES-YES - add_local_crate_allocator_objects(cmd, codegen_results); - - // OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Order dependent, applies to the following objects. Where should it be placed? // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.link_dead_code() { @@ -1712,65 +1995,31 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.gc_sections(keep_metadata); } - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER cmd.set_output_kind(link_output_kind, out_filename); - // OBJECT-FILES-NO, AUDIT-ORDER add_relro_args(cmd, sess); - // OBJECT-FILES-NO, AUDIT-ORDER // Pass optimization flags down to the linker. cmd.optimize(); - // OBJECT-FILES-NO, AUDIT-ORDER // Pass debuginfo and strip flags down to the linker. cmd.debuginfo(sess.opts.debugging_opts.strip); - // OBJECT-FILES-NO, AUDIT-ORDER // We want to prevent the compiler from accidentally leaking in any system libraries, // so by default we tell linkers not to link to any default libraries. if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries { cmd.no_default_libraries(); } - // OBJECT-FILES-YES - link_local_crate_native_libs_and_dependent_crate_libs::<B>( - cmd, - sess, - crate_type, - codegen_results, - tmpdir, - ); - - // OBJECT-FILES-NO, AUDIT-ORDER if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() { cmd.pgo_gen(); } - // OBJECT-FILES-NO, AUDIT-ORDER if sess.opts.cg.control_flow_guard != CFGuard::Disabled { cmd.control_flow_guard(); } - // OBJECT-FILES-NO, AUDIT-ORDER add_rpath_args(cmd, sess, codegen_results, out_filename); - - // OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT - add_user_defined_link_args(cmd, sess); - - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - cmd.finalize(); - - // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT - add_late_link_args(cmd, sess, flavor, crate_type, codegen_results); - - // NO-OPT-OUT, OBJECT-FILES-YES - add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); - - // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT - add_post_link_args(cmd, sess, flavor); - - cmd.take_cmd() } /// # Native library linking @@ -1805,13 +2054,14 @@ fn add_local_native_libraries( 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 } => { @@ -1963,11 +2213,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } // 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 @@ -1980,20 +2227,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'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, @@ -2005,6 +2241,24 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( 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. @@ -2016,10 +2270,9 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( 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; } @@ -2069,21 +2322,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( 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); }); } @@ -2144,9 +2383,6 @@ fn add_upstream_native_libraries( 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, @@ -2154,6 +2390,10 @@ fn add_upstream_native_libraries( 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 } => { @@ -2176,10 +2416,7 @@ fn add_upstream_native_libraries( // already included them when we included the rust library // previously NativeLibKind::Static { bundle: None | Some(true), .. } => {} - NativeLibKind::RawDylib => { - // FIXME(#58713): Proper handling for raw dylibs. - bug!("raw_dylib feature not yet implemented"); - } + NativeLibKind::RawDylib => {} } } } @@ -2293,3 +2530,30 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> { Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), } } + +fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld { + if let LinkerFlavor::Gcc = flavor { + match ld_impl { + LdImpl::Lld => { + let tools_path = + sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + let lld_path = tools_path + .into_iter() + .map(|p| p.join("gcc-ld")) + .find(|p| { + p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() + }) + .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); + cmd.cmd().arg({ + let mut arg = OsString::from("-B"); + arg.push(lld_path); + arg + }); + } + } + } else { + sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc"); + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4dc9a3f5e41..43ff664c3e6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -37,7 +37,7 @@ pub fn disable_localization(linker: &mut Command) { /// need out of the shared crate context before we get rid of it. #[derive(Encodable, Decodable)] pub struct LinkerInfo { - target_cpu: String, + pub(super) target_cpu: String, exports: FxHashMap<CrateType, Vec<String>>, } @@ -81,8 +81,10 @@ impl LinkerInfo { Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker> } - LinkerFlavor::PtxLinker => { - Box::new(PtxLinker { cmd, sess, info: self }) as Box<dyn Linker> + LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>, + + LinkerFlavor::BpfLinker => { + Box::new(BpfLinker { cmd, sess, info: self }) as Box<dyn Linker> } } } @@ -128,7 +130,7 @@ pub trait Linker { fn add_eh_frame_header(&mut self) {} fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} - fn finalize(&mut self); + fn reset_per_library_state(&mut self) {} } impl dyn Linker + '_ { @@ -472,7 +474,9 @@ impl<'a> Linker for GccLinker<'a> { // eliminate the metadata. If we're building an executable, however, // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. - } else if self.sess.target.linker_is_gnu && !keep_metadata { + } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm) + && !keep_metadata + { self.linker_arg("--gc-sections"); } } @@ -480,13 +484,13 @@ impl<'a> Linker for GccLinker<'a> { fn no_gc_sections(&mut self) { if self.sess.target.is_like_osx { self.linker_arg("-no_dead_strip"); - } else if self.sess.target.linker_is_gnu { + } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm { self.linker_arg("--no-gc-sections"); } } fn optimize(&mut self) { - if !self.sess.target.linker_is_gnu { + if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm { return; } @@ -522,15 +526,18 @@ impl<'a> Linker for GccLinker<'a> { fn control_flow_guard(&mut self) {} fn debuginfo(&mut self, strip: Strip) { + // MacOS linker doesn't support stripping symbols directly anymore. + if self.sess.target.is_like_osx { + return; + } + match strip { Strip::None => {} Strip::Debuginfo => { - // MacOS linker does not support longhand argument --strip-debug - self.linker_arg("-S"); + self.linker_arg("--strip-debug"); } Strip::Symbols => { - // MacOS linker does not support longhand argument --strip-all - self.linker_arg("-s"); + self.linker_arg("--strip-all"); } } } @@ -647,7 +654,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg(&subsystem); } - fn finalize(&mut self) { + fn reset_per_library_state(&mut self) { self.hint_dynamic(); // Reset to default before returning the composed command line. } @@ -931,8 +938,6 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn finalize(&mut self) {} - // MSVC doesn't need group indicators fn group_start(&mut self) {} fn group_end(&mut self) {} @@ -1093,8 +1098,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - fn finalize(&mut self) {} - // Appears not necessary on Emscripten fn group_start(&mut self) {} fn group_end(&mut self) {} @@ -1275,8 +1278,6 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn finalize(&mut self) {} - // Not needed for now with LLD fn group_start(&mut self) {} fn group_end(&mut self) {} @@ -1330,7 +1331,6 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { pub struct PtxLinker<'a> { cmd: Command, sess: &'a Session, - info: &'a LinkerInfo, } impl<'a> Linker for PtxLinker<'a> { @@ -1374,9 +1374,105 @@ impl<'a> Linker for PtxLinker<'a> { self.cmd.arg("-o").arg(path); } - fn finalize(&mut self) { - // Provide the linker with fallback to internal `target-cpu`. - self.cmd.arg("--fallback-arch").arg(&self.info.target_cpu); + fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { + panic!("external dylibs not supported") + } + + fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { + panic!("external dylibs not supported") + } + + fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { + panic!("staticlibs not supported") + } + + fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { + panic!("staticlibs not supported") + } + + fn framework_path(&mut self, _path: &Path) { + panic!("frameworks not supported") + } + + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { + panic!("frameworks not supported") + } + + fn full_relro(&mut self) {} + + fn partial_relro(&mut self) {} + + fn no_relro(&mut self) {} + + fn gc_sections(&mut self, _keep_metadata: bool) {} + + fn no_gc_sections(&mut self) {} + + fn pgo_gen(&mut self) {} + + fn no_crt_objects(&mut self) {} + + fn no_default_libraries(&mut self) {} + + fn control_flow_guard(&mut self) {} + + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {} + + fn subsystem(&mut self, _subsystem: &str) {} + + fn group_start(&mut self) {} + + fn group_end(&mut self) {} + + fn linker_plugin_lto(&mut self) {} +} + +pub struct BpfLinker<'a> { + cmd: Command, + sess: &'a Session, + info: &'a LinkerInfo, +} + +impl<'a> Linker for BpfLinker<'a> { + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + + fn link_rlib(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn link_whole_rlib(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn debuginfo(&mut self, _strip: Strip) { + self.cmd.arg("--debug"); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn optimize(&mut self) { + self.cmd.arg(match self.sess.opts.optimize { + OptLevel::No => "-O0", + OptLevel::Less => "-O1", + OptLevel::Default => "-O2", + OptLevel::Aggressive => "-O3", + OptLevel::Size => "-Os", + OptLevel::SizeMin => "-Oz", + }); + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); } fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { @@ -1421,7 +1517,20 @@ impl<'a> Linker for PtxLinker<'a> { fn control_flow_guard(&mut self) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {} + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { + let path = tmpdir.join("symbols"); + let res: io::Result<()> = try { + let mut f = BufWriter::new(File::create(&path)?); + for sym in self.info.exports[&crate_type].iter() { + writeln!(f, "{}", sym)?; + } + }; + if let Err(e) = res { + self.sess.fatal(&format!("failed to write symbols file: {}", e)); + } else { + self.cmd.arg("--export-symbols").arg(&path); + } + } fn subsystem(&mut self, _subsystem: &str) {} diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 37d1f8ecc83..0fff3195808 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -3,6 +3,7 @@ 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; @@ -46,7 +47,10 @@ impl MetadataLoader for DefaultMetadataLoader { 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"); } } @@ -55,17 +59,27 @@ impl MetadataLoader for DefaultMetadataLoader { } 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)) +} diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 5f21046b05e..39b0ccd120d 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -13,7 +13,6 @@ pub struct RPathConfig<'a> { pub is_like_osx: bool, pub has_rpath: bool, pub linker_is_gnu: bool, - pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf, } pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> { @@ -63,24 +62,13 @@ fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> { // Use relative paths to the libraries. Binaries can be moved // as long as they maintain the relative relationship to the // crates they depend on. - let rel_rpaths = get_rpaths_relative_to_output(config, libs); + let rpaths = get_rpaths_relative_to_output(config, libs); - // And a final backup rpath to the global library location. - let fallback_rpaths = vec![get_install_prefix_rpath(config)]; - - fn log_rpaths(desc: &str, rpaths: &[String]) { - debug!("{} rpaths:", desc); - for rpath in rpaths { - debug!(" {}", *rpath); - } + debug!("rpaths:"); + for rpath in &rpaths { + debug!(" {}", rpath); } - log_rpaths("relative", &rel_rpaths); - log_rpaths("fallback", &fallback_rpaths); - - let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths); - // Remove duplicates minimize_rpaths(&rpaths) } @@ -113,13 +101,6 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> { diff_paths(path, base) } -fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String { - let path = (config.get_install_prefix_lib_path)(); - let path = env::current_dir().unwrap().join(&path); - // FIXME (#9639): This needs to handle non-utf8 paths - path.to_str().expect("non-utf8 component in rpath").to_owned() -} - fn minimize_rpaths(rpaths: &[String]) -> Vec<String> { let mut set = FxHashSet::default(); let mut minimized = Vec::new(); diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 35836ae719b..24c362db122 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -40,7 +40,6 @@ fn test_rpath_relative() { is_like_osx: true, linker_is_gnu: false, out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), }; let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); assert_eq!(res, "@loader_path/../lib"); @@ -48,7 +47,6 @@ fn test_rpath_relative() { let config = &mut RPathConfig { used_crates: &[], out_filename: PathBuf::from("bin/rustc"), - get_install_prefix_lib_path: &mut || panic!(), has_rpath: true, is_like_osx: false, linker_is_gnu: true, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 14d6f0ba147..b2ecc3b0f32 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -370,7 +370,6 @@ pub fn provide(providers: &mut Providers) { pub fn provide_extern(providers: &mut Providers) { providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; - providers.wasm_import_module_map = wasm_import_module_map; } fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 49774dc6d5c..ff4e6409571 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -31,7 +31,7 @@ use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType}; use rustc_session::config::{Passes, SwitchWithOptPath}; use rustc_session::Session; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet}; @@ -426,21 +426,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( let (coordinator_send, coordinator_receive) = channel(); let sess = tcx.sess; - let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins); let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins); - let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != sym::windows && subsystem != sym::console { - tcx.sess.fatal(&format!( - "invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem - )); - } - subsystem.to_string() - }); let linker_info = LinkerInfo::new(tcx, target_cpu); let crate_info = CrateInfo::new(tcx); @@ -472,9 +460,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( OngoingCodegen { backend, - crate_name, metadata, - windows_subsystem, linker_info, crate_info, @@ -1812,9 +1798,7 @@ impl SharedEmitterMain { pub struct OngoingCodegen<B: ExtraBackendMethods> { pub backend: B, - pub crate_name: Symbol, pub metadata: EncodedMetadata, - pub windows_subsystem: Option<String>, pub linker_info: LinkerInfo, pub crate_info: CrateInfo, pub coordinator_send: Sender<Box<dyn Any + Send>>, @@ -1857,9 +1841,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { ( CodegenResults { - crate_name: self.crate_name, metadata: self.metadata, - windows_subsystem: self.windows_subsystem, linker_info: self.linker_info, crate_info: self.crate_info, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b44e74d5ae8..38ab39febe0 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -30,6 +30,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; use rustc_session::Session; +use rustc_span::symbol::sym; use rustc_target::abi::{Align, LayoutOf, VariantIdx}; use std::ops::{Deref, DerefMut}; @@ -755,7 +756,22 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> { impl CrateInfo { pub fn new(tcx: TyCtxt<'_>) -> CrateInfo { + let local_crate_name = tcx.crate_name(LOCAL_CRATE); + let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != sym::windows && subsystem != sym::console { + tcx.sess.fatal(&format!( + "invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem + )); + } + subsystem.to_string() + }); + let mut info = CrateInfo { + local_crate_name, panic_runtime: None, compiler_builtins: None, profiler_runtime: None, @@ -769,6 +785,7 @@ impl CrateInfo { lang_item_to_crate: Default::default(), missing_lang_items: Default::default(), dependency_formats: tcx.dependency_formats(()), + windows_subsystem, }; let lang_items = tcx.lang_items(); diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index 08442c588f8..c1dfe1ef856 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -28,6 +28,7 @@ pub struct Expression { /// 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, @@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> { 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, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index d1bbf74307c..7b4b0821c4b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -3,7 +3,8 @@ 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; @@ -45,8 +46,12 @@ pub fn push_debuginfo_type_name<'tcx>( 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 { @@ -233,6 +238,54 @@ pub fn push_debuginfo_type_name<'tcx>( } } + /// 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()); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1b53b551901..b6de12fa35e 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,16 +1,11 @@ #![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 @@ -115,11 +110,18 @@ pub struct NativeLib { pub name: Option<Symbol>, pub cfg: Option<ast::MetaItem>, pub verbatim: Option<bool>, + pub dll_imports: Vec<cstore::DllImport>, } impl From<&cstore::NativeLib> for NativeLib { fn from(lib: &cstore::NativeLib) -> Self { - NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim } + NativeLib { + kind: lib.kind, + name: lib.name, + cfg: lib.cfg.clone(), + verbatim: lib.verbatim, + dll_imports: lib.dll_imports.clone(), + } } } @@ -133,6 +135,7 @@ impl From<&cstore::NativeLib> for NativeLib { /// and the corresponding properties without referencing information outside of a `CrateInfo`. #[derive(Debug, Encodable, Decodable)] pub struct CrateInfo { + pub local_crate_name: Symbol, pub panic_runtime: Option<CrateNum>, pub compiler_builtins: Option<CrateNum>, pub profiler_runtime: Option<CrateNum>, @@ -146,16 +149,15 @@ pub struct CrateInfo { pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>, pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>, pub dependency_formats: Lrc<Dependencies>, + pub windows_subsystem: Option<String>, } #[derive(Encodable, Decodable)] pub struct CodegenResults { - pub crate_name: Symbol, pub modules: Vec<CompiledModule>, pub allocator_module: Option<CompiledModule>, pub metadata_module: Option<CompiledModule>, pub metadata: rustc_middle::middle::cstore::EncodedMetadata, - pub windows_subsystem: Option<String>, pub linker_info: back::linker::LinkerInfo, pub crate_info: CrateInfo, } diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 38e928145a8..49b5e8466be 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -7,11 +7,8 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::traversal; -use rustc_middle::mir::visit::{ - MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor, -}; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, Location, TerminatorKind}; -use rustc_middle::ty; use rustc_middle::ty::layout::HasTyCtxt; use rustc_target::abi::LayoutOf; @@ -21,7 +18,12 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); - analyzer.visit_body(&mir); + // If there exists a local definition that dominates all uses of that local, + // the definition should be visited first. Traverse blocks in preorder which + // is a topological sort of dominance partial order. + for (bb, data) in traversal::preorder(&mir) { + analyzer.visit_basic_block_data(bb, data); + } for (local, decl) in mir.local_decls.iter_enumerated() { let ty = fx.monomorphize(decl.ty); @@ -142,36 +144,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { if let mir::ProjectionElem::Deref = elem { // Deref projections typically only read the pointer. - // (the exception being `VarDebugInfo` contexts, handled below) base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); - - // Indirect debuginfo requires going through memory, that only - // the debugger accesses, following our emitted DWARF pointer ops. - // - // FIXME(eddyb) Investigate the possibility of relaxing this, but - // note that `llvm.dbg.declare` *must* be used for indirect places, - // even if we start using `llvm.dbg.value` for all other cases, - // as we don't necessarily know when the value changes, but only - // where it lives in memory. - // - // It's possible `llvm.dbg.declare` could support starting from - // a pointer that doesn't point to an `alloca`, but this would - // only be useful if we know the pointer being `Deref`'d comes - // from an immutable place, and if `llvm.dbg.declare` calls - // must be at the very start of the function, then only function - // arguments could contain such pointers. - if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { - // We use `NonUseContext::VarDebugInfo` for the base, - // which might not force the base local to memory, - // so we have to do it manually. - self.visit_local(&place_ref.local, context, location); - } - } - - // `NonUseContext::VarDebugInfo` needs to flow all the - // way down to the base local (see `visit_local`). - if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) { - base_context = context; } self.process_place(&place_base, base_context, location); @@ -186,20 +159,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ); } } else { - // FIXME this is super_place code, is repeated here to avoid cloning place or changing - // visit_place API - let mut context = context; - - if !place_ref.projection.is_empty() { - context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - } - self.visit_local(&place_ref.local, context, location); - self.visit_projection(*place_ref, context, location); } } } @@ -228,34 +188,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> 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); diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 98d550d732f..c89d42ecc58 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -205,11 +205,13 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ]; const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ - ("simd128", Some(sym::wasm_target_feature)), + ("simd128", None), ("atomics", Some(sym::wasm_target_feature)), ("nontrapping-fptoint", Some(sym::wasm_target_feature)), ]; +const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -224,6 +226,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol .chain(MIPS_ALLOWED_FEATURES.iter()) .chain(RISCV_ALLOWED_FEATURES.iter()) .chain(WASM_ALLOWED_FEATURES.iter()) + .chain(BPF_ALLOWED_FEATURES.iter()) .cloned() } @@ -237,6 +240,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES, "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES, "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES, + "bpf" => BPF_ALLOWED_FEATURES, _ => &[], } } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index f28db2fe84b..dc4146ec7b5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -63,9 +63,16 @@ pub trait CodegenBackend { None } - fn metadata_loader(&self) -> Box<MetadataLoaderDyn>; - fn provide(&self, _providers: &mut Providers); - fn provide_extern(&self, _providers: &mut Providers); + /// The metadata loader used to load rlib and dylib metadata. + /// + /// Alternative codegen backends may want to use different rlib or dylib formats than the + /// default native static archives and dynamic libraries. + fn metadata_loader(&self) -> Box<MetadataLoaderDyn> { + Box::new(crate::back::metadata::DefaultMetadataLoader) + } + + fn provide(&self, _providers: &mut Providers) {} + fn provide_extern(&self, _providers: &mut Providers) {} fn codegen_crate<'tcx>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index aa95ecbdaf9..c35a164bb33 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -34,7 +34,7 @@ tempfile = "3.2" 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" diff --git a/compiler/rustc_data_structures/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs deleted file mode 100644 index eb6f4e8213e..00000000000 --- a/compiler/rustc_data_structures/src/box_region.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! This module provides a way to deal with self-referential data. -//! -//! The main idea is to allocate such data in a generator frame and then -//! give access to it by executing user-provided closures inside that generator. -//! The module provides a safe abstraction for the latter task. -//! -//! The interface consists of two exported macros meant to be used together: -//! * `declare_box_region_type` wraps a generator inside a struct with `access` -//! method which accepts closures. -//! * `box_region_allow_access` is a helper which should be called inside -//! a generator to actually execute those closures. - -use std::marker::PhantomData; -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -#[derive(Copy, Clone)] -pub struct AccessAction(*mut dyn FnMut()); - -impl AccessAction { - pub fn get(self) -> *mut dyn FnMut() { - self.0 - } -} - -#[derive(Copy, Clone)] -pub enum Action { - Initial, - Access(AccessAction), - Complete, -} - -pub struct PinnedGenerator<I, A, R> { - generator: Pin<Box<dyn Generator<Action, Yield = YieldType<I, A>, Return = R>>>, -} - -impl<I, A, R> PinnedGenerator<I, A, R> { - pub fn new<T: Generator<Action, Yield = YieldType<I, A>, Return = R> + 'static>( - generator: T, - ) -> (I, Self) { - let mut result = PinnedGenerator { generator: Box::pin(generator) }; - - // Run it to the first yield to set it up - let init = match Pin::new(&mut result.generator).resume(Action::Initial) { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - (init, result) - } - - pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { - // Call the generator, which in turn will call the closure - if let GeneratorState::Complete(_) = - Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure))) - { - panic!() - } - } - - pub fn complete(&mut self) -> R { - // Tell the generator we want it to complete, consuming it and yielding a result - let result = Pin::new(&mut self.generator).resume(Action::Complete); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } -} - -#[derive(PartialEq)] -pub struct Marker<T>(PhantomData<T>); - -impl<T> Marker<T> { - pub unsafe fn new() -> Self { - Marker(PhantomData) - } -} - -pub enum YieldType<I, A> { - Initial(I), - Accessor(Marker<A>), -} - -#[macro_export] -#[allow_internal_unstable(fn_traits)] -macro_rules! declare_box_region_type { - (impl $v:vis - $name: ident, - $yield_type:ty, - for($($lifetimes:tt)*), - ($($args:ty),*) -> ($reti:ty, $retc:ty) - ) => { - $v struct $name($crate::box_region::PinnedGenerator< - $reti, - for<$($lifetimes)*> fn(($($args,)*)), - $retc - >); - - impl $name { - fn new<T: ::std::ops::Generator<$crate::box_region::Action, Yield = $yield_type, Return = $retc> + 'static>( - generator: T - ) -> ($reti, Self) { - let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); - (initial, $name(pinned)) - } - - $v fn access<F: for<$($lifetimes)*> FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R { - // Turn the FnOnce closure into *mut dyn FnMut() - // so we can pass it in to the generator - let mut r = None; - let mut f = Some(f); - let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) = - &mut |args| { - let f = f.take().unwrap(); - r = Some(FnOnce::call_once(f, args)); - }; - let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*)); - - // Get the generator to call our closure - unsafe { - self.0.access(::std::mem::transmute(mut_f)); - } - - // Unwrap the result - r.unwrap() - } - - $v fn complete(mut self) -> $retc { - self.0.complete() - } - - fn initial_yield(value: $reti) -> $yield_type { - $crate::box_region::YieldType::Initial(value) - } - } - }; - - ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { - declare_box_region_type!( - impl $v $name, - $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>, - for($($lifetimes)*), - ($($args),*) -> ($reti, $retc) - ); - }; -} - -#[macro_export] -#[allow_internal_unstable(fn_traits)] -macro_rules! box_region_allow_access { - (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*), $action:ident) => { - loop { - match $action { - $crate::box_region::Action::Access(accessor) => { - let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe { - ::std::mem::transmute(accessor.get()) - }; - (*accessor)(($($exprs),*)); - unsafe { - let marker = $crate::box_region::Marker::< - for<$($lifetimes)*> fn(($($args,)*)) - >::new(); - $action = yield $crate::box_region::YieldType::Accessor(marker); - }; - } - $crate::box_region::Action::Complete => break, - $crate::box_region::Action::Initial => panic!("unexpected box_region action: Initial"), - } - } - } -} diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 9383be474fd..4f5d8d7ea48 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -54,6 +54,10 @@ cfg_if! { 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 @@ -103,6 +107,10 @@ cfg_if! { 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 { @@ -122,6 +130,7 @@ cfg_if! { 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}; @@ -194,6 +203,10 @@ cfg_if! { 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 diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index adbb98fa750..16151e9dca5 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,15 +10,11 @@ #![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)] @@ -66,7 +62,6 @@ macro_rules! unlikely { pub mod base_n; pub mod binary_search_util; -pub mod box_region; pub mod captures; pub mod flock; pub mod functor; @@ -99,6 +94,7 @@ pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; pub mod vec_linked_list; +pub mod vec_map; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 29d685ab530..05b1a85381f 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -342,7 +342,7 @@ impl<O: ForestObligation> ObligationForest<O> { return Ok(()); } - match self.active_cache.entry(cache_key.clone()) { + match self.active_cache.entry(cache_key) { Entry::Occupied(o) => { let node = &mut self.nodes[*o.get()]; if let Some(parent_index) = parent { @@ -366,8 +366,7 @@ impl<O: ForestObligation> ObligationForest<O> { && self .error_cache .get(&obligation_tree_id) - .map(|errors| errors.contains(&cache_key)) - .unwrap_or(false); + .map_or(false, |errors| errors.contains(v.key())); if already_failed { Err(()) @@ -597,7 +596,7 @@ impl<O: ForestObligation> ObligationForest<O> { Some(rpos) => { // Cycle detected. processor.process_backedge( - stack[rpos..].iter().map(GetObligation(&self.nodes)), + stack[rpos..].iter().map(|&i| &self.nodes[i].obligation), PhantomData, ); } @@ -705,20 +704,3 @@ impl<O: ForestObligation> ObligationForest<O> { }); } } - -// 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 - } -} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index ff28784a1dc..18b352cf3b0 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -550,35 +550,3 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>( 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); - } -} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 26706cd2b1b..722ce6b6367 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,49 +43,9 @@ cfg_if! { 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)] @@ -159,22 +119,6 @@ cfg_if! { (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),*) => { @@ -318,8 +262,6 @@ cfg_if! { 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; diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index cd1e12ca450..324a8624dd0 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -90,9 +90,11 @@ pub unsafe trait Tag: Copy { 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) } @@ -104,9 +106,11 @@ unsafe impl<T> Pointer for Box<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) } @@ -118,9 +122,11 @@ unsafe impl<T> Pointer for Rc<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) } @@ -132,9 +138,11 @@ unsafe impl<T> Pointer for Arc<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) } @@ -145,9 +153,11 @@ unsafe impl<'a, T: 'a> Pointer for &'a 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) } diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs new file mode 100644 index 00000000000..73b04d3329c --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -0,0 +1,155 @@ +use std::borrow::Borrow; +use std::iter::FromIterator; +use std::slice::{Iter, IterMut}; +use std::vec::IntoIter; + +use crate::stable_hasher::{HashStable, StableHasher}; + +/// A map type implemented as a vector of pairs `K` (key) and `V` (value). +/// It currently provides a subset of all the map operations, the rest could be added as needed. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct VecMap<K, V>(Vec<(K, V)>); + +impl<K, V> VecMap<K, V> +where + K: PartialEq, +{ + pub fn new() -> Self { + VecMap(Default::default()) + } + + /// Sets the value of the entry, and returns the entry's old value. + pub fn insert(&mut self, k: K, v: V) -> Option<V> { + if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) { + Some(std::mem::replace(&mut elem.1, v)) + } else { + self.0.push((k, v)); + None + } + } + + /// Gets a reference to the value in the entry. + pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> + where + K: Borrow<Q>, + Q: Eq, + { + self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) + } + + /// Returns the value corresponding to the supplied predicate filter. + /// + /// The supplied predicate will be applied to each (key, value) pair and it will return a + /// reference to the values where the predicate returns `true`. + pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { + self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1) + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, + /// [`Eq`] on the borrowed form *must* match those for + /// the key type. + pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool + where + K: Borrow<Q>, + Q: Eq, + { + self.get(k).is_some() + } + + /// Returns `true` if the map contains no elements. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn iter(&self) -> Iter<'_, (K, V)> { + self.into_iter() + } + + pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> { + self.into_iter() + } +} + +impl<K, V> Default for VecMap<K, V> { + #[inline] + fn default() -> Self { + Self(Default::default()) + } +} + +impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> { + fn from(vec: Vec<(K, V)>) -> Self { + Self(vec) + } +} + +impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> { + fn into(self) -> Vec<(K, V)> { + self.0 + } +} + +impl<K, V> FromIterator<(K, V)> for VecMap<K, V> { + fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl<'a, K, V> IntoIterator for &'a VecMap<K, V> { + type Item = &'a (K, V); + type IntoIter = Iter<'a, (K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> { + type Item = &'a mut (K, V); + type IntoIter = IterMut<'a, (K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl<K, V> IntoIterator for VecMap<K, V> { + type Item = (K, V); + type IntoIter = IntoIter<(K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<K, V> Extend<(K, V)> for VecMap<K, V> { + fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { + self.0.extend(iter); + } + + fn extend_one(&mut self, item: (K, V)) { + self.0.extend_one(item); + } + + fn extend_reserve(&mut self, additional: usize) { + self.0.extend_reserve(additional); + } +} + +impl<K, V, CTX> HashStable<CTX> for VecMap<K, V> +where + K: HashStable<CTX> + Eq, + V: HashStable<CTX>, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.0.hash_stable(hcx, hasher) + } +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs new file mode 100644 index 00000000000..9083de85982 --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_map/tests.rs @@ -0,0 +1,48 @@ +use super::*; + +impl<K, V> VecMap<K, V> { + fn into_vec(self) -> Vec<(K, V)> { + self.0.into() + } +} + +#[test] +fn test_from_iterator() { + assert_eq!( + std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(), + Vec::<(i32, bool)>::new() + ); + assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]); + assert_eq!( + vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(), + vec![(1, true), (2, false)] + ); +} + +#[test] +fn test_into_iterator_owned() { + assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new()); + assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]); + assert_eq!( + VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(), + vec![(1, true), (2, false)] + ); +} + +#[test] +fn test_insert() { + let mut v = VecMap::new(); + assert_eq!(v.insert(1, true), None); + assert_eq!(v.insert(2, false), None); + assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]); + assert_eq!(v.insert(1, false), Some(true)); + assert_eq!(v.into_vec(), vec![(1, false), (2, false)]); +} + +#[test] +fn test_get() { + let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>(); + assert_eq!(v.get(&1), Some(&true)); + assert_eq!(v.get(&2), Some(&false)); + assert_eq!(v.get(&3), None); +} diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index c9b36dd0c24..b943977e4c2 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -21,7 +21,7 @@ use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorReported, PResult}; use rustc_feature::find_gated_cfg; -use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend}; +use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; use rustc_metadata::locator; @@ -499,7 +499,7 @@ fn make_input( } } -// Whether to stop or continue compilation. +/// Whether to stop or continue compilation. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Compilation { Stop, @@ -765,9 +765,16 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(util::commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(util::release_str())); - if cfg!(feature = "llvm") { - get_builtin_codegen_backend(&None, "llvm")().print_version(); - } + + let debug_flags = matches.opt_strs("Z"); + let backend_name = debug_flags.iter().find_map(|x| { + if x.starts_with("codegen-backend=") { + Some(&x["codegen-backends=".len()..]) + } else { + None + } + }); + get_codegen_backend(&None, backend_name).print_version(); } } @@ -1039,8 +1046,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { } // Don't handle -W help here, because we might first load plugins. - let r = matches.opt_strs("Z"); - if r.iter().any(|x| *x == "help") { + let debug_flags = matches.opt_strs("Z"); + if debug_flags.iter().any(|x| *x == "help") { describe_debug_flags(); return None; } @@ -1060,9 +1067,14 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { } if cg_flags.iter().any(|x| *x == "passes=list") { - if cfg!(feature = "llvm") { - get_builtin_codegen_backend(&None, "llvm")().print_passes(); - } + let backend_name = debug_flags.iter().find_map(|x| { + if x.starts_with("codegen-backend=") { + Some(&x["codegen-backends=".len()..]) + } else { + None + } + }); + get_codegen_backend(&None, backend_name).print_passes(); return None; } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index c343809179b..f10efd83236 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -157,6 +157,7 @@ E0308: include_str!("./error_codes/E0308.md"), E0309: include_str!("./error_codes/E0309.md"), E0310: include_str!("./error_codes/E0310.md"), E0312: include_str!("./error_codes/E0312.md"), +E0316: include_str!("./error_codes/E0316.md"), E0317: include_str!("./error_codes/E0317.md"), E0321: include_str!("./error_codes/E0321.md"), E0322: include_str!("./error_codes/E0322.md"), @@ -553,9 +554,8 @@ E0783: include_str!("./error_codes/E0783.md"), E0311, // thing may not live long enough E0313, // lifetime of borrowed pointer outlives lifetime of captured // variable - E0314, // closure outlives stack frame - E0315, // cannot invoke closure outside of its lifetime - E0316, // nested quantification of lifetimes +// E0314, // closure outlives stack frame +// E0315, // cannot invoke closure outside of its lifetime // E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck // E0372, // coherence not object safe @@ -584,21 +584,21 @@ E0783: include_str!("./error_codes/E0783.md"), // E0470, removed // E0471, // constant evaluation error (in pattern) E0472, // llvm_asm! is unsupported on this target - E0473, // dereference of reference outside its lifetime - E0474, // captured variable `..` does not outlive the enclosing closure - E0475, // index of slice outside its lifetime +// E0473, // dereference of reference outside its lifetime +// E0474, // captured variable `..` does not outlive the enclosing closure +// E0475, // index of slice outside its lifetime E0476, // lifetime of the source pointer does not outlive lifetime bound... - E0479, // the type `..` (provided as the value of a type parameter) is... - E0480, // lifetime of method receiver does not outlive the method call - E0481, // lifetime of function argument does not outlive the function call +// E0479, // the type `..` (provided as the value of a type parameter) is... +// E0480, // lifetime of method receiver does not outlive the method call +// E0481, // lifetime of function argument does not outlive the function call E0482, // lifetime of return value does not outlive the function call - E0483, // lifetime of operand does not outlive the operation - E0484, // reference is not valid at the time of borrow - E0485, // automatically reference is not valid at the time of borrow - E0486, // type of expression contains references that are not valid during.. - E0487, // unsafe use of destructor: destructor might be called while... - E0488, // lifetime of variable does not enclose its declaration - E0489, // type/lifetime parameter not in scope here +// E0483, // lifetime of operand does not outlive the operation +// E0484, // reference is not valid at the time of borrow +// E0485, // automatically reference is not valid at the time of borrow +// E0486, // type of expression contains references that are not valid during.. +// E0487, // unsafe use of destructor: destructor might be called while... +// E0488, // lifetime of variable does not enclose its declaration +// E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long E0498, // malformed plugin attribute E0514, // metadata version mismatch diff --git a/compiler/rustc_error_codes/src/error_codes/E0316.md b/compiler/rustc_error_codes/src/error_codes/E0316.md new file mode 100644 index 00000000000..4368c321737 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0316.md @@ -0,0 +1,32 @@ +A `where` clause contains a nested quantification over lifetimes. + +Erroneous code example: + +```compile_fail,E0316 +trait Tr<'a, 'b> {} + +fn foo<T>(t: T) +where + for<'a> &'a T: for<'b> Tr<'a, 'b>, // error: nested quantification +{ +} +``` + +Rust syntax allows lifetime quantifications in two places within +`where` clauses: Quantifying over the trait bound only (as in +`Ty: for<'l> Trait<'l>`) and quantifying over the whole clause +(as in `for<'l> &'l Ty: Trait<'l>`). Using both in the same clause +leads to a nested lifetime quantification, which is not supported. + +The following example compiles, because the clause with the nested +quantification has been rewritten to use only one `for<>`: + +``` +trait Tr<'a, 'b> {} + +fn foo<T>(t: T) +where + for<'a, 'b> &'a T: Tr<'a, 'b>, // ok +{ +} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0493.md b/compiler/rustc_error_codes/src/error_codes/E0493.md index 0dcc3b62b4b..e891129efa0 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0493.md +++ b/compiler/rustc_error_codes/src/error_codes/E0493.md @@ -21,7 +21,7 @@ static FOO: Foo = Foo { field1: (DropType::A, DropType::A).1 }; // error! The problem here is that if the given type or one of its fields implements the `Drop` trait, this `Drop` implementation cannot be called within a const context since it may run arbitrary, non-const-checked code. To prevent this -issue, ensure all values with custom a custom `Drop` implementation escape the +issue, ensure all values with a custom `Drop` implementation escape the initializer. ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md index 2fe5ada257f..6b16a7d415a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0759.md +++ b/compiler/rustc_error_codes/src/error_codes/E0759.md @@ -16,13 +16,13 @@ fn bar(x: &i32) -> Box<dyn Debug> { // error! Add `'static` requirement to fix them: -```compile_fail,E0759 +``` # use std::fmt::Debug; -fn foo(x: &i32) -> impl Debug + 'static { // ok! +fn foo(x: &'static i32) -> impl Debug + 'static { // ok! x } -fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok! +fn bar(x: &'static i32) -> Box<dyn Debug + 'static> { // ok! Box::new(x) } ``` diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 5d175a3ade9..72395bd31ec 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -216,7 +216,7 @@ macro_rules! encode_fields { $( $enc.emit_struct_field( stringify!($name), - idx, + idx == 0, |enc| $name.encode(enc), )?; idx += 1; @@ -229,7 +229,7 @@ macro_rules! encode_fields { // Special-case encoder to skip tool_metadata if not set impl<E: Encoder> Encodable<E> for Diagnostic { fn encode(&self, s: &mut E) -> Result<(), E::Error> { - s.emit_struct("diagnostic", 7, |s| { + s.emit_struct(false, |s| { let mut idx = 0; idx = encode_fields!( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 65352f0bc6e..979f2d3b300 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -715,6 +715,7 @@ impl Handler { self.inner.borrow_mut().bug(msg) } + #[inline] pub fn err_count(&self) -> usize { self.inner.borrow().err_count() } @@ -924,6 +925,7 @@ impl HandlerInner { } } + #[inline] fn err_count(&self) -> usize { self.err_count + self.stashed_diagnostics.len() } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e1c218c6408..aab2741c852 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1068,11 +1068,11 @@ impl<'a> ExtCtxt<'a> { 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>, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index cb8b9398283..ef5b97a9469 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -275,7 +275,12 @@ impl<'a> ExtCtxt<'a> { ) -> P<ast::Expr> { self.expr( span, - ast::ExprKind::Struct(P(ast::StructExpr { path, fields, rest: ast::StructRest::None })), + ast::ExprKind::Struct(P(ast::StructExpr { + qself: None, + path, + fields, + rest: ast::StructRest::None, + })), ) } pub fn expr_struct_ident( @@ -405,7 +410,7 @@ impl<'a> ExtCtxt<'a> { path: ast::Path, subpats: Vec<P<ast::Pat>>, ) -> P<ast::Pat> { - self.pat(span, PatKind::TupleStruct(path, subpats)) + self.pat(span, PatKind::TupleStruct(None, path, subpats)) } pub fn pat_struct( &self, @@ -413,7 +418,7 @@ impl<'a> ExtCtxt<'a> { path: ast::Path, field_pats: Vec<ast::PatField>, ) -> P<ast::Pat> { - self.pat(span, PatKind::Struct(path, field_pats, false)) + self.pat(span, PatKind::Struct(None, path, field_pats, false)) } pub fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> { self.pat(span, PatKind::Tuple(pats)) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f5c6bb3db65..39c0447bd09 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -12,11 +12,11 @@ use rustc_ast::ptr::P; 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; @@ -28,15 +28,14 @@ use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; 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 { ( @@ -1524,139 +1523,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { 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); diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5fb85867501..efed41de23a 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,9 +1,8 @@ -#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] +#![feature(format_args_capture)] #![feature(iter_zip)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 1aed42a24e2..a7434d73abe 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -85,6 +85,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_span::symbol::Ident; use std::borrow::Cow; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::mem; @@ -615,7 +616,11 @@ fn inner_parse_loop<'root, 'tt>( /// Use the given sequence of token trees (`ms`) as a matcher. Match the token /// stream from the given `parser` against it and return the match. -pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult { +pub(super) fn parse_tt( + parser: &mut Cow<'_, Parser<'_>>, + ms: &[TokenTree], + macro_name: Ident, +) -> NamedParseResult { // A queue of possible matcher positions. We initialize it with the matcher position in which // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then // processes all of these possible matcher positions and produces possible next positions into @@ -711,7 +716,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na return Error( parser.token.span, format!( - "local ambiguity: multiple parsing options: {}", + "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}", match next_items.len() { 0 => format!("built-in NTs {}.", nts), 1 => format!("built-in NTs {} or 1 other option.", nts), diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 91d4a0f0d65..abad190b072 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -245,7 +245,7 @@ fn generic_extension<'cx>( // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut()); - match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { + match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt, name) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. @@ -338,7 +338,7 @@ fn generic_extension<'cx>( _ => continue, }; if let Success(_) = - parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt) + parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt, name) { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -432,7 +432,7 @@ pub fn compile_declarative_macro( ]; let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS); - let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) { + let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, def.ident) { Success(m) => m, Failure(token, msg) => { let s = parse_failure_msg(&token); @@ -467,6 +467,7 @@ pub fn compile_declarative_macro( &sess.parse_sess, def.id, features, + edition, ) .pop() .unwrap(); @@ -492,6 +493,7 @@ pub fn compile_declarative_macro( &sess.parse_sess, def.id, features, + edition, ) .pop() .unwrap(); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index aca02ef93f8..fb7479eafc8 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -9,7 +9,8 @@ use rustc_feature::Features; 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; @@ -32,6 +33,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ /// - `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 /// @@ -42,6 +44,7 @@ pub(super) fn parse( sess: &ParseSess, node_id: NodeId, features: &Features, + edition: Edition, ) -> Vec<TokenTree> { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -52,7 +55,7 @@ pub(super) fn parse( 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() { @@ -64,7 +67,19 @@ pub(super) fn parse( 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( || { @@ -117,6 +132,7 @@ pub(super) fn parse( /// - `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>, @@ -124,6 +140,7 @@ fn parse_tree( 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 { @@ -151,7 +168,7 @@ fn parse_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); @@ -204,7 +221,7 @@ fn parse_tree( span, Lrc::new(Delimited { delim, - tts: parse(tts, expect_matchers, sess, node_id, features), + tts: parse(tts, expect_matchers, sess, node_id, features, edition), }), ), } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index eef71e096a5..95504723e7b 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -283,6 +283,10 @@ declare_features! ( (accepted, non_ascii_idents, "1.53.0", Some(55467), None), /// Allows arbitrary expressions in key-value attributes at parse time. (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 diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2cef46a844a..56a320c8d3b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -250,6 +250,7 @@ declare_features! ( (active, f16c_target_feature, "1.36.0", Some(44839), None), (active, riscv_target_feature, "1.45.0", Some(44839), None), (active, ermsb_target_feature, "1.49.0", Some(44839), None), + (active, bpf_target_feature, "1.54.0", Some(44839), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates (target features) @@ -370,9 +371,6 @@ declare_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), @@ -472,9 +470,6 @@ declare_features! ( /// 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), @@ -644,9 +639,6 @@ declare_features! ( /// Allows trait bounds in `const fn`. (active, const_fn_trait_bound, "1.53.0", Some(57563), None), - /// Allows unsizing coercions in `const fn`. - (active, const_fn_unsize, "1.53.0", Some(64992), None), - /// Allows `async {}` expressions in const contexts. (active, const_async_blocks, "1.53.0", Some(85368), None), @@ -671,6 +663,9 @@ declare_features! ( /// Allows unnamed fields of struct and union type (active, unnamed_fields, "1.53.0", Some(49804), None), + /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. + (active, more_qualified_paths, "1.54.0", Some(80080), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -697,11 +692,6 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ 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, ]; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e7e128f8a9b..259a6328a22 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -569,10 +569,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ 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 = "...""#), ), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 138398825af..71c10eb6507 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -140,6 +140,10 @@ declare_features! ( (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 // ------------------------------------------------------------------------- diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 647d735fb86..753b8c85670 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -94,15 +94,6 @@ impl DefPathTable { .iter_enumerated() .map(move |(index, key)| (index, key, &self.def_path_hashes[index])) } - - pub fn all_def_path_hashes_and_def_ids( - &self, - krate: CrateNum, - ) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ { - self.def_path_hashes - .iter_enumerated() - .map(move |(index, hash)| (*hash, DefId { krate, index })) - } } /// The definition table containing node definitions. @@ -306,6 +297,7 @@ impl Definitions { self.table.index_to_key.len() } + #[inline] pub fn def_key(&self, id: LocalDefId) -> DefKey { self.table.def_key(id.local_def_index) } @@ -439,6 +431,14 @@ impl Definitions { pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ { self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k) } + + #[inline(always)] + pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> { + self.table + .def_path_hash_to_index + .get(&hash) + .map(|&local_def_index| LocalDefId { local_def_index }) + } } #[derive(Copy, Clone, PartialEq, Debug)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 91fd97a0d40..577d43b1c8e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,7 +1,7 @@ // 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; @@ -10,6 +10,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject 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; @@ -658,7 +659,9 @@ pub struct Crate<'hir> { /// 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]>, @@ -2485,6 +2488,7 @@ pub enum FnRetTy<'hir> { } impl FnRetTy<'_> { + #[inline] pub fn span(&self) -> Span { match *self { Self::DefaultReturn(span) => span, diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 71e997994de..ad2ecae9233 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -3,11 +3,10 @@ //! [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] diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 0232654aaa5..56060752833 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -5,7 +5,7 @@ use crate::hir::{ TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; -use rustc_span::def_id::{DefPathHash, LocalDefId}; +use rustc_span::def_id::DefPathHash; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro @@ -21,7 +21,6 @@ pub trait HashStableContext: fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F); - fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash; } impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId { @@ -29,7 +28,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { - let def_path_hash = hcx.local_def_path_hash(self.owner); + let def_path_hash = self.owner.to_stable_hash_key(hcx); (def_path_hash, self.local_id) } } @@ -39,7 +38,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - hcx.local_def_path_hash(self.def_id) + self.def_id.to_stable_hash_key(hcx) } } @@ -48,7 +47,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - hcx.local_def_path_hash(self.def_id) + self.def_id.to_stable_hash_key(hcx) } } @@ -57,7 +56,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId { #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - hcx.local_def_path_hash(self.def_id) + self.def_id.to_stable_hash_key(hcx) } } @@ -66,7 +65,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId #[inline] fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash { - hcx.local_def_path_hash(self.def_id) + self.def_id.to_stable_hash_key(hcx) } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fe02cc5de8c..2b932b7c953 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] use rustc_ast as ast; diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 049e5b8b722..85bf4dc176b 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_session = { path = "../rustc_session" } +rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index e7bd488af8e..9abd4eae914 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -1,6 +1,5 @@ -//! 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 @@ -30,7 +29,6 @@ use std::iter::FromIterator; 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 @@ -102,6 +100,12 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = 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]; /// Abstract data type (struct, enum, union) `DepNode`s. @@ -122,22 +126,12 @@ struct Assertion { 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; } @@ -147,11 +141,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { 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 @@ -169,37 +159,20 @@ pub struct DirtyCleanVisitor<'tcx> { 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() { @@ -211,21 +184,7 @@ impl DirtyCleanVisitor<'tcx> { 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 @@ -288,20 +247,7 @@ impl DirtyCleanVisitor<'tcx> { 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), @@ -434,35 +380,23 @@ impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> { } } -/// 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, @@ -483,21 +417,18 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { } } -// 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 @@ -506,17 +437,14 @@ impl FindAllAttrs<'_, 'tcx> { 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> { diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 30c6c408bc7..83e80b55dae 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -106,6 +106,7 @@ 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}; @@ -189,9 +190,9 @@ pub fn prepare_session_directory( sess: &Session, crate_name: &str, crate_disambiguator: CrateDisambiguator, -) { +) -> Result<(), ErrorReported> { if sess.opts.incremental.is_none() { - return; + return Ok(()); } let _timer = sess.timer("incr_comp_prepare_session_directory"); @@ -201,9 +202,7 @@ pub fn prepare_session_directory( // {incr-comp-dir}/{crate-name-and-disambiguator} let crate_dir = crate_path(sess, crate_name, crate_disambiguator); 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; @@ -217,7 +216,7 @@ pub fn prepare_session_directory( crate_dir.display(), err )); - return; + return Err(ErrorReported); } }; @@ -232,16 +231,11 @@ pub fn prepare_session_directory( // 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. @@ -257,7 +251,7 @@ pub fn prepare_session_directory( ); sess.init_incr_comp_session(session_dir, directory_lock, false); - return; + return Ok(()); }; debug!("attempting to copy data from source: {}", source_directory.display()); @@ -278,7 +272,7 @@ pub fn prepare_session_directory( } sess.init_incr_comp_session(session_dir, directory_lock, true); - return; + return Ok(()); } else { debug!("copying failed - trying next directory"); @@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { 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); @@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> { 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()); @@ -510,13 +507,36 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa ) { // 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) } } } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index bd3b5239f7b..8539cc69371 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,8 +1,7 @@ //! Code to save/load the dep-graph from files. 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; @@ -22,8 +21,8 @@ pub enum LoadResult<T> { 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); @@ -84,7 +83,7 @@ impl<T> MaybeAsync<T> { } } -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 { @@ -185,7 +184,7 @@ 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) } } } })) @@ -196,10 +195,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { /// If we are not in incremental compilation mode, returns `None`. /// Otherwise, tries to load the query result cache from disk, /// creating an empty cache if it could not be loaded. -pub fn load_query_result_cache<'a>( - sess: &'a Session, - def_path_table: &DefPathTable, -) -> Option<OnDiskCache<'a>> { +pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option<OnDiskCache<'a>> { if sess.opts.incremental.is_none() { return None; } @@ -212,7 +208,7 @@ pub fn load_query_result_cache<'a>( sess.is_nightly_build(), ) { LoadResult::Ok { data: (bytes, start_pos) } => { - Some(OnDiskCache::new(sess, bytes, start_pos, def_path_table)) + Some(OnDiskCache::new(sess, bytes, start_pos)) } _ => Some(OnDiskCache::new_empty(sess.source_map())), } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 1484088837a..a8455854ebb 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -1,6 +1,6 @@ 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; @@ -186,7 +186,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR 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() { @@ -229,6 +229,7 @@ pub fn build_dep_graph( } Some(DepGraph::new( + &sess.prof, prev_graph, prev_work_products, encoder, diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 4c73b7bf612..0093fa5e562 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,6 +1,5 @@ #![feature(allow_internal_unstable)] #![feature(bench_black_box)] -#![feature(const_panic)] #![feature(extend_one)] #![feature(iter_zip)] #![feature(unboxed_closures)] diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 1b1a59a254e..246fa28d986 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -65,7 +65,7 @@ impl Idx for u32 { /// `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 ---- @@ -184,7 +184,7 @@ macro_rules! newtype_index { } } - 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( @@ -204,6 +204,9 @@ macro_rules! newtype_index { } } + // 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 { diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b8ecc949588..c3c28d70081 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -660,7 +660,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { ) } - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + fn push_outlives( + &mut self, + sup: ty::Region<'tcx>, + sub: ty::Region<'tcx>, + _info: ty::VarianceDiagInfo<'tcx>, + ) { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 30214e94203..3a11b5a2144 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -371,9 +371,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { match dir { EqTo => self.equate(a_is_expected).relate(a_ty, b_ty), SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty), - SupertypeOf => { - self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty) - } + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, + ty::VarianceDiagInfo::default(), + a_ty, + b_ty, + ), }?; Ok(()) @@ -574,6 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -737,7 +741,12 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { if self.tcx().lazy_normalization() => { assert_eq!(promoted, None); - let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?; + let substs = self.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + substs, + substs, + )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), @@ -831,6 +840,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, _variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -965,7 +975,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { if self.tcx().lazy_normalization() => { assert_eq!(promoted, None); - let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?; + let substs = self.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + substs, + substs, + )?; Ok(self.tcx().mk_const(ty::Const { ty: c.ty, val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 45ba50bb634..0c93271a1ae 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -59,6 +59,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 680f6af63f2..e3a79fe2653 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -64,6 +64,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; +use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, @@ -524,7 +525,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } 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, @@ -1965,7 +1966,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) } FailureCode::Error0308(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) + let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); + if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) = + trace.values + { + // If a tuple of length one was expected and the found expression has + // parentheses around it, perhaps the user meant to write `(expr,)` to + // build a tuple (issue #86100) + match (expected.kind(), found.kind()) { + (ty::Tuple(_), ty::Tuple(_)) => {} + (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('(').and_then(|s| s.strip_suffix(')')) + { + err.span_suggestion( + span, + "use a trailing comma to create a tuple with one element", + format!("({},)", code), + Applicability::MaybeIncorrect, + ); + } + } + } + _ => {} + } + } + err } FailureCode::Error0644(failure_str) => { struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 02662043dba..60f02b84aa3 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -96,7 +97,7 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { // When higher-ranked types are involved, computing the LUB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance(ty::Variance::Invariant, a, b)?; + self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 4fa8f2f1a6a..a08323535c5 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -43,6 +43,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -96,7 +97,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { // When higher-ranked types are involved, computing the LUB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance(ty::Variance::Invariant, a, b)?; + self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 077d2cc20a2..20be06adfd0 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -55,6 +55,8 @@ where /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, + ambient_variance_info: ty::VarianceDiagInfo<'tcx>, + /// When we pass through a set of binders (e.g., when looking into /// a `fn` type), we push a new bound region scope onto here. This /// will contain the instantiated region for each region in those @@ -78,7 +80,12 @@ pub trait TypeRelatingDelegate<'tcx> { /// satisfied for the two types to be related. `sub` and `sup` may /// be regions from the type or new variables created through the /// delegate. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); + fn push_outlives( + &mut self, + sup: ty::Region<'tcx>, + sub: ty::Region<'tcx>, + info: ty::VarianceDiagInfo<'tcx>, + ); fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); @@ -138,7 +145,14 @@ where delegate: D, ambient_variance: ty::Variance, ) -> Self { - Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] } + Self { + infcx, + delegate, + ambient_variance, + ambient_variance_info: ty::VarianceDiagInfo::default(), + a_scopes: vec![], + b_scopes: vec![], + } } fn ambient_covariance(&self) -> bool { @@ -239,10 +253,15 @@ where /// Push a new outlives requirement into our output set of /// constraints. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + fn push_outlives( + &mut self, + sup: ty::Region<'tcx>, + sub: ty::Region<'tcx>, + info: ty::VarianceDiagInfo<'tcx>, + ) { debug!("push_outlives({:?}: {:?})", sup, sub); - self.delegate.push_outlives(sup, sub); + self.delegate.push_outlives(sup, sub, info); } /// Relate a projection type and some value type lazily. This will always @@ -490,6 +509,7 @@ where fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -497,6 +517,7 @@ where let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.ambient_variance.xform(variance); + self.ambient_variance_info = self.ambient_variance_info.clone().xform(info); debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance); @@ -574,12 +595,12 @@ where if self.ambient_covariance() { // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a); + self.push_outlives(v_b, v_a, self.ambient_variance_info.clone()); } if self.ambient_contravariance() { // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b); + self.push_outlives(v_a, v_b, self.ambient_variance_info.clone()); } Ok(a) @@ -835,6 +856,7 @@ where fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index bf5f328233d..b3131936ae0 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -62,6 +62,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 15b4a7ed207..ee358c52c2f 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,13 +16,12 @@ #![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] diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index f2b69da3f86..c7424b9e2a1 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,10 +1,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(internal_output_capture)] #![feature(nll)] -#![feature(generator_trait)] -#![feature(generators)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e2220e3b60d..9e3e96df3a7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,10 +6,10 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; -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; @@ -47,7 +47,9 @@ use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::lazy::SyncLazy; +use std::marker::PhantomPinned; use std::path::PathBuf; +use std::pin::Pin; use std::rc::Rc; use std::{env, fs, iter}; @@ -85,11 +87,83 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -declare_box_region_type!( - pub BoxedResolver, - for(), - (&mut Resolver<'_>) -> (Result<ast::Crate>, ResolverOutputs) -); +pub use boxed_resolver::BoxedResolver; +mod boxed_resolver { + use super::*; + + pub struct BoxedResolver(Pin<Box<BoxedResolverInner>>); + + struct BoxedResolverInner { + session: Lrc<Session>, + resolver_arenas: Option<ResolverArenas<'static>>, + resolver: Option<Resolver<'static>>, + _pin: PhantomPinned, + } + + // Note: Drop order is important to prevent dangling references. Resolver must be dropped first, + // then resolver_arenas and finally session. + impl Drop for BoxedResolverInner { + fn drop(&mut self) { + self.resolver.take(); + self.resolver_arenas.take(); + } + } + + impl BoxedResolver { + pub(super) fn new<F>(session: Lrc<Session>, make_resolver: F) -> Result<(ast::Crate, Self)> + where + F: for<'a> FnOnce( + &'a Session, + &'a ResolverArenas<'a>, + ) -> Result<(ast::Crate, Resolver<'a>)>, + { + let mut boxed_resolver = Box::new(BoxedResolverInner { + session, + resolver_arenas: Some(Resolver::arenas()), + resolver: None, + _pin: PhantomPinned, + }); + // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and + // returns a resolver with the same lifetime as the arena. We ensure that the arena + // outlives the resolver in the drop impl and elsewhere so these transmutes are sound. + unsafe { + let (crate_, resolver) = make_resolver( + std::mem::transmute::<&Session, &Session>(&boxed_resolver.session), + std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>( + boxed_resolver.resolver_arenas.as_ref().unwrap(), + ), + )?; + boxed_resolver.resolver = Some(resolver); + Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver)))) + } + } + + pub fn access<F: for<'a> FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R { + // SAFETY: The resolver doesn't need to be pinned. + let mut resolver = unsafe { + self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + f((&mut *resolver).as_mut().unwrap()) + } + + pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs { + match Rc::try_unwrap(resolver) { + Ok(resolver) => { + let mut resolver = resolver.into_inner(); + // SAFETY: The resolver doesn't need to be pinned. + let mut resolver = unsafe { + resolver + .0 + .as_mut() + .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + resolver.take().unwrap().into_outputs() + } + Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), + } + } + } +} /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, /// syntax expansion, secondary `cfg` expansion, synthesis of a test @@ -111,41 +185,16 @@ pub fn configure_and_expand( // its contents but the results of name resolution on those contents. Hopefully we'll push // this back at some point. let crate_name = crate_name.to_string(); - let (result, resolver) = BoxedResolver::new(static move |mut action| { - let _ = action; - let sess = &*sess; - let resolver_arenas = Resolver::arenas(); - let res = configure_and_expand_inner( + BoxedResolver::new(sess, move |sess, resolver_arenas| { + configure_and_expand_inner( sess, &lint_store, krate, &crate_name, &resolver_arenas, - &*metadata_loader, - ); - let mut resolver = match res { - Err(v) => { - yield BoxedResolver::initial_yield(Err(v)); - panic!() - } - Ok((krate, resolver)) => { - action = yield BoxedResolver::initial_yield(Ok(krate)); - resolver - } - }; - box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action); - resolver.into_outputs() - }); - result.map(|k| (k, resolver)) -} - -impl BoxedResolver { - pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs { - match Rc::try_unwrap(resolver) { - Ok(resolver) => resolver.into_inner().complete(), - Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), - } - } + metadata_loader, + ) + }) } pub fn register_plugins<'a>( @@ -172,7 +221,7 @@ pub fn register_plugins<'a>( 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); + rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?; if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { @@ -231,11 +280,11 @@ fn pre_expansion_lint( fn configure_and_expand_inner<'a>( sess: &'a Session, - lint_store: &'a LintStore, + lint_store: &LintStore, mut krate: ast::Crate, crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box<MetadataLoaderDyn>, ) -> Result<(ast::Crate, Resolver<'a>)> { tracing::trace!("configure_and_expand_inner"); pre_expansion_lint(sess, lint_store, &krate, crate_name); @@ -765,9 +814,7 @@ pub fn create_global_ctxt<'tcx>( ) -> QueryContext<'tcx> { let sess = &compiler.session(); - let def_path_table = resolver_outputs.definitions.def_path_table(); - let query_result_on_disk_cache = - rustc_incremental::load_query_result_cache(sess, def_path_table); + let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); let codegen_backend = compiler.codegen_backend(); let mut local_providers = *DEFAULT_QUERY_PROVIDERS; @@ -795,7 +842,7 @@ pub fn create_global_ctxt<'tcx>( query_result_on_disk_cache, queries.as_dyn(), &crate_name, - &outputs, + outputs, ) }) }); @@ -873,9 +920,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { 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); } @@ -982,7 +1028,7 @@ fn encode_and_write_metadata( .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)); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 92d05e48068..2320f0b47d2 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -148,7 +148,7 @@ impl<'tcx> Queries<'tcx> { 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 @@ -157,7 +157,7 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - result + Ok(result) }) } @@ -245,8 +245,7 @@ impl<'tcx> Queries<'tcx> { self.prepare_outputs.compute(|| { let expansion_result = self.expansion()?; let (krate, boxed_resolver, _) = &*expansion_result.peek(); - let crate_name = self.crate_name()?; - let crate_name = crate_name.peek(); + let crate_name = self.crate_name()?.peek(); passes::prepare_outputs( self.session(), self.compiler, @@ -343,32 +342,36 @@ impl<'tcx> Queries<'tcx> { } pub fn linker(&'tcx self) -> Result<Linker> { - let dep_graph = self.dep_graph()?; - let prepare_outputs = self.prepare_outputs()?; - let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE)); - let ongoing_codegen = self.ongoing_codegen()?; - let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); + let dep_graph = self.dep_graph()?.peek().clone(); + let prepare_outputs = self.prepare_outputs()?.take(); + let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE)); + let ongoing_codegen = self.ongoing_codegen()?.take(); + Ok(Linker { sess, - dep_graph: dep_graph.peek().clone(), - prepare_outputs: prepare_outputs.take(), - crate_hash, - ongoing_codegen: ongoing_codegen.take(), codegen_backend, + + dep_graph, + prepare_outputs, + crate_hash, + ongoing_codegen, }) } } pub struct Linker { + // compilation inputs sess: Lrc<Session>, + codegen_backend: Lrc<Box<dyn CodegenBackend>>, + + // compilation outputs dep_graph: DepGraph, prepare_outputs: OutputFilenames, crate_hash: Svh, ongoing_codegen: Box<dyn Any>, - codegen_backend: Lrc<Box<dyn CodegenBackend>>, } impl Linker { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index bea7d0fb81f..5d8a6084f2e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -252,7 +252,8 @@ fn test_lints_tracking_hash_different_construction_order() { (String::from("d"), Level::Forbid), ]; - assert_same_hash(&v1, &v2); + // The hash should be order-dependent + assert_different_hash(&v1, &v2); } #[test] @@ -491,9 +492,10 @@ fn test_native_libs_tracking_hash_different_order() { }, ]; - 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] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 7b1660b501b..6485fbebd66 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -35,7 +35,7 @@ use std::ops::DerefMut; use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex, Once}; +use std::sync::{Arc, Mutex}; use std::thread; use tracing::info; @@ -76,7 +76,10 @@ pub fn create_session( let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) } else { - get_codegen_backend(&sopts) + get_codegen_backend( + &sopts.maybe_sysroot, + sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]), + ) }; // target_override is documented to be called before init(), so this is okay @@ -244,35 +247,34 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> { } } -pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> { - static INIT: Once = Once::new(); - - static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!(); +/// Get the codegen backend based on the name and specified sysroot. +/// +/// A name of `None` indicates that the default backend should be used. +pub fn get_codegen_backend( + maybe_sysroot: &Option<PathBuf>, + backend_name: Option<&str>, +) -> Box<dyn CodegenBackend> { + static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new(); - INIT.call_once(|| { + let load = LOAD.get_or_init(|| { #[cfg(feature = "llvm")] const DEFAULT_CODEGEN_BACKEND: &str = "llvm"; #[cfg(not(feature = "llvm"))] const DEFAULT_CODEGEN_BACKEND: &str = "cranelift"; - let codegen_name = sopts - .debugging_opts - .codegen_backend - .as_ref() - .map(|name| &name[..]) - .unwrap_or(DEFAULT_CODEGEN_BACKEND); - - let backend = match codegen_name { + match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), - codegen_name => get_builtin_codegen_backend(&sopts.maybe_sysroot, codegen_name), - }; - - unsafe { - LOAD = backend; + #[cfg(feature = "llvm")] + "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, + backend_name => get_codegen_sysroot(maybe_sysroot, backend_name), } }); - unsafe { LOAD() } + + // SAFETY: In case of a builtin codegen backend this is safe. In case of an external codegen + // backend we hope that the backend links against the same rustc_driver version. If this is not + // the case, we get UB. + unsafe { load() } } // This is used for rustdoc, but it uses similar machinery to codegen backend @@ -390,17 +392,6 @@ fn sysroot_candidates() -> Vec<PathBuf> { } } -pub fn get_builtin_codegen_backend( - maybe_sysroot: &Option<PathBuf>, - backend_name: &str, -) -> fn() -> Box<dyn CodegenBackend> { - match backend_name { - #[cfg(feature = "llvm")] - "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, - _ => get_codegen_sysroot(maybe_sysroot, backend_name), - } -} - pub fn get_codegen_sysroot( maybe_sysroot: &Option<PathBuf>, backend_name: &str, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e7275374b89..f6a84966f7a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -489,7 +489,7 @@ fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool { 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; } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c1d6a4f1de1..a8df1b0952c 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -334,8 +334,14 @@ impl LintStore { } } - /// 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)), @@ -361,18 +367,23 @@ impl LintStore { }; 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 } } @@ -922,7 +933,7 @@ impl<'tcx> LateContext<'tcx> { } 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( diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 91cdef9b089..0ee434f5fb5 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ -109,6 +109,16 @@ impl<'s> LintLevelsBuilder<'s> { } } + 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 }); } @@ -142,6 +152,9 @@ impl<'s> LintLevelsBuilder<'s> { 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={:?}", @@ -166,6 +179,7 @@ impl<'s> LintLevelsBuilder<'s> { 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(); }; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2f46969b021..4f59460aa82 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -36,9 +36,6 @@ #![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"] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index be9c6eafb6f..7146dd51aa7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -176,6 +176,7 @@ impl EarlyLintPass for NonCamelCaseTypes { | 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), _ => (), } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9c94bab04e9..a3a87a48768 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet; 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}; @@ -13,7 +12,7 @@ use rustc_span::source_map; 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; @@ -680,16 +679,11 @@ pub fn transparent_newtype_field<'a, 'tcx>( variant: &'a ty::VariantDef, ) -> Option<&'a ty::FieldDef> { let param_env = tcx.param_env(variant.def_id); - for field in &variant.fields { + variant.fields.iter().find(|field| { let field_ty = tcx.type_of(field.did); let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst()); - - if !is_zst { - return Some(field); - } - } - - None + !is_zst + }) } /// Is type known to be non-null? @@ -712,15 +706,10 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi return false; } - for variant in &def.variants { - if let Some(field) = transparent_newtype_field(cx.tcx, variant) { - if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) { - return true; - } - } - } - - false + def.variants + .iter() + .filter_map(|variant| transparent_newtype_field(cx.tcx, variant)) + .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, substs), mode)) } _ => false, } @@ -783,25 +772,14 @@ crate fn repr_nullable_ptr<'tcx>( ) -> 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; } @@ -921,11 +899,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } 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); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 67946dfb292..44c2a550c30 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -858,10 +858,10 @@ impl EarlyLintPass for UnusedParens { // The other cases do not contain sub-patterns. | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, // These are list-like patterns; parens can always be removed. - TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { + TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false); }, - Struct(_, fps, _) => for f in fps { + Struct(_, _, fps, _) => for f in fps { self.check_unused_parens_pat(cx, &f.pat, false, false); }, // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 15246971bae..352146d6463 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2994,6 +2994,7 @@ declare_lint_pass! { USELESS_DEPRECATED, UNSUPPORTED_NAKED_FUNCTIONS, MISSING_ABI, + INVALID_DOC_ATTRIBUTES, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, DISJOINT_CAPTURE_MIGRATION, LEGACY_DERIVE_HELPERS, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 70475563a4a..f1c4e5fb4a3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -25,7 +25,11 @@ macro_rules! pluralize { /// 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, diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 7a34788de91..3fca2e1ccb9 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -13,4 +13,4 @@ libc = "0.2.73" [build-dependencies] build_helper = { path = "../../src/build_helper" } -cc = "1.0.67" +cc = "1.0.68" diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 301ed639f3b..452d1b19a18 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -86,6 +86,7 @@ fn main() { "nvptx", "hexagon", "riscv", + "bpf", ]; let required_components = &[ diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 99ce13a6ed5..3595e37cf96 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -793,16 +793,23 @@ LLVMRustOptimizeWithNewPassManager( PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse); } -#if LLVM_VERSION_GE(12, 0) +#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0) PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC); #else PassBuilder PB(TM, PTO, PGOOpt, &PIC); #endif +#if LLVM_VERSION_GE(13, 0) + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; +#else LoopAnalysisManager LAM(DebugPassManager); FunctionAnalysisManager FAM(DebugPassManager); CGSCCAnalysisManager CGAM(DebugPassManager); ModuleAnalysisManager MAM(DebugPassManager); +#endif FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); @@ -956,7 +963,11 @@ LLVMRustOptimizeWithNewPassManager( } } +#if LLVM_VERSION_GE(13, 0) + ModulePassManager MPM; +#else ModulePassManager MPM(DebugPassManager); +#endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { if (OptLevel == PassBuilder::OptimizationLevel::O0) { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 2e135fbe2bd..9b757eb40c1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -6,6 +6,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/Support/Signals.h" @@ -70,17 +71,6 @@ extern "C" void LLVMRustInstallFatalErrorHandler() { 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; @@ -1077,30 +1067,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, } } -// 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) { @@ -1757,3 +1723,54 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); } + +// This struct contains all necessary info about a symbol exported from a DLL. +// At the moment, it's just the symbol's name, but we use a separate struct to +// make it easier to add other information like ordinal later. +struct LLVMRustCOFFShortExport { + const char* name; +}; + +// Machine must be a COFF machine type, as defined in PE specs. +extern "C" LLVMRustResult LLVMRustWriteImportLibrary( + const char* ImportName, + const char* Path, + const LLVMRustCOFFShortExport* Exports, + size_t NumExports, + uint16_t Machine, + bool MinGW) +{ + std::vector<llvm::object::COFFShortExport> ConvertedExports; + ConvertedExports.reserve(NumExports); + + for (size_t i = 0; i < NumExports; ++i) { + ConvertedExports.push_back(llvm::object::COFFShortExport{ + Exports[i].name, // Name + std::string{}, // ExtName + std::string{}, // SymbolName + std::string{}, // AliasTarget + 0, // Ordinal + false, // Noname + false, // Data + false, // Private + false // Constant + }); + } + + auto Error = llvm::object::writeImportLibrary( + ImportName, + Path, + ConvertedExports, + static_cast<llvm::COFF::MachineTypes>(Machine), + MinGW); + if (Error) { + std::string errorString; + llvm::raw_string_ostream stream(errorString); + stream << Error; + stream.flush(); + LLVMRustSetLastError(errorString.c_str()); + return LLVMRustResult::Failure; + } else { + return LLVMRustResult::Success; + } +} diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 555aefb1929..122627eb500 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -167,4 +167,12 @@ pub fn initialize_available_targets() { LLVMInitializeWebAssemblyAsmPrinter, LLVMInitializeWebAssemblyAsmParser ); + init_target!( + llvm_component = "bpf", + LLVMInitializeBPFTargetInfo, + LLVMInitializeBPFTarget, + LLVMInitializeBPFTargetMC, + LLVMInitializeBPFAsmPrinter, + LLVMInitializeBPFAsmParser + ); } diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 72bd4804e98..7bc669f2b00 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -43,12 +43,9 @@ fn decodable_body( let decode_body = match s.variants() { [vi] => { let construct = vi.construct(|field, index| decode_field(field, index, true)); - let n_fields = vi.ast().fields.len(); quote! { ::rustc_serialize::Decoder::read_struct( __decoder, - #ty_name, - #n_fields, |__decoder| { ::std::result::Result::Ok(#construct) }, ) } @@ -77,7 +74,6 @@ fn decodable_body( quote! { ::rustc_serialize::Decoder::read_enum( __decoder, - #ty_name, |__decoder| { ::rustc_serialize::Decoder::read_enum_variant( __decoder, @@ -128,7 +124,7 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro quote! { match ::rustc_serialize::Decoder::#decode_method( - __decoder, #opt_field_name #index, #decode_inner_method) { + __decoder, #opt_field_name #decode_inner_method) { ::std::result::Result::Ok(__res) => __res, ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), } @@ -183,7 +179,6 @@ fn encodable_body( } }); - let ty_name = s.ast().ident.to_string(); let encode_body = match s.variants() { [_] => { let mut field_idx = 0usize; @@ -197,11 +192,12 @@ fn encodable_body( .ident .as_ref() .map_or_else(|| field_idx.to_string(), |i| i.to_string()); + let first = field_idx == 0; let result = quote! { match ::rustc_serialize::Encoder::emit_struct_field( __encoder, #field_name, - #field_idx, + #first, |__encoder| ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), ) { @@ -215,8 +211,9 @@ fn encodable_body( }) .collect::<TokenStream>() }); + let no_fields = field_idx == 0; quote! { - ::rustc_serialize::Encoder::emit_struct(__encoder, #ty_name, #field_idx, |__encoder| { + ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| { ::std::result::Result::Ok(match *self { #encode_inner }) }) } @@ -232,10 +229,11 @@ fn encodable_body( .iter() .map(|binding| { let bind_ident = &binding.binding; + let first = field_idx == 0; let result = quote! { match ::rustc_serialize::Encoder::emit_enum_variant_arg( __encoder, - #field_idx, + #first, |__encoder| ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), ) { @@ -260,7 +258,7 @@ fn encodable_body( result }); quote! { - ::rustc_serialize::Encoder::emit_enum(__encoder, #ty_name, |__encoder| { + ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| { match *self { #encode_inner } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e9ae22f8ced..d73cfe35dc4 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -54,7 +54,7 @@ pub struct CStore { pub struct CrateLoader<'a> { // Immutable configuration. sess: &'a Session, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box<MetadataLoaderDyn>, local_crate_name: Symbol, // Mutable output. cstore: CStore, @@ -219,7 +219,7 @@ impl CStore { impl<'a> CrateLoader<'a> { pub fn new( sess: &'a Session, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box<MetadataLoaderDyn>, local_crate_name: &str, ) -> Self { let local_crate_stable_id = @@ -544,7 +544,7 @@ impl<'a> CrateLoader<'a> { info!("falling back to a load"); let mut locator = CrateLocator::new( self.sess, - self.metadata_loader, + &*self.metadata_loader, name, hash, host_hash, diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index c4d9e3f77f0..2c9bad7e5ce 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,14 +1,11 @@ #![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"] @@ -32,3 +29,5 @@ mod rmeta; pub mod creader; pub mod dynamic_lib; pub mod locator; + +pub use rmeta::METADATA_HEADER; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index bc342119efb..cd4c394ae14 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::NativeLib; +use rustc_middle::middle::cstore::{DllImport, NativeLib}; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; @@ -33,8 +33,8 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - let abi = match it.kind { - hir::ItemKind::ForeignMod { abi, .. } => abi, + let (abi, foreign_mod_items) = match it.kind { + hir::ItemKind::ForeignMod { abi, items } => (abi, items), _ => return, }; @@ -57,6 +57,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { foreign_module: Some(it.def_id.to_def_id()), wasm_import_module: None, verbatim: None, + dll_imports: Vec::new(), }; let mut kind_specified = false; @@ -196,6 +197,27 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { .span_label(m.span, "missing `name` argument") .emit(); } + + if lib.kind == NativeLibKind::RawDylib { + match abi { + Abi::C { .. } => (), + Abi::Cdecl => (), + _ => { + if sess.target.arch == "x86" { + sess.span_fatal( + it.span, + r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#, + ); + } + } + }; + lib.dll_imports.extend( + foreign_mod_items + .iter() + .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }), + ); + } + self.register_native_lib(Some(m.span), lib); } } @@ -253,15 +275,42 @@ impl Collector<'tcx> { ) .emit(); } - if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib { - feature_err( - &self.tcx.sess.parse_sess, - sym::raw_dylib, - span.unwrap_or(rustc_span::DUMMY_SP), - "kind=\"raw-dylib\" is unstable", - ) - .emit(); + // this just unwraps lib.name; we already established that it isn't empty above. + if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) { + let span = match span { + Some(s) => s, + None => { + bug!("raw-dylib libraries are not supported on the command line"); + } + }; + + if !self.tcx.sess.target.options.is_like_windows { + self.tcx.sess.span_fatal( + span, + "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows", + ); + } else if !self.tcx.sess.target.options.is_like_msvc { + self.tcx.sess.span_warn( + span, + "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu", + ); + } + + if lib_name.as_str().contains('\0') { + self.tcx.sess.span_err(span, "library name may not contain NUL characters"); + } + + if !self.tcx.features().raw_dylib { + feature_err( + &self.tcx.sess.parse_sess, + sym::raw_dylib, + span, + "kind=\"raw-dylib\" is unstable", + ) + .emit(); + } } + self.libs.push(lib); } @@ -337,6 +386,7 @@ impl Collector<'tcx> { foreign_module: None, wasm_import_module: None, verbatim: passed_lib.verbatim, + dll_imports: Vec::new(), }; self.register_native_lib(None, lib); } else { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b27eef376c4..52cb1e1996e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { { 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); @@ -1935,6 +1935,10 @@ impl CrateMetadata { 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 } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index e25b22c8331..9a97835d9c0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,7 +1,7 @@ use crate::creader::{CStore, LoadedMacro}; use crate::foreign_modules; use crate::native_libs; -use crate::rmeta::{self, encoder}; +use crate::rmeta::encoder; use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; @@ -155,6 +155,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, 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 } @@ -188,7 +189,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, 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() } @@ -205,7 +206,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, 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); @@ -251,6 +251,10 @@ pub fn provide(providers: &mut Providers) { 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() @@ -455,6 +459,13 @@ impl CStore { 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() } @@ -478,10 +489,6 @@ impl CrateStore for CStore { 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 } @@ -529,10 +536,6 @@ impl CrateStore for CStore { encoder::encode_metadata(tcx) } - fn metadata_encoding_version(&self) -> &[u8] { - rmeta::METADATA_HEADER - } - fn allocator_kind(&self) -> Option<AllocatorKind> { self.allocator_kind() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0c31430598a..76007398000 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -943,7 +943,7 @@ impl EncodeContext<'a, 'tcx> { }); 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)); } @@ -1674,7 +1674,7 @@ impl EncodeContext<'a, 'tcx> { .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), diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 04fe5cf5890..99ea0cc8f2f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -52,7 +52,7 @@ const METADATA_VERSION: u8 = 5; /// This header is followed by the position of the `CrateRoot`, /// which is encoded as a 32-bit big-endian unsigned integer, /// and further followed by the rustc version string. -crate const METADATA_HEADER: &[u8; 8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; +pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; /// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`, /// e.g. for `Lazy<[T]>`, this is the length (count of `T` values). diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d5697513eef..a89d00e26ac 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -14,6 +14,7 @@ macro_rules! arena_types { [] 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: diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index aa54d1ae7b9..8476929eaec 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -285,7 +285,7 @@ pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>; // required that their size stay the same, but we don't want to change // it inadvertently. This assert just ensures we're aware of any change. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -static_assert_size!(DepNode, 17); +static_assert_size!(DepNode, 18); #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] static_assert_size!(DepNode, 24); diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 31bea832958..aa61219ad78 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -18,7 +18,6 @@ crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; 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>; diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 342cc9a7397..8ffd98326f1 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,6 +1,6 @@ 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; @@ -28,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> { /// 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 @@ -107,9 +107,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { 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( @@ -124,7 +122,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { 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 } @@ -137,22 +135,13 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { 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 { @@ -168,13 +157,16 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { 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>) { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d154b7804f0..20bbf9097f4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,6 @@ 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; @@ -952,7 +952,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { .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())) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 879372c65ea..087f772c812 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -15,23 +15,25 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; -use rustc_index::vec::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>, } @@ -43,6 +45,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'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, @@ -51,8 +56,12 @@ pub struct ParentedNode<'tcx> { #[derive(Debug)] pub struct OwnerNodes<'tcx> { + /// Pre-computed hash of the full HIR. hash: Fingerprint, + /// Full HIR for the current owner. + // The zeroth node's parent is trash, but is never accessed. nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, + /// Content of local bodies. bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>, } @@ -65,6 +74,8 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'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]>, @@ -127,8 +138,12 @@ pub fn provide(providers: &mut Providers) { 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) @@ -152,4 +167,8 @@ pub fn provide(providers: &mut Providers) { }; 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) + }; } diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index b2fef731b7e..91c81c367a1 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -14,7 +14,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData}; -use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX}; use smallvec::SmallVec; use std::cmp::Ord; use std::thread::LocalKey; @@ -227,15 +226,8 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } #[inline] - fn hash_crate_num(&mut self, cnum: CrateNum, hasher: &mut StableHasher) { - let hcx = self; - hcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher); - } - - #[inline] - fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) { - let hcx = self; - hcx.def_path_hash(def_id).hash_stable(hcx, hasher); + fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + self.def_path_hash(def_id) } fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> { diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs index abf56832329..5dfd00bc6d4 100644 --- a/compiler/rustc_middle/src/ich/impls_hir.rs +++ b/compiler/rustc_middle/src/ich/impls_hir.rs @@ -6,7 +6,6 @@ use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::DefPathHash; use smallvec::SmallVec; use std::mem; @@ -113,46 +112,6 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { self.node_id_hashing_mode = prev_hash_node_ids; } - - #[inline] - fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash { - self.local_def_path_hash(def_id) - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.def_path_hash(*self) - } -} - -impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId { - #[inline] - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher); - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.def_path_hash(self.to_def_id()) - } -} - -impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; - def_id.to_stable_hash_key(hcx) - } } impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::ItemLocalId { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 5df2f91f09f..d764d45ba7e 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -294,6 +294,7 @@ TrivialTypeFoldableImpls! { } impl<'tcx> CanonicalVarValues<'tcx> { + #[inline] pub fn len(&self) -> usize { self.var_values.len() } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 597a4fd0f52..e1d7bc4be53 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,14 +29,12 @@ #![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)] @@ -83,6 +81,7 @@ pub mod infer; pub mod lint; pub mod middle; pub mod mir; +pub mod thir; pub mod traits; pub mod ty; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 38d0793a682..4c7ea937ceb 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,7 +1,7 @@ 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; @@ -28,6 +28,9 @@ pub enum LintLevelSource { /// 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 { @@ -36,6 +39,7 @@ impl LintLevelSource { LintLevelSource::Default => symbol::kw::Default, LintLevelSource::Node(name, _, _) => name, LintLevelSource::CommandLine(name, _) => name, + LintLevelSource::ForceWarn(name) => name, } } @@ -44,6 +48,7 @@ impl LintLevelSource { LintLevelSource::Default => DUMMY_SP, LintLevelSource::Node(_, span, _) => span, LintLevelSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::ForceWarn(_) => DUMMY_SP, } } } @@ -55,6 +60,7 @@ pub type LevelAndSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec<LintSet>, pub lint_cap: Level, + pub force_warns: FxHashSet<LintId>, } #[derive(Debug)] @@ -73,7 +79,11 @@ pub enum LintSet { 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( @@ -83,6 +93,11 @@ impl LintLevelSets { 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 @@ -176,11 +191,11 @@ impl LintLevelMap { 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); @@ -346,6 +361,13 @@ pub fn struct_lint_level<'s, 'd>( ); } } + 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 }); diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index d63116e29c8..a7ab43d106c 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -95,6 +95,13 @@ pub struct NativeLib { pub foreign_module: Option<DefId>, pub wasm_import_module: Option<Symbol>, pub verbatim: Option<bool>, + pub dll_imports: Vec<DllImport>, +} + +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct DllImport { + pub name: Symbol, + pub ordinal: Option<u16>, } #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] @@ -199,7 +206,6 @@ pub trait CrateStore { // "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 crate_hash_untracked(&self, cnum: CrateNum) -> Svh; @@ -209,7 +215,6 @@ pub trait CrateStore { // utility functions fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; - fn metadata_encoding_version(&self) -> &[u8]; fn allocator_kind(&self) -> Option<AllocatorKind>; } diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 276e45ce99b..288dd039446 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -49,7 +49,7 @@ impl<'tcx> ExportedSymbol<'tcx> { pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { format!( "rust_metadata_{}_{}", - tcx.original_crate_name(LOCAL_CRATE), + tcx.crate_name(LOCAL_CRATE), tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex() ) } diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 776a777b1bd..1ef10241143 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -1,6 +1,6 @@ //! A subset of a mir body used for const evaluatability checking. -use crate::mir; -use crate::ty; +use crate::mir::{self, CastKind}; +use crate::ty::{self, Ty}; rustc_index::newtype_index! { /// An index into an `AbstractConst`. @@ -17,6 +17,7 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), + Cast(CastKind, NodeId, Ty<'tcx>), } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 622eaf57578..ee3902991e9 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -99,8 +99,12 @@ impl AllocRange { // 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 { @@ -108,13 +112,13 @@ impl<Tag> Allocation<Tag> { 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 { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7282e65f3f8..7941800c7fa 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -227,7 +227,11 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), /// Invalid drop function in vtable. - InvalidDropFn(FnSig<'tcx>), + InvalidVtableDropFn(FnSig<'tcx>), + /// Invalid size in a vtable: too large. + InvalidVtableSize, + /// Invalid alignment in a vtable: too large, or not a power of 2. + InvalidVtableAlignment(String), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -252,7 +256,12 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// The value validity check found a problem. /// Should only be thrown by `validity.rs` and always point out which part of the value /// is the problem. - ValidationFailure(String), + ValidationFailure { + /// The "path" to the value in question, e.g. `.0[5].field` for a struct + /// field in the 6th element of an array that is the first element of a tuple. + path: Option<String>, + msg: String, + }, /// Using a non-boolean `u8` as bool. InvalidBool(u8), /// Using a non-character `u32` as character. @@ -287,11 +296,15 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), - InvalidDropFn(sig) => write!( + InvalidVtableDropFn(sig) => write!( f, "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", sig ), + InvalidVtableSize => { + write!(f, "invalid vtable: size is bigger than largest supported object") + } + InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {} with no null found before end of allocation", @@ -323,7 +336,10 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { ), WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a), DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a), - ValidationFailure(ref err) => write!(f, "type validation failed: {}", err), + ValidationFailure { path: None, msg } => write!(f, "type validation failed: {}", msg), + ValidationFailure { path: Some(path), msg } => { + write!(f, "type validation failed at {}: {}", path, msg) + } InvalidBool(b) => { write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b) } @@ -435,8 +451,12 @@ impl<T: Any> AsAny for T { } /// 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)] @@ -487,13 +507,13 @@ impl fmt::Debug for InterpError<'_> { } impl InterpError<'_> { - /// Some errors to string formatting even if the error is never printed. + /// Some errors do string formatting even if the error is never printed. /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, /// so this method lets us detect them and `bug!` on unexpected errors. pub fn formatted_string(&self) -> bool { match self { InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) - | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. }) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true, _ => false, } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d03a7421ca7..14bdb0a5a2d 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -246,6 +246,7 @@ pub struct AllocDecodingState { } 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); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1cc7f235d7d..7ae7eab6e5a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1249,10 +1249,12 @@ impl<'tcx> BasicBlockData<'tcx> { /// /// 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") } @@ -1870,6 +1872,7 @@ impl<'tcx> PlaceRef<'tcx> { /// 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), @@ -1877,6 +1880,7 @@ impl<'tcx> PlaceRef<'tcx> { } } + #[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)) @@ -2464,12 +2468,14 @@ impl Constant<'tcx> { _ => 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) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index edf2e539765..74650f50a1c 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -186,6 +186,15 @@ impl<'tcx> MonoItem<'tcx> { 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> { @@ -258,6 +267,7 @@ pub enum Visibility { } impl<'tcx> CodegenUnit<'tcx> { + #[inline] pub fn new(name: Symbol) -> CodegenUnit<'tcx> { CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false } } @@ -302,6 +312,7 @@ impl<'tcx> CodegenUnit<'tcx> { 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") diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 0edb79fdbc8..4fb737f463a 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,13 +2,14 @@ use crate::mir::{abstract_const, Body, Promoted}; use crate::ty::{self, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; use rustc_index::vec::IndexVec; +use rustc_middle::ty::OpaqueTypeKey; use rustc_span::Span; use rustc_target::abi::VariantIdx; use smallvec::SmallVec; @@ -210,7 +211,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, pub used_mut_upvars: SmallVec<[Field; 8]>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 70f70788bca..0860520ef9d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -47,7 +47,7 @@ rustc_queries! { /// /// 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()) } } @@ -210,8 +210,8 @@ rustc_queries! { 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) } } @@ -220,6 +220,13 @@ rustc_queries! { 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. @@ -1120,8 +1127,7 @@ rustc_queries! { 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" } } @@ -1245,10 +1251,6 @@ rustc_queries! { 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" } @@ -1412,6 +1414,12 @@ rustc_queries! { 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) } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs new file mode 100644 index 00000000000..a5069113702 --- /dev/null +++ b/compiler/rustc_middle/src/thir.rs @@ -0,0 +1,747 @@ +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(()) + } + } + } +} diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 8e2c79701af..02ff1b9f4d6 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -46,6 +46,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, + _: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a50dda69a0f..8f648b21131 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -47,7 +47,7 @@ pub enum PointerCast { /// 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`. @@ -56,7 +56,7 @@ pub enum PointerCast { /// 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: /// /// ``` @@ -66,7 +66,7 @@ pub enum PointerCast { /// ``` /// /// 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]`. @@ -75,8 +75,8 @@ pub enum PointerCast { /// 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>, diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 7790369af7f..0706a057dd0 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -1,7 +1,7 @@ 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; @@ -12,6 +12,10 @@ use super::{Ty, TyCtxt}; 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, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index dde5cbadbd9..d13cbdd1228 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -13,6 +13,7 @@ use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetime 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}; @@ -30,9 +31,10 @@ use rustc_attr as attr; 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_data_structures::vec_map::VecMap; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -46,6 +48,7 @@ use rustc_hir::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; +use rustc_middle::ty::OpaqueTypeKey; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; @@ -285,17 +288,6 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } -/// All information necessary to validate and reveal an `impl Trait`. -#[derive(TyEncodable, TyDecodable, Debug, HashStable)] -pub struct ResolvedOpaqueTy<'tcx> { - /// The revealed type as seen by this function. - pub concrete_type: Ty<'tcx>, - /// Generic parameters on the opaque type as passed by this function. - /// For `type Foo<A, B> = impl Bar<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }` - /// this is `[T, U]`, not `[A, B]`. - pub substs: SubstsRef<'tcx>, -} - /// Whenever a value may be live across a generator yield, the type of that value winds up in the /// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such /// captured types that can be useful for diagnostics. In particular, it stores the span that @@ -423,7 +415,7 @@ pub struct TypeckResults<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. - pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>, + pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -965,10 +957,6 @@ pub struct GlobalCtxt<'tcx> { /// 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>, @@ -1008,7 +996,7 @@ pub struct GlobalCtxt<'tcx> { /// 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, @@ -1041,6 +1029,10 @@ impl<'tcx> TyCtxt<'tcx> { } } + 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)) } @@ -1072,7 +1064,7 @@ impl<'tcx> TyCtxt<'tcx> { /// 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) } @@ -1134,7 +1126,7 @@ impl<'tcx> TyCtxt<'tcx> { 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); @@ -1145,12 +1137,6 @@ impl<'tcx> TyCtxt<'tcx> { 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, @@ -1164,7 +1150,6 @@ impl<'tcx> TyCtxt<'tcx> { 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, @@ -1185,7 +1170,7 @@ impl<'tcx> TyCtxt<'tcx> { 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, } } @@ -1270,12 +1255,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// 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() { @@ -1309,10 +1288,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn metadata_encoding_version(self) -> Vec<u8> { - self.cstore.metadata_encoding_version().to_vec() - } - pub fn encode_metadata(self) -> EncodedMetadata { let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata"); self.cstore.encode_metadata(self) @@ -2657,8 +2632,10 @@ impl<'tcx> TyCtxt<'tcx> { 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> { @@ -2788,7 +2765,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { } 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); diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 982c8a354b4..bfb4c0cb538 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -54,7 +54,7 @@ impl<'tcx> TyS<'tcx> { /// ADTs with no type arguments. pub fn is_simple_text(&self) -> bool { match self.kind() { - Adt(_, substs) => substs.types().next().is_none(), + Adt(_, substs) => substs.non_erasable_generics().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(), _ => self.is_simple_ty(), } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index c8fdbc30d15..4e3f475a915 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -93,6 +93,7 @@ pub struct Generics { } impl<'tcx> Generics { + #[inline] pub fn count(&self) -> usize { self.parent_count + self.params.len() } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2e9dba6c8e..28a44b09de2 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -367,7 +367,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { for &i in &inverse_memory_index { let field = fields[i as usize]; if !sized { - bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty); + self.tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "univariant: field #{} of `{}` comes after unsized field", + offsets.len(), + ty + ), + ); } if field.is_unsized() { @@ -2579,7 +2586,7 @@ where 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, @@ -2641,6 +2648,43 @@ fn fn_can_unwind( } } +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>> @@ -2650,10 +2694,7 @@ where + 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 { @@ -2689,35 +2730,7 @@ where 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 { @@ -2753,6 +2766,7 @@ where 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. diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index e657088a5e4..44dfcbf1866 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -37,9 +37,11 @@ pub struct List<T> { 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>) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 94e325e9e87..227aa8dc284 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -39,7 +39,6 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; 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; @@ -59,7 +58,7 @@ pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Uneval pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, - Lift, ResolvedOpaqueTy, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, + Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex, }; pub use self::instance::{Instance, InstanceDef}; pub use self::list::List; @@ -72,7 +71,7 @@ pub use self::sty::{ ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, - RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, + RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, }; pub use self::trait_def::TraitDef; @@ -269,7 +268,7 @@ pub struct CrateVariancesMap<'tcx> { // the types of AST nodes. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct CReaderCacheKey { - pub cnum: CrateNum, + pub cnum: Option<CrateNum>, pub pos: usize, } @@ -836,6 +835,12 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub struct OpaqueTypeKey<'tcx> { + pub def_id: DefId, + pub substs: SubstsRef<'tcx>, +} + rustc_index::newtype_index! { /// "Universes" are used during type- and trait-checking in the /// presence of `for<..>` binders to control what sets of names are @@ -1097,12 +1102,14 @@ pub struct ParamEnv<'tcx> { 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, @@ -1200,6 +1207,7 @@ impl<'tcx> ParamEnv<'tcx> { } /// Returns this same environment but with no caller bounds. + #[inline] pub fn without_caller_bounds(self) -> Self { Self::new(List::empty(), self.reveal()) } @@ -1618,7 +1626,7 @@ impl<'tcx> TyCtxt<'tcx> { 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 { @@ -1859,20 +1867,11 @@ impl<'tcx> TyCtxt<'tcx> { && 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 } @@ -1883,8 +1882,7 @@ impl<'tcx> TyCtxt<'tcx> { 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) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f514278a11c..69e3b8c76c8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -452,7 +452,7 @@ pub trait PrettyPrinter<'tcx>: } // 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)); } _ => {} } @@ -685,10 +685,10 @@ pub trait PrettyPrinter<'tcx>: self = self.comma_sep(substs.as_generator().upvar_tys())?; } p!(")"); - } - if substs.as_generator().is_valid() { - p!(" ", print(substs.as_generator().witness())); + if substs.as_generator().is_valid() { + p!(" ", print(substs.as_generator().witness())); + } } p!("]") diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 3c772a14647..297110ee3ec 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -18,6 +18,7 @@ use crate::mir::interpret::GlobalId; 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, @@ -33,7 +34,6 @@ use crate::ty::subst::{GenericArg, SubstsRef}; 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; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index a688b816e9a..5c42625306b 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -10,7 +10,7 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathHash, DefPathTable}; +use rustc_hir::definitions::DefPathHash; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::dep_graph::DepContext; use rustc_query_system::query::QueryContext; @@ -27,7 +27,6 @@ use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP}; use std::collections::hash_map::Entry; -use std::iter::FromIterator; use std::mem; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -103,12 +102,6 @@ pub struct OnDiskCache<'sess> { // during the next compilation session. latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>, - // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all - // local items in the current compilation session. This is only populated - // when we are in incremental mode and have loaded a pre-existing cache - // from disk, since this map is only used when deserializing a `DefPathHash` - // from the incremental cache. - local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>, // Caches all lookups of `DefPathHashes`, both for local and foreign // definitions. A definition from the previous compilation session // may no longer exist in the current compilation session, so @@ -168,12 +161,7 @@ crate struct RawDefId { impl<'sess> OnDiskCache<'sess> { /// Creates a new `OnDiskCache` instance from the serialized data in `data`. - pub fn new( - sess: &'sess Session, - data: Vec<u8>, - start_pos: usize, - def_path_table: &DefPathTable, - ) -> Self { + pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self { debug_assert!(sess.opts.incremental.is_some()); // Wrap in a scope so we can borrow `data`. @@ -210,11 +198,6 @@ impl<'sess> OnDiskCache<'sess> { hygiene_context: Default::default(), foreign_def_path_hashes: footer.foreign_def_path_hashes, latest_foreign_def_path_hashes: Default::default(), - local_def_path_hash_to_def_id: UnhashMap::from_iter( - def_path_table - .all_def_path_hashes_and_def_ids(LOCAL_CRATE) - .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())), - ), def_path_hash_to_def_id_cache: Default::default(), } } @@ -236,7 +219,6 @@ impl<'sess> OnDiskCache<'sess> { hygiene_context: Default::default(), foreign_def_path_hashes: Default::default(), latest_foreign_def_path_hashes: Default::default(), - local_def_path_hash_to_def_id: Default::default(), def_path_hash_to_def_id_cache: Default::default(), } } @@ -349,7 +331,7 @@ impl<'sess> OnDiskCache<'sess> { let prev_cnums: Vec<_> = sorted_cnums .iter() .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); + let crate_name = tcx.crate_name(cnum).to_string(); let crate_disambiguator = tcx.crate_disambiguator(cnum); (cnum.as_u32(), crate_name, crate_disambiguator) }) @@ -582,7 +564,7 @@ impl<'sess> OnDiskCache<'sess> { .all_crate_nums(()) .iter() .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); + let crate_name = tcx.crate_name(cnum).to_string(); let crate_disambiguator = tcx.crate_disambiguator(cnum); ((crate_name, crate_disambiguator), cnum) }) @@ -616,7 +598,7 @@ impl<'sess> OnDiskCache<'sess> { debug!("def_path_hash_to_def_id({:?})", hash); // Check if the `DefPathHash` corresponds to a definition in the current // crate - if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() { + if let Some(def_id) = tcx.definitions.local_def_path_hash_to_def_id(hash) { let def_id = def_id.to_def_id(); e.insert(Some(def_id)); return Some(def_id); @@ -758,8 +740,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { { 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); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b6f93c9bd59..3f426b13688 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -67,6 +67,7 @@ pub trait TypeRelation<'tcx>: Sized { fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, + info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T>; @@ -111,24 +112,23 @@ pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy { /////////////////////////////////////////////////////////////////////////// // Relate impls -impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::TypeAndMut<'tcx>, - b: ty::TypeAndMut<'tcx>, - ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { - debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); - if a.mutbl != b.mutbl { - Err(TypeError::Mutability) - } else { - let mutbl = a.mutbl; - let variance = match mutbl { - ast::Mutability::Not => ty::Covariant, - ast::Mutability::Mut => ty::Invariant, - }; - let ty = relation.relate_with_variance(variance, a.ty, b.ty)?; - Ok(ty::TypeAndMut { ty, mutbl }) - } +pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( + relation: &mut R, + a: ty::TypeAndMut<'tcx>, + b: ty::TypeAndMut<'tcx>, + kind: ty::VarianceDiagMutKind, +) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { + debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); + if a.mutbl != b.mutbl { + Err(TypeError::Mutability) + } else { + let mutbl = a.mutbl; + let (variance, info) = match mutbl { + ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), + ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }), + }; + let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?; + Ok(ty::TypeAndMut { ty, mutbl }) } } @@ -142,7 +142,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>( let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, a, b) + relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b) }); tcx.mk_substs(params) @@ -177,7 +177,12 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { if is_output { relation.relate(a, b) } else { - relation.relate_with_variance(ty::Contravariant, a, b) + relation.relate_with_variance( + ty::Contravariant, + ty::VarianceDiagInfo::default(), + a, + b, + ) } }) .enumerate() @@ -251,8 +256,18 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { b.item_def_id, ))) } else { - let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?; - let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?; + let ty = relation.relate_with_variance( + ty::Invariant, + ty::VarianceDiagInfo::default(), + a.ty, + b.ty, + )?; + let substs = relation.relate_with_variance( + ty::Invariant, + ty::VarianceDiagInfo::default(), + a.substs, + b.substs, + )?; Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty }) } } @@ -364,7 +379,12 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>( (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { - relation.relate_with_variance(ty::Contravariant, a_region, b_region) + relation.relate_with_variance( + ty::Contravariant, + ty::VarianceDiagInfo::default(), + a_region, + b_region, + ) })?; Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) } @@ -398,15 +418,20 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>( } (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { - let mt = relation.relate(a_mt, b_mt)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?; Ok(tcx.mk_ptr(mt)) } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?; + let r = relation.relate_with_variance( + ty::Contravariant, + ty::VarianceDiagInfo::default(), + a_r, + b_r, + )?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; - let mt = relation.relate(a_mt, b_mt)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?; Ok(tcx.mk_ref(r, mt)) } @@ -536,8 +561,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>( (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def && au.promoted == bu.promoted => { - let substs = - relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?; + let substs = relation.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + au.substs, + bu.substs, + )?; return Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: au.def, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 691bfcc98d1..1d9ff512288 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -669,7 +669,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, HashStable)] pub enum UpvarSubsts<'tcx> { Closure(SubstsRef<'tcx>), Generator(SubstsRef<'tcx>), @@ -1837,10 +1837,12 @@ impl<'tcx> TyS<'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] @@ -1889,11 +1891,6 @@ impl<'tcx> TyS<'tcx> { } #[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(_)) } @@ -2184,3 +2181,55 @@ impl<'tcx> TyS<'tcx> { } } } + +/// Extra information about why we ended up with a particular variance. +/// This is only used to add more information to error messages, and +/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` +/// may lead to confusing notes in error messages, it will never cause +/// a miscompilation or unsoundness. +/// +/// When in doubt, use `VarianceDiagInfo::default()` +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum VarianceDiagInfo<'tcx> { + /// No additional information - this is the default. + /// We will not add any additional information to error messages. + None, + /// We switched our variance because a type occurs inside + /// the generic argument of a mutable reference or pointer + /// (`*mut T` or `&mut T`). In either case, our variance + /// will always be `Invariant`. + Mut { + /// Tracks whether we had a mutable pointer or reference, + /// for better error messages + kind: VarianceDiagMutKind, + /// The type parameter of the mutable pointer/reference + /// (the `T` in `&mut T` or `*mut T`). + ty: Ty<'tcx>, + }, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum VarianceDiagMutKind { + /// A mutable raw pointer (`*mut T`) + RawPtr, + /// A mutable reference (`&mut T`) + Ref, +} + +impl<'tcx> VarianceDiagInfo<'tcx> { + /// Mirrors `Variance::xform` - used to 'combine' the existing + /// and new `VarianceDiagInfo`s when our variance changes. + pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { + // For now, just use the first `VarianceDiagInfo::Mut` that we see + match self { + VarianceDiagInfo::None => other, + VarianceDiagInfo::Mut { .. } => self, + } + } +} + +impl<'tcx> Default for VarianceDiagInfo<'tcx> { + fn default() -> Self { + Self::None + } +} diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c84ca61122f..9b8d22d8eaf 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } /// 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> { diff --git a/compiler/rustc_mir/src/borrow_check/constraints/graph.rs b/compiler/rustc_mir/src/borrow_check/constraints/graph.rs index f3f6b8c10da..9e4cfb2cc00 100644 --- a/compiler/rustc_mir/src/borrow_check/constraints/graph.rs +++ b/compiler/rustc_mir/src/borrow_check/constraints/graph.rs @@ -1,7 +1,7 @@ use rustc_data_structures::graph; use rustc_index::vec::IndexVec; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::RegionVid; +use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; use rustc_span::DUMMY_SP; use crate::borrow_check::{ @@ -26,8 +26,8 @@ crate type ReverseConstraintGraph = ConstraintGraph<Reverse>; /// Marker trait that controls whether a `R1: R2` constraint /// represents an edge `R1 -> R2` or `R2 -> R1`. crate trait ConstraintGraphDirecton: Copy + 'static { - fn start_region(c: &OutlivesConstraint) -> RegionVid; - fn end_region(c: &OutlivesConstraint) -> RegionVid; + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; fn is_normal() -> bool; } @@ -39,11 +39,11 @@ crate trait ConstraintGraphDirecton: Copy + 'static { crate struct Normal; impl ConstraintGraphDirecton for Normal { - fn start_region(c: &OutlivesConstraint) -> RegionVid { + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sup } - fn end_region(c: &OutlivesConstraint) -> RegionVid { + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sub } @@ -60,11 +60,11 @@ impl ConstraintGraphDirecton for Normal { crate struct Reverse; impl ConstraintGraphDirecton for Reverse { - fn start_region(c: &OutlivesConstraint) -> RegionVid { + fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sub } - fn end_region(c: &OutlivesConstraint) -> RegionVid { + fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { c.sup } @@ -78,7 +78,7 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> { /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. - crate fn new(direction: D, set: &OutlivesConstraintSet, num_region_vars: usize) -> Self { + crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self { let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars); let mut next_constraints = IndexVec::from_elem(None, &set.outlives); @@ -96,21 +96,21 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> { /// Given the constraint set from which this graph was built /// creates a region graph so that you can iterate over *regions* /// and not constraints. - crate fn region_graph<'rg>( + crate fn region_graph<'rg, 'tcx>( &'rg self, - set: &'rg OutlivesConstraintSet, + set: &'rg OutlivesConstraintSet<'tcx>, static_region: RegionVid, - ) -> RegionGraph<'rg, D> { + ) -> RegionGraph<'rg, 'tcx, D> { RegionGraph::new(set, self, static_region) } /// Given a region `R`, iterate over all constraints `R: R1`. - crate fn outgoing_edges<'a>( + crate fn outgoing_edges<'a, 'tcx>( &'a self, region_sup: RegionVid, - constraints: &'a OutlivesConstraintSet, + constraints: &'a OutlivesConstraintSet<'tcx>, static_region: RegionVid, - ) -> Edges<'a, D> { + ) -> Edges<'a, 'tcx, D> { //if this is the `'static` region and the graph's direction is normal, //then setup the Edges iterator to return all regions #53178 if region_sup == static_region && D::is_normal() { @@ -129,22 +129,22 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> { } } -crate struct Edges<'s, D: ConstraintGraphDirecton> { +crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { graph: &'s ConstraintGraph<D>, - constraints: &'s OutlivesConstraintSet, + constraints: &'s OutlivesConstraintSet<'tcx>, pointer: Option<OutlivesConstraintIndex>, next_static_idx: Option<usize>, static_region: RegionVid, } -impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { - type Item = OutlivesConstraint; +impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> { + type Item = OutlivesConstraint<'tcx>; fn next(&mut self) -> Option<Self::Item> { if let Some(p) = self.pointer { self.pointer = self.graph.next_constraints[p]; - Some(self.constraints[p]) + Some(self.constraints[p].clone()) } else if let Some(next_static_idx) = self.next_static_idx { self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { None @@ -157,6 +157,7 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { sub: next_static_idx.into(), locations: Locations::All(DUMMY_SP), category: ConstraintCategory::Internal, + variance_info: VarianceDiagInfo::default(), }) } else { None @@ -167,19 +168,19 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> { /// This struct brings together a constraint set and a (normal, not /// reverse) constraint graph. It implements the graph traits and is /// usd for doing the SCC computation. -crate struct RegionGraph<'s, D: ConstraintGraphDirecton> { - set: &'s OutlivesConstraintSet, +crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> { + set: &'s OutlivesConstraintSet<'tcx>, constraint_graph: &'s ConstraintGraph<D>, static_region: RegionVid, } -impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { +impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> { /// Creates a "dependency graph" where each region constraint `R1: /// R2` is treated as an edge `R1 -> R2`. We use this graph to /// construct SCCs for region inference but also for error /// reporting. crate fn new( - set: &'s OutlivesConstraintSet, + set: &'s OutlivesConstraintSet<'tcx>, constraint_graph: &'s ConstraintGraph<D>, static_region: RegionVid, ) -> Self { @@ -188,18 +189,18 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. - crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> { + crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> { Successors { edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), } } } -crate struct Successors<'s, D: ConstraintGraphDirecton> { - edges: Edges<'s, D>, +crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> { + edges: Edges<'s, 'tcx, D>, } -impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> { +impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option<Self::Item> { @@ -207,23 +208,26 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> { } } -impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> { +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> { type Node = RegionVid; } -impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> { +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> { fn num_nodes(&self) -> usize { self.constraint_graph.first_constraints.len() } } -impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> { +impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> { fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter { self.outgoing_regions(node) } } -impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> { +impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> + for RegionGraph<'s, 'tcx, D> +{ type Item = RegionVid; - type Iter = Successors<'graph, D>; + // FIXME - why can't this be `'graph, 'tcx` + type Iter = Successors<'graph, 'graph, D>; } diff --git a/compiler/rustc_mir/src/borrow_check/constraints/mod.rs b/compiler/rustc_mir/src/borrow_check/constraints/mod.rs index 3772b7d8f98..b944479ca45 100644 --- a/compiler/rustc_mir/src/borrow_check/constraints/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/constraints/mod.rs @@ -1,7 +1,7 @@ use rustc_data_structures::graph::scc::Sccs; use rustc_index::vec::IndexVec; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::RegionVid; +use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; use std::fmt; use std::ops::Index; @@ -14,12 +14,12 @@ crate mod graph; /// a unique `OutlivesConstraintIndex` and you can index into the set /// (`constraint_set[i]`) to access the constraint details. #[derive(Clone, Default)] -crate struct OutlivesConstraintSet { - outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint>, +crate struct OutlivesConstraintSet<'tcx> { + outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>, } -impl OutlivesConstraintSet { - crate fn push(&mut self, constraint: OutlivesConstraint) { +impl<'tcx> OutlivesConstraintSet<'tcx> { + crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) { debug!( "OutlivesConstraintSet::push({:?}: {:?} @ {:?}", constraint.sup, constraint.sub, constraint.locations @@ -59,21 +59,21 @@ impl OutlivesConstraintSet { Sccs::new(region_graph) } - crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint> { + crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> { &self.outlives } } -impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet { - type Output = OutlivesConstraint; +impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> { + type Output = OutlivesConstraint<'tcx>; fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output { &self.outlives[i] } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct OutlivesConstraint { +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct OutlivesConstraint<'tcx> { // NB. The ordering here is not significant for correctness, but // it is for convenience. Before we dump the constraints in the // debugging logs, we sort them, and we'd like the "super region" @@ -89,11 +89,18 @@ pub struct OutlivesConstraint { /// What caused this constraint? pub category: ConstraintCategory, + + /// Variance diagnostic information + pub variance_info: VarianceDiagInfo<'tcx>, } -impl fmt::Debug for OutlivesConstraint { +impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "({:?}: {:?}) due to {:?}", self.sup, self.sub, self.locations) + write!( + formatter, + "({:?}: {:?}) due to {:?} ({:?})", + self.sup, self.sub, self.locations, self.variance_info + ) } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 30e0b293ffb..8b0761889b8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -4,10 +4,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; 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}; @@ -1274,7 +1273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 ", diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index 1b0cae51d58..e9f1ecb9bbc 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_span::Span; +use crate::borrow_check::region_infer::BlameConstraint; use crate::borrow_check::{ borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt, WriteKind, @@ -289,12 +290,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_region: RegionVid, outlived_region: RegionVid, ) -> (ConstraintCategory, bool, Span, Option<RegionName>) { - let (category, from_closure, span) = self.regioncx.best_blame_constraint( - &self.body, - borrow_region, - NllRegionVariableOrigin::FreeRegion, - |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), - ); + let BlameConstraint { category, from_closure, span, variance_info: _ } = + self.regioncx.best_blame_constraint( + &self.body, + borrow_region, + NllRegionVariableOrigin::FreeRegion, + |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), + ); let outlived_fr_name = self.give_region_a_name(outlived_region); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 1e2714a2c1b..bf5f2c0eec2 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -1,6 +1,5 @@ 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}; @@ -115,12 +114,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } 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, @@ -478,11 +479,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - 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); } @@ -903,9 +902,13 @@ fn suggest_ampmut<'tcx>( { let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; - return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); + if !ty.trim_start().starts_with("mut") { + return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); + } } else if let Some(stripped) = src.strip_prefix('&') { - return (assignment_rhs_span, format!("&mut {}", stripped)); + if !stripped.trim_start().starts_with("mut") { + return (assignment_rhs_span, format!("&mut {}", stripped)); + } } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index 8665ef06126..feb7672f650 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -13,6 +13,7 @@ use rustc_span::Span; use crate::util::borrowck_errors; +use crate::borrow_check::region_infer::BlameConstraint; use crate::borrow_check::{ nll::ConstraintDescription, region_infer::{values::RegionElement, TypeTest}, @@ -275,12 +276,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let (category, _, span) = + let BlameConstraint { category, span, variance_info, from_closure: _ } = self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); - debug!("report_region_error: category={:?} {:?}", category, span); + debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); @@ -309,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { span, }; - let diag = match (category, fr_is_local, outlived_fr_is_local) { + let mut diag = match (category, fr_is_local, outlived_fr_is_local) { (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => { self.report_fnmut_error(&errci, kind) } @@ -332,6 +333,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; + match variance_info { + ty::VarianceDiagInfo::None => {} + ty::VarianceDiagInfo::Mut { kind, ty } => { + let kind_name = match kind { + ty::VarianceDiagMutKind::Ref => "reference", + ty::VarianceDiagMutKind::RawPtr => "pointer", + }; + diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); + diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); + diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance"); + } + } + diag.buffer(&mut self.errors_buffer); } diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 4c35be39a3d..36eb8a4baa8 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -1965,13 +1965,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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; } } diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs index a0265b20d12..bfeafa33a91 100644 --- a/compiler/rustc_mir/src/borrow_check/nll.rs +++ b/compiler/rustc_mir/src/borrow_check/nll.rs @@ -1,15 +1,14 @@ //! The entry point of the NLL borrow checker. -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::vec_map::VecMap; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, RegionKind, RegionVid}; +use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty}; use rustc_span::symbol::sym; use std::env; use std::fmt::Debug; @@ -47,7 +46,7 @@ crate type PoloniusOutput = Output<RustcFacts>; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, pub polonius_output: Option<Rc<PoloniusOutput>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, pub nll_errors: RegionErrors<'tcx>, @@ -367,7 +366,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, - opaque_type_values: &FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, errors_buffer: &mut Vec<Diagnostic>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs index 3654b51949e..d21550a8e1a 100644 --- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>( 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 } } } diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs index 5892ef37eba..213ebff12ab 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs @@ -74,7 +74,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort(); for constraint in &constraints { - let OutlivesConstraint { sup, sub, locations, category } = constraint; + let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint; let (name, arg) = match locations { Locations::All(span) => { ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs index 7156612f473..b944d74e6f2 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs @@ -35,7 +35,7 @@ struct RawConstraints<'a, 'tcx> { impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { type Node = RegionVid; - type Edge = OutlivesConstraint; + type Edge = OutlivesConstraint<'tcx>; fn graph_id(&'this self) -> dot::Id<'this> { dot::Id::new("RegionInferenceContext").unwrap() @@ -49,31 +49,31 @@ impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> { fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> { dot::LabelText::LabelStr(format!("{:?}", n).into()) } - fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> { + fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> { dot::LabelText::LabelStr(format!("{:?}", e.locations).into()) } } impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> { type Node = RegionVid; - type Edge = OutlivesConstraint; + type Edge = OutlivesConstraint<'tcx>; fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect(); vids.into() } - fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> { + fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> { (&self.regioncx.constraints.outlives().raw[..]).into() } // Render `a: b` as `a -> b`, indicating the flow // of data during inference. - fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid { + fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { edge.sup } - fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid { + fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid { edge.sub } } diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index f4d78ac04cb..dded7a7e3cf 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -54,7 +54,7 @@ pub struct RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues<RegionVid>, /// The outlives constraints computed by the type-check. - constraints: Frozen<OutlivesConstraintSet>, + constraints: Frozen<OutlivesConstraintSet<'tcx>>, /// The constraint-set, but in graph form, making it easy to traverse /// the constraints adjacent to a particular region. Used to construct @@ -227,10 +227,10 @@ enum RegionRelationCheckResult { Error, } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum Trace { +#[derive(Clone, PartialEq, Eq, Debug)] +enum Trace<'tcx> { StartRegion, - FromOutlivesConstraint(OutlivesConstraint), + FromOutlivesConstraint(OutlivesConstraint<'tcx>), NotVisited, } @@ -247,7 +247,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_regions: Rc<UniversalRegions<'tcx>>, placeholder_indices: Rc<PlaceholderIndices>, universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - outlives_constraints: OutlivesConstraintSet, + outlives_constraints: OutlivesConstraintSet<'tcx>, member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< Location, @@ -1750,20 +1750,35 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn retrieve_closure_constraint_info( &self, body: &Body<'tcx>, - constraint: &OutlivesConstraint, - ) -> (ConstraintCategory, bool, Span) { + constraint: &OutlivesConstraint<'tcx>, + ) -> BlameConstraint<'tcx> { let loc = match constraint.locations { - Locations::All(span) => return (constraint.category, false, span), + Locations::All(span) => { + return BlameConstraint { + category: constraint.category, + from_closure: false, + span, + variance_info: constraint.variance_info.clone(), + }; + } Locations::Single(loc) => loc, }; let opt_span_category = self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)); - opt_span_category.map(|&(category, span)| (category, true, span)).unwrap_or(( - constraint.category, - false, - body.source_info(loc).span, - )) + opt_span_category + .map(|&(category, span)| BlameConstraint { + category, + from_closure: true, + span: span, + variance_info: constraint.variance_info.clone(), + }) + .unwrap_or(BlameConstraint { + category: constraint.category, + from_closure: false, + span: body.source_info(loc).span, + variance_info: constraint.variance_info.clone(), + }) } /// Finds a good span to blame for the fact that `fr1` outlives `fr2`. @@ -1774,9 +1789,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory, Span) { - let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| { - self.provides_universal_region(r, fr1, fr2) - }); + let BlameConstraint { category, span, .. } = + self.best_blame_constraint(body, fr1, fr1_origin, |r| { + self.provides_universal_region(r, fr1, fr2) + }); (category, span) } @@ -1792,7 +1808,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, from_region: RegionVid, target_test: impl Fn(RegionVid) -> bool, - ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> { + ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> { let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); context[from_region] = Trace::StartRegion; @@ -1816,14 +1832,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut result = vec![]; let mut p = r; loop { - match context[p] { + match context[p].clone() { Trace::NotVisited => { bug!("found unvisited region {:?} on path to {:?}", p, r) } Trace::FromOutlivesConstraint(c) => { - result.push(c); p = c.sup; + result.push(c); } Trace::StartRegion => { @@ -1846,7 +1862,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Always inline this closure because it can be hot. let mut handle_constraint = #[inline(always)] - |constraint: OutlivesConstraint| { + |constraint: OutlivesConstraint<'tcx>| { debug_assert_eq!(constraint.sup, r); let sub_region = constraint.sub; if let Trace::NotVisited = context[sub_region] { @@ -1870,6 +1886,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { sub: constraint.min_choice, locations: Locations::All(p_c.definition_span), category: ConstraintCategory::OpaqueType, + variance_info: ty::VarianceDiagInfo::default(), }; handle_constraint(constraint); } @@ -1967,7 +1984,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_region: RegionVid, from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, - ) -> (ConstraintCategory, bool, Span) { + ) -> BlameConstraint<'tcx> { debug!( "best_blame_constraint(from_region={:?}, from_region_origin={:?})", from_region, from_region_origin @@ -1979,7 +1996,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "best_blame_constraint: path={:#?}", path.iter() - .map(|&c| format!( + .map(|c| format!( "{:?} ({:?}: {:?})", c, self.constraint_sccs.scc(c.sup), @@ -1989,13 +2006,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); // Classify each of the constraints along the path. - let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path + let mut categorized_path: Vec<BlameConstraint<'tcx>> = path .iter() .map(|constraint| { if constraint.category == ConstraintCategory::ClosureBounds { self.retrieve_closure_constraint_info(body, &constraint) } else { - (constraint.category, false, constraint.locations.span(body)) + BlameConstraint { + category: constraint.category, + from_closure: false, + span: constraint.locations.span(body), + variance_info: constraint.variance_info.clone(), + } } }) .collect(); @@ -2067,12 +2089,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; let find_region = |i: &usize| { - let constraint = path[*i]; + let constraint = &path[*i]; let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup); if blame_source { - match categorized_path[*i].0 { + match categorized_path[*i].category { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation @@ -2083,7 +2105,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { _ => constraint_sup_scc != target_scc, } } else { - match categorized_path[*i].0 { + match categorized_path[*i].category { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation @@ -2103,37 +2125,42 @@ impl<'tcx> RegionInferenceContext<'tcx> { if let Some(i) = best_choice { if let Some(next) = categorized_path.get(i + 1) { - if matches!(categorized_path[i].0, ConstraintCategory::Return(_)) - && next.0 == ConstraintCategory::OpaqueType + if matches!(categorized_path[i].category, ConstraintCategory::Return(_)) + && next.category == ConstraintCategory::OpaqueType { // The return expression is being influenced by the return type being // impl Trait, point at the return type and not the return expr. - return *next; + return next.clone(); } } - if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) { + if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal) + { let field = categorized_path.iter().find_map(|p| { - if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None } + if let ConstraintCategory::ClosureUpvar(f) = p.category { + Some(f) + } else { + None + } }); if let Some(field) = field { - categorized_path[i].0 = + categorized_path[i].category = ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)); } } - return categorized_path[i]; + return categorized_path[i].clone(); } // If that search fails, that is.. unusual. Maybe everything // is in the same SCC or something. In that case, find what // appears to be the most interesting point to report to the // user via an even more ad-hoc guess. - categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0)); + categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category)); debug!("`: sorted_path={:#?}", categorized_path); - *categorized_path.first().unwrap() + categorized_path.remove(0) } } @@ -2228,3 +2255,11 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx .collect() } } + +#[derive(Clone, Debug)] +pub struct BlameConstraint<'tcx> { + pub category: ConstraintCategory, + pub from_closure: bool, + pub span: Span, + pub variance_info: ty::VarianceDiagInfo<'tcx>, +} diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs index 0d1d2551042..3ec24156f22 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs @@ -1,7 +1,6 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; +use rustc_data_structures::vec_map::VecMap; use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; @@ -51,12 +50,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(in crate::borrow_check) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, span: Span, - ) -> FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>> { + ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> { opaque_ty_decls .into_iter() - .map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| { + .map(|(opaque_type_key, concrete_type)| { + let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; @@ -110,16 +110,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?universal_concrete_type, ?universal_substs); + let opaque_type_key = + OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; let remapped_type = infcx.infer_opaque_definition_from_instantiation( - opaque_def_id, - universal_substs, + opaque_type_key, universal_concrete_type, span, ); - ( - opaque_def_id, - ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs }, - ) + (opaque_type_key, remapped_type) }) .collect() } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs index 8513e5e531b..eb11b937143 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs @@ -143,6 +143,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { category: self.category, sub, sup, + variance_info: ty::VarianceDiagInfo::default(), }); } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs index bddcd34ed3e..a34ae281b70 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs @@ -107,7 +107,7 @@ fn compute_live_locals( fn regions_that_outlive_free_regions( num_region_vars: usize, universal_regions: &UniversalRegions<'tcx>, - constraint_set: &OutlivesConstraintSet, + constraint_set: &OutlivesConstraintSet<'tcx>, ) -> FxHashSet<RegionVid> { // Build a graph of the outlives constraints thus far. This is // a reverse graph, so for each constraint `R1: R2` we have an diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index d27fcb2f26f..09cafddeeff 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -7,9 +7,10 @@ use either::Either; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::vec_map::VecMap; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; @@ -27,8 +28,8 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty, - TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, + ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, }; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; @@ -226,7 +227,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); let location_table = cx.location_table; facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map( - |constraint: &OutlivesConstraint| { + |constraint: &OutlivesConstraint<'_>| { if let Some(from_location) = constraint.locations.from_location() { Either::Left(iter::once(( constraint.sup, @@ -572,7 +573,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let locations = location.to_locations(); for constraint in constraints.outlives().iter() { - let mut constraint = *constraint; + let mut constraint = constraint.clone(); constraint.locations = locations; if let ConstraintCategory::Return(_) | ConstraintCategory::UseAsConst @@ -818,7 +819,7 @@ struct TypeChecker<'a, 'tcx> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, - opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, } struct BorrowCheckContext<'a, 'tcx> { @@ -833,7 +834,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>, + crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, } /// A collection of region constraints that must be satisfied for the @@ -862,7 +863,7 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// hence it must report on their liveness constraints. crate liveness_constraints: LivenessValues<RegionVid>, - crate outlives_constraints: OutlivesConstraintSet, + crate outlives_constraints: OutlivesConstraintSet<'tcx>, crate member_constraints: MemberConstraintSet<'tcx, RegionVid>, @@ -978,7 +979,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, - opaque_type_values: FxHashMap::default(), + opaque_type_values: VecMap::default(), }; checker.check_user_type_annotations(); checker @@ -1240,7 +1241,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let param_env = self.param_env; let body = self.body; let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types; - let mut opaque_type_values = Vec::new(); + let mut opaque_type_values = VecMap::new(); debug!("eq_opaque_type_and_type: mir_def_id={:?}", body.source.def_id()); let opaque_type_map = self.fully_perform_op( @@ -1281,37 +1282,39 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - for (&opaque_def_id, opaque_decl) in &opaque_type_map { + for &(opaque_type_key, opaque_decl) in &opaque_type_map { let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty); let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { - *def_id == opaque_def_id + *def_id == opaque_type_key.def_id } else { false }; - let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) { + + let concrete_ty = match concrete_opaque_types + .get_by(|(key, _)| key.def_id == opaque_type_key.def_id) + { None => { if !concrete_is_opaque { tcx.sess.delay_span_bug( body.span, &format!( "Non-defining use of {:?} with revealed type", - opaque_def_id, + opaque_type_key.def_id, ), ); } continue; } - Some(opaque_defn_ty) => opaque_defn_ty, + Some(concrete_ty) => concrete_ty, }; - debug!("opaque_defn_ty = {:?}", opaque_defn_ty); - let subst_opaque_defn_ty = - opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); + debug!("concrete_ty = {:?}", concrete_ty); + let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs); let renumbered_opaque_defn_ty = renumber::renumber_regions(infcx, subst_opaque_defn_ty); debug!( "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", - opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, + concrete_ty, resolved_ty, renumbered_opaque_defn_ty, ); if !concrete_is_opaque { @@ -1322,13 +1325,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .at(&ObligationCause::dummy(), param_env) .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, ); - opaque_type_values.push(( - opaque_def_id, - ty::ResolvedOpaqueTy { - concrete_type: renumbered_opaque_defn_ty, - substs: opaque_decl.substs, - }, - )); + opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty); } else { // We're using an opaque `impl Trait` type without // 'revealing' it. For example, code like this: @@ -1351,7 +1348,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // gets 'revealed' into debug!( "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_def_id, + opaque_type_key.def_id, ); } } @@ -1376,14 +1373,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // prove that `T: Iterator` where `T` is the type we // instantiated it with). if let Some(opaque_type_map) = opaque_type_map { - for (opaque_def_id, opaque_decl) in opaque_type_map { + for (opaque_type_key, opaque_decl) in opaque_type_map { self.fully_perform_op( locations, ConstraintCategory::OpaqueType, CustomTypeOp::new( |_cx| { infcx.constrain_opaque_type( - opaque_def_id, + opaque_type_key, &opaque_decl, GenerateMemberConstraints::IfNoStaticBound, universal_region_relations, @@ -2535,6 +2532,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sub: borrow_region.to_region_vid(), locations: location.to_locations(), category, + variance_info: ty::VarianceDiagInfo::default(), }); match mutbl { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs index 249945f04b7..f97252a117a 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs @@ -94,7 +94,12 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { ) } - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + fn push_outlives( + &mut self, + sup: ty::Region<'tcx>, + sub: ty::Region<'tcx>, + info: ty::VarianceDiagInfo<'tcx>, + ) { if let Some(borrowck_context) = &mut self.borrowck_context { let sub = borrowck_context.universal_regions.to_region_vid(sub); let sup = borrowck_context.universal_regions.to_region_vid(sup); @@ -103,6 +108,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { sub, locations: self.locations, category: self.category, + variance_info: info, }); } } diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 754ed0bea84..fc21047ab72 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol}; 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. @@ -24,12 +24,21 @@ pub enum ConstEvalErrKind { 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() } } @@ -148,31 +157,10 @@ impl<'tcx> ConstEvalErr<'tcx> { 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); } @@ -186,34 +174,50 @@ impl<'tcx> ConstEvalErr<'tcx> { 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) } } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index d51adc8864d..460fea37461 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; 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 { @@ -169,8 +170,9 @@ pub(super) fn op_to_const<'tcx>( (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, ), }; @@ -327,11 +329,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>( )) } 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) => { diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 8e9148f5b66..773df7d7b60 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi; 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::*; @@ -223,7 +223,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _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); @@ -263,7 +263,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 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)? { diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 1bfbb843114..cea465ea1ed 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -519,10 +519,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // 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; } } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index e9dd7a3fe68..6f7519e6156 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -134,14 +134,25 @@ pub struct FrameInfo<'tcx> { 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 @@ -746,13 +757,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// *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 @@ -801,21 +819,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + 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(()); @@ -834,16 +851,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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. diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 99622fb310a..4e4166dad50 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -56,8 +56,12 @@ crate fn eval_nullary_intrinsic<'tcx>( let alloc = type_name::alloc_type_name(tcx, tp_ty); ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } - sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)), + sym::needs_drop => { + ensure_monomorphic_enough(tcx, tp_ty)?; + ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) + } sym::min_align_of | sym::pref_align_of => { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; let n = match name { sym::pref_align_of => layout.align.pref.bytes(), @@ -71,6 +75,7 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::from_u64(tcx.type_id_hash(tp_ty)) } sym::variant_count => match tp_ty.kind() { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx), ty::Projection(_) | ty::Opaque(_, _) diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs index 2b996cf62a3..792a4749108 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs @@ -1,5 +1,6 @@ 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; @@ -79,7 +80,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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); diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index ae5e78ee33f..a7012cd63f3 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -1,5 +1,5 @@ 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, @@ -88,7 +88,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } 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) } @@ -127,11 +127,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { ) -> 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) @@ -197,6 +192,6 @@ impl Write for AbsolutePathPrinter<'_> { /// 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) } diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index e7d7c38cc8f..0d01dc3c219 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -14,7 +14,7 @@ use rustc_target::spec::abi::Abi; 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, @@ -132,6 +132,11 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether function calls should be [ABI](Abi)-checked. + fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + true + } + /// Entry point for obtaining the MIR of anything that should get evaluated. /// So not just functions and shims, but also const/static initializers, anonymous /// constants, ... @@ -158,7 +163,7 @@ pub trait Machine<'mir, 'tcx>: Sized { 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 @@ -169,7 +174,7 @@ pub trait Machine<'mir, 'tcx>: Sized { 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 @@ -179,7 +184,7 @@ pub trait Machine<'mir, 'tcx>: Sized { 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. @@ -451,7 +456,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _abi: Abi, _args: &[OpTy<$tcx>], _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>, - _unwind: Option<mir::BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<$tcx> { match fn_val {} } diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 7fb7c51b0b5..77de19ac674 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -219,9 +219,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { 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) } @@ -321,6 +323,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } }; + 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", @@ -625,9 +630,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // 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", @@ -673,8 +675,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn get_alloc_extra_mut<'a>( &'a mut self, id: AllocId, - ) -> InterpResult<'tcx, &'a mut M::AllocExtra> { - Ok(&mut self.get_raw_mut(id)?.0.extra) + ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> { + let (alloc, memory_extra) = self.get_raw_mut(id)?; + Ok((&mut alloc.extra, memory_extra)) } /// Obtain the size and alignment of an allocation, even if that allocation has diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs index 9b95f691167..2b9fe565997 100644 --- a/compiler/rustc_mir/src/interpret/mod.rs +++ b/compiler/rustc_mir/src/interpret/mod.rs @@ -18,7 +18,9 @@ mod visitor; 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}; diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index ef603b51554..4c53510ed00 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; 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}; @@ -14,9 +15,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; 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)] @@ -291,8 +292,6 @@ where // 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()`. @@ -1024,18 +1023,23 @@ where 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 } } diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index a7fcb41f74a..a5bdeb55e78 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -1,7 +1,8 @@ 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, @@ -12,9 +13,19 @@ use rustc_target::spec::abi::Abi; 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>, @@ -58,12 +69,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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); @@ -72,6 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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!( @@ -89,7 +105,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } 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 { @@ -219,7 +245,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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); @@ -230,14 +256,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; + 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> { - 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 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. @@ -258,7 +285,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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) } @@ -279,7 +308,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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, @@ -469,7 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Rust, &[arg.into()], Some((&dest.into(), target)), - unwind, + match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, ) } } diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 11f8d388820..9a59161f08f 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -137,9 +137,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { - throw_ub!(InvalidDropFn(fn_sig)); + throw_ub!(InvalidVtableDropFn(fn_sig)); } - let ty = args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))?.ty; + let ty = + args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty; Ok((drop_instance, ty)) } @@ -158,13 +159,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap(); let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?; let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap(); + let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?; if size >= self.tcx.data_layout.obj_size_bound() { - throw_ub_format!( - "invalid vtable: \ - size is bigger than largest supported object" - ); + throw_ub!(InvalidVtableSize); } - Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap())) + Ok((Size::from_bytes(size), align)) } } diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index fb165a991bc..112cba3efda 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -26,23 +26,24 @@ use super::{ macro_rules! throw_validation_failure { ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{ - let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| { - let mut msg = String::new(); - msg.push_str("encountered "); - write!(&mut msg, $($what_fmt),+).unwrap(); + let mut msg = String::new(); + msg.push_str("encountered "); + write!(&mut msg, $($what_fmt),+).unwrap(); + $( + msg.push_str(", but expected "); + write!(&mut msg, $($expected_fmt),+).unwrap(); + )? + let path = rustc_middle::ty::print::with_no_trimmed_paths(|| { let where_ = &$where; if !where_.is_empty() { - msg.push_str(" at "); - write_path(&mut msg, where_); + let mut path = String::new(); + write_path(&mut path, where_); + Some(path) + } else { + None } - $( - msg.push_str(", but expected "); - write!(&mut msg, $($expected_fmt),+).unwrap(); - )? - - msg }); - throw_ub!(ValidationFailure(msg)) + throw_ub!(ValidationFailure { path, msg }) }}; } @@ -349,12 +350,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' err_ub!(InvalidFunctionPointer(..)) | err_unsup!(ReadBytesAsPointer) => { "invalid drop function pointer in vtable (not pointing to a function)" }, - err_ub!(InvalidDropFn(..)) => + err_ub!(InvalidVtableDropFn(..)) => { "invalid drop function pointer in vtable (function has incompatible signature)" }, ); try_validation!( self.ecx.read_size_and_align_from_vtable(vtable), self.path, + err_ub!(InvalidVtableSize) => + { "invalid vtable: size is bigger than largest supported object" }, + err_ub!(InvalidVtableAlignment(msg)) => + { "invalid vtable: alignment {}", msg }, err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, ); // FIXME: More checks for the vtable. diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 69585979d41..1da17bddcb7 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -12,16 +12,14 @@ Rust MIR: a lowered representation of Rust. #![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(format_args_capture)] #![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)] @@ -29,7 +27,6 @@ Rust MIR: a lowered representation of Rust. #![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"] diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index ef79f36b3b5..31cb5484bce 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -184,7 +184,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; 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; @@ -194,6 +194,7 @@ use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; 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}; @@ -342,7 +343,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< .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>>, @@ -359,6 +361,31 @@ fn collect_items_rec<'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); @@ -411,6 +438,20 @@ fn collect_items_rec<'tcx>( } } + // 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 { diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 16f5f14f563..dcbc9c523dc 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -541,30 +541,6 @@ impl NonConstOp for UnionAccess { } } -/// See [#64992]. -/// -/// [#64992]: https://github.com/rust-lang/rust/issues/64992 -#[derive(Debug)] -pub struct UnsizingCast; -impl NonConstOp for UnsizingCast { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_unsize) - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_unsize, - span, - "unsizing casts to types besides slices are not allowed in const fn", - ) - } -} - // Types that cannot appear in the signature or locals of a `const fn`. pub mod ty { use super::*; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 63fc66f2b9f..4fbd27c89d9 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -10,9 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{ - self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, -}; +use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; @@ -358,10 +356,9 @@ impl Validator<'mir, 'tcx> { } 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) } @@ -636,17 +633,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { _, ) => self.check_op(ops::FnPtrCast), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => { - if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { - let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); - - // Casting/coercing things to slices is fine. - if let ty::Slice(_) | ty::Str = unsized_ty.kind() { - return; - } - } - - self.check_op(ops::UnsizingCast); + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { + // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur + // in the type of any local, which also excludes casts). } Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { @@ -740,13 +729,11 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; if let ty::RawPtr(_) = base_ty.kind() { if proj_base.is_empty() { - if let (local, []) = (place_local, proj_base) { - let decl = &self.body.local_decls[local]; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { - let span = decl.source_info.span; - self.check_static(def_id, span); - return; - } + let decl = &self.body.local_decls[place_local]; + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { + let span = decl.source_info.span; + self.check_static(def_id, span); + return; } } self.check_op(ops::RawPtrDeref); @@ -763,12 +750,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | 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); } } } diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 955be8cc81e..103ddda1a1d 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } 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 @@ -376,6 +376,12 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { /// 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; diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs index b5c8b4bebc3..ba10b54c5ae 100644 --- a/compiler/rustc_mir/src/transform/const_goto.rs +++ b/compiler/rustc_mir/src/transform/const_goto.rs @@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // 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); } } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 5968bbbfca7..681d63c6fc9 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -33,6 +33,7 @@ use crate::interpret::{ 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; @@ -198,7 +199,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _abi: Abi, _args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, - _unwind: Option<BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { Ok(None) } @@ -208,7 +209,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _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") } diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index 2397d627880..f6672335cb1 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -116,7 +116,6 @@ use crate::util::pretty; 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; diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs index c41e71e09a4..912505c6598 100644 --- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 29df86ca6cd..4f5a467a6ee 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -114,7 +114,7 @@ use rustc_middle::mir::{ 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 @@ -910,17 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { // 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 { @@ -930,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { } place_ty = place_ty.projection_ty(self.tcx, elem); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return; } } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 7934d4ba849..07127042fa4 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // 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); } } } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 003003a8abb..3560b4b1e86 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>( // 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(())); @@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>( // 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(())); } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index b6f80763bc8..f1c95a84ade 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline { if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs index 7aaf0224164..b64189a7f3c 100644 --- a/compiler/rustc_mir/src/transform/instcombine.rs +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -4,7 +4,7 @@ use crate::transform::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::{ BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, - StatementKind, + StatementKind, UnOp, }; use rustc_middle::ty::{self, TyCtxt}; @@ -47,28 +47,35 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> { Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => { let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) { // Transform "Eq(a, true)" ==> "a" - (BinOp::Eq, _, Some(true)) => Some(a.clone()), + (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())), // Transform "Ne(a, false)" ==> "a" - (BinOp::Ne, _, Some(false)) => Some(a.clone()), + (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())), // Transform "Eq(true, b)" ==> "b" - (BinOp::Eq, Some(true), _) => Some(b.clone()), + (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())), // Transform "Ne(false, b)" ==> "b" - (BinOp::Ne, Some(false), _) => Some(b.clone()), + (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())), - // FIXME: Consider combining remaining comparisons into logical operations: // Transform "Eq(false, b)" ==> "Not(b)" + (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + // Transform "Ne(true, b)" ==> "Not(b)" + (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())), + // Transform "Eq(a, false)" ==> "Not(a)" + (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + // Transform "Ne(a, true)" ==> "Not(a)" + (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())), + _ => None, }; if let Some(new) = new { if self.should_combine(source_info, rvalue) { - *rvalue = Rvalue::Use(new); + *rvalue = new; } } } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index f7a9835353e..21b208a08c2 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index 4aaa0baa9f4..cd2db180552 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } } - simplify::remove_dead_blocks(body) + simplify::remove_dead_blocks(tcx, body) } } diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index f6b1323e107..78e84419c62 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -415,11 +415,9 @@ impl<'tcx> Validator<'_, 'tcx> { 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); } } } diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 5144d48750d..02e45021a0a 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // 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); } } } diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs index 70f7538dd57..40b1a8a2da9 100644 --- a/compiler/rustc_mir/src/transform/remove_zsts.rs +++ b/compiler/rustc_mir/src/transform/remove_zsts.rs @@ -16,32 +16,29 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for block in basic_blocks.iter_mut() { for statement in block.statements.iter_mut() { - match statement.kind { - StatementKind::Assign(box (place, _)) => { - let place_ty = place.ty(local_decls, tcx).ty; - if !maybe_zst(place_ty) { - continue; - } - let layout = match tcx.layout_of(param_env.and(place_ty)) { - Ok(layout) => layout, - Err(_) => continue, - }; - if !layout.is_zst() { - continue; - } - if involves_a_union(place, local_decls, tcx) { - continue; - } - if tcx.consider_optimizing(|| { - format!( - "RemoveZsts - Place: {:?} SourceInfo: {:?}", - place, statement.source_info - ) - }) { - statement.make_nop(); - } + if let StatementKind::Assign(box (place, _)) = statement.kind { + let place_ty = place.ty(local_decls, tcx).ty; + if !maybe_zst(place_ty) { + continue; + } + let layout = match tcx.layout_of(param_env.and(place_ty)) { + Ok(layout) => layout, + Err(_) => continue, + }; + if !layout.is_zst() { + continue; + } + if involves_a_union(place, local_decls, tcx) { + continue; + } + if tcx.consider_optimizing(|| { + format!( + "RemoveZsts - Place: {:?} SourceInfo: {:?}", + place, statement.source_info + ) + }) { + statement.make_nop(); } - _ => {} } } } @@ -69,21 +66,14 @@ fn involves_a_union<'tcx>( 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, - } -} diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 65e2d096b20..7aebca77e6f 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -29,6 +29,7 @@ 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; @@ -46,9 +47,9 @@ impl SimplifyCfg { } } -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(); @@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { 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); } } @@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } -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() { @@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } 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 { @@ -315,6 +321,75 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } } +/// 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 { diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 89fddc95c98..dd2ec39c066 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { if did_remove_blocks { // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index 658c6b6e9db..e7fb6b4f6b4 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -60,7 +60,7 @@ impl MirPass<'_> for UnreachablePropagation { } if replaced { - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index d009b0b1b23..835789069bb 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -11,8 +11,9 @@ use rustc_middle::mir::interpret::Scalar; 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}; @@ -217,6 +218,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { 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)) => { diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs index 6ce305a4821..770b52a4d4b 100644 --- a/compiler/rustc_mir/src/util/generic_graph.rs +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -1,6 +1,5 @@ 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; diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index ea3a5174fd8..8426b24270d 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,8 +1,8 @@ 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; diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 796a90713ba..5e305ebba2f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,8 +1,8 @@ //! 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> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 1c439aad394..b2a1dbf4c52 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -2,9 +2,9 @@ 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 diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 96df77a65da..5511cd4c73b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -3,13 +3,13 @@ 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; @@ -209,9 +209,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( 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(); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 92a2a7bc17a..69786c14ee8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -5,11 +5,11 @@ use rustc_index::vec::Idx; 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; @@ -185,6 +185,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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])); @@ -446,7 +447,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // Not in a closure debug_assert!( - local == Local::new(1), + local == ty::CAPTURE_STRUCT_LOCAL, "Expected local to be Local(1), found {:?}", local ); diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 96bf3e6d69d..45e0243c88a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -2,10 +2,10 @@ 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 diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index 9320b5810e3..c834ce6ce68 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -1,4 +1,4 @@ -use crate::thir::*; +use rustc_middle::thir::*; #[derive(Debug, PartialEq)] crate enum Category { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index d7c8a07103e..f2b00f0f6ed 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -2,13 +2,13 @@ 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; @@ -337,8 +337,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 { diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index d2442f33b0c..b03a6bb1a2b 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -1,8 +1,8 @@ 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`. diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index c30193b5a5a..8164529dd1f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -10,7 +10,6 @@ use crate::build::scope::DropKind; 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, @@ -19,6 +18,7 @@ use rustc_hir::HirId; 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; @@ -432,7 +432,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .. }, 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); @@ -687,7 +687,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 // diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 3ad143a57ff..13cfc3695cc 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,8 +15,8 @@ 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}; @@ -152,7 +152,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index b082169cd63..c87f42738c6 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -9,11 +9,11 @@ use crate::build::expr::as_place::PlaceBuilder; 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}; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d49a00a5660..3cf8ae6efd9 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,8 +1,8 @@ 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; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 4f6c57be2da..10d6521e7de 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,7 +1,7 @@ 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; @@ -13,6 +13,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; 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}; @@ -45,6 +46,16 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ 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, _, _), .. }) => { @@ -104,7 +115,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ }; 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() { @@ -212,8 +226,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ 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) }; @@ -937,9 +953,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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; @@ -985,7 +1000,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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), }), }); @@ -1016,7 +1031,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e79a19d57ac..3de894bd370 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -82,11 +82,12 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ 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)] diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8c2c81c8628..2d52577829c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,14 +1,17 @@ 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; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::symbol::Symbol; use rustc_span::Span; +use std::ops::Bound; + struct UnsafetyVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, thir: &'a Thir<'tcx>, @@ -19,6 +22,10 @@ struct UnsafetyVisitor<'a, 'tcx> { /// `unsafe` block, and whether it has been used. safety_context: SafetyContext, body_unsafety: BodyUnsafety, + /// The `#[target_feature]` attributes of the body. Used for checking + /// calls to functions with `#[target_feature]` (RFC 2396). + body_target_features: &'tcx Vec<Symbol>, + is_const: bool, } impl<'tcx> UnsafetyVisitor<'_, 'tcx> { @@ -35,7 +42,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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 { @@ -45,7 +52,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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; @@ -65,16 +80,20 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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 { "" }; @@ -97,18 +116,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { &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(); }); @@ -148,11 +164,82 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => { if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe { 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`. 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); + } + } + } + ExprKind::Deref { arg } => { + if let ExprKind::StaticRef { def_id, .. } = self.thir[arg].kind { + if self.tcx.is_mutable_static(def_id) { + self.requires_unsafe(expr.span, UseOfMutableStatic); + } else if self.tcx.is_foreign_item(def_id) { + self.requires_unsafe(expr.span, UseOfExternStatic); + } + } else if self.thir[arg].ty.is_unsafe_ptr() { + self.requires_unsafe(expr.span, DerefOfRawPointer); } } ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => { self.requires_unsafe(expr.span, UseOfInlineAssembly); } + ExprKind::Adt { + adt_def, + variant_index: _, + substs: _, + user_ty: _, + fields: _, + base: _, + } => match self.tcx.layout_scalar_valid_range(adt_def.did) { + (Bound::Unbounded, Bound::Unbounded) => {} + _ => self.requires_unsafe(expr.span, InitializingTypeWith), + }, + ExprKind::Cast { source } => { + let source = &self.thir[source]; + if self.tcx.features().const_raw_ptr_to_usize_cast + && self.is_const + && (source.ty.is_unsafe_ptr() || source.ty.is_fn_ptr()) + && expr.ty.is_integral() + { + 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; + } _ => {} } @@ -195,15 +282,10 @@ impl BodyUnsafety { enum UnsafeOpKind { CallToUnsafeFunction, UseOfInlineAssembly, - #[allow(dead_code)] // FIXME InitializingTypeWith, - #[allow(dead_code)] // FIXME CastOfPointerToInt, - #[allow(dead_code)] // FIXME UseOfMutableStatic, - #[allow(dead_code)] // FIXME UseOfExternStatic, - #[allow(dead_code)] // FIXME DerefOfRawPointer, #[allow(dead_code)] // FIXME AssignToDroppingUnionField, @@ -213,7 +295,6 @@ enum UnsafeOpKind { MutationOfLayoutConstrainedField, #[allow(dead_code)] // FIXME BorrowOfLayoutConstrainedField, - #[allow(dead_code)] // FIXME CallToFunctionWith, } @@ -251,7 +332,7 @@ impl UnsafeOpKind { ), 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 => ( @@ -281,14 +362,26 @@ impl UnsafeOpKind { } } -// 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, - 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) @@ -296,29 +389,31 @@ pub fn check_unsafety<'tcx>( BodyUnsafety::Safe } }); + 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 mut visitor = - UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, body_unsafety }; + let is_const = match tcx.hir().body_owner_kind(hir_id) { + hir::BodyOwnerKind::Closure => false, + hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()), + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true, + }; + let mut visitor = UnsafetyVisitor { + tcx, + thir, + safety_context, + hir_context: hir_id, + body_unsafety, + body_target_features, + is_const, + }; 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, 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)) } } @@ -326,5 +421,5 @@ crate fn thir_check_unsafety_for_const_arg<'tcx>( 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) }) } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index d4e9a0a3169..d2992f0bf18 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,16 +1,14 @@ //! 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] @@ -31,4 +29,5 @@ pub fn provide(providers: &mut Providers) { 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; } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index ac93d042970..d62fd161e2f 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -25,14 +25,14 @@ crate fn lit_to_const<'tcx>( 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() } } diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index b90f9abe33a..77235fe9ab3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -1,8 +1,8 @@ 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; @@ -81,7 +81,7 @@ impl<'tcx> Cx<'tcx> { 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, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 9cc7fbdf824..aa4acfab5c8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,6 +1,5 @@ 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}; @@ -8,14 +7,18 @@ use rustc_index::vec::Idx; 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 { diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index aad6319e404..49ba71e3520 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -2,25 +2,32 @@ //! 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> { @@ -79,7 +86,7 @@ impl<'tcx> 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) } } diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index d188d17dd56..e5123d8ef0c 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -4,438 +4,11 @@ //! 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, - }, -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e4419070cbd..389a7595315 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,8 +1,8 @@ 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; @@ -12,6 +12,7 @@ use rustc_hir::def::*; 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}; @@ -344,7 +345,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa /// 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), @@ -514,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>( 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, \ diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index c0624c805a6..369fff00456 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -2,6 +2,7 @@ use rustc_hir as hir; 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; @@ -12,7 +13,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; 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). diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index db0f487645f..4b5b648c504 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -46,8 +46,7 @@ use self::Constructor::*; 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; @@ -55,6 +54,7 @@ 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; @@ -1245,13 +1245,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { // 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() }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9ac79a37ac6..3225d302cb3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ use crate::thir::util::UserAnnotatedTyHelpers; 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; @@ -19,16 +19,12 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; 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 { @@ -39,317 +35,6 @@ 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>, @@ -358,22 +43,20 @@ crate struct PatCtxt<'a, '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> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index dce0df8473b..5d4eb75155a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -284,7 +284,6 @@ use self::Usefulness::*; use self::WitnessPreference::*; use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; -use super::{Pat, PatKind}; use super::{PatternFoldable, PatternFolder}; use rustc_data_structures::captures::Captures; @@ -293,6 +292,7 @@ use rustc_data_structures::fx::FxHashMap; 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; @@ -382,31 +382,29 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander { } } -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]` @@ -451,7 +449,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // 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 @@ -525,7 +523,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// 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); } @@ -760,7 +758,7 @@ impl<'p, 'tcx> SubPatSet<'p, 'tcx> { } } 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() { @@ -1118,7 +1116,7 @@ fn is_useful<'p, 'tcx>( 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(); @@ -1174,7 +1172,7 @@ fn is_useful<'p, 'tcx>( #[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, } @@ -1196,7 +1194,7 @@ crate struct UsefulnessReport<'p, 'tcx> { 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 @@ -1232,7 +1230,7 @@ crate fn compute_match_usefulness<'p, 'tcx>( }) .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 { diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs index 671d1fe9b03..1a60b1de7fd 100644 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ b/compiler/rustc_mir_build/src/thir/visit.rs @@ -1,4 +1,5 @@ -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>; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 077b19fa959..51df06bd989 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,8 +3,6 @@ #![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"] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ee6ff4dba39..8b050389078 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -32,7 +32,6 @@ impl<'a> Parser<'a> { let mut just_parsed_doc_comment = false; let start_pos = self.token_cursor.num_next_calls; loop { - debug!("parse_outer_attributes: self.token={:?}", self.token); let attr = if self.check(&token::Pound) { let inner_error_reason = if just_parsed_doc_comment { "an inner attribute is not permitted following an outer doc comment" diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 35759a396e8..e1d0b84f419 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -342,16 +342,10 @@ impl<'a> Parser<'a> { // If we support tokens at all if let Some(target_tokens) = ret.tokens_mut() { - if let Some(target_tokens) = target_tokens { - assert!( - !self.capture_cfg, - "Encountered existing tokens with capture_cfg set: {:?}", - target_tokens - ); - } else { + if target_tokens.is_none() { // Store se our newly captured tokens into the AST node *target_tokens = Some(tokens.clone()); - }; + } } let final_attrs = ret.attrs(); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 72fdc78c30c..b37caaebfb6 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -366,7 +366,7 @@ impl<'a> Parser<'a> { let mut snapshot = self.clone(); let path = Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None }; - let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false); + let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false); let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No); return Some(match (struct_expr, block_tail) { (Ok(expr), Err(mut err)) => { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 56c97b59476..c8789abc142 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -94,17 +94,7 @@ impl<'a> Parser<'a> { /// Parses an expression, forcing tokens to be collected pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> { - // If we have outer attributes, then the call to `collect_tokens_trailing_token` - // will be made for us. - if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) { - self.parse_expr() - } else { - // If we don't have outer attributes, then we need to ensure - // that collection happens by using `collect_tokens_no_attrs`. - // Expression don't support custom inner attributes, so `parse_expr` - // will never try to collect tokens if we don't have outer attributes. - self.collect_tokens_no_attrs(|this| this.parse_expr()) - } + self.collect_tokens_no_attrs(|this| this.parse_expr()) } pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> { @@ -1118,9 +1108,6 @@ impl<'a> Parser<'a> { self.parse_closure_expr(attrs) } else if self.check(&token::OpenDelim(token::Bracket)) { self.parse_array_or_repeat_expr(attrs) - } else if self.eat_lt() { - let (qself, path) = self.parse_qpath(PathStyle::Expr)?; - Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) } else if self.check_path() { self.parse_path_start_expr(attrs) } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { @@ -1272,12 +1259,20 @@ impl<'a> Parser<'a> { } fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { - let path = self.parse_path(PathStyle::Expr)?; + let (qself, path) = if self.eat_lt() { + let (qself, path) = self.parse_qpath(PathStyle::Expr)?; + (Some(qself), path) + } else { + (None, self.parse_path(PathStyle::Expr)?) + }; let lo = path.span; // `!`, as an operator, is prefix, so we know this isn't that. let (hi, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression + if qself.is_some() { + self.struct_span_err(path.span, "macros cannot use qualified paths").emit(); + } let mac = MacCall { path, args: self.parse_mac_args()?, @@ -1285,13 +1280,16 @@ impl<'a> Parser<'a> { }; (self.prev_token.span, ExprKind::MacCall(mac)) } else if self.check(&token::OpenDelim(token::Brace)) { - if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) { + if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) { + if qself.is_some() { + self.sess.gated_spans.gate(sym::more_qualified_paths, path.span); + } return expr; } else { - (path.span, ExprKind::Path(None, path)) + (path.span, ExprKind::Path(qself, path)) } } else { - (path.span, ExprKind::Path(None, path)) + (path.span, ExprKind::Path(qself, path)) }; let expr = self.mk_expr(lo.to(hi), kind, attrs); @@ -2257,6 +2255,7 @@ impl<'a> Parser<'a> { fn maybe_parse_struct_expr( &mut self, + qself: Option<&ast::QSelf>, path: &ast::Path, attrs: &AttrVec, ) -> Option<PResult<'a, P<Expr>>> { @@ -2265,7 +2264,7 @@ impl<'a> Parser<'a> { if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) { return Some(Err(err)); } - let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true); + let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true); if let (Ok(expr), false) = (&expr, struct_allowed) { // This is a struct literal, but we don't can't accept them here. self.error_struct_lit_not_allowed_here(path.span, expr.span); @@ -2288,6 +2287,7 @@ impl<'a> Parser<'a> { /// Precondition: already parsed the '{'. pub(super) fn parse_struct_expr( &mut self, + qself: Option<ast::QSelf>, pth: ast::Path, attrs: AttrVec, recover: bool, @@ -2385,7 +2385,7 @@ impl<'a> Parser<'a> { let expr = if recover_async { ExprKind::Err } else { - ExprKind::Struct(P(ast::StructExpr { path: pth, fields, rest: base })) + ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base })) }; Ok(self.mk_expr(span, expr, attrs)) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c64fab0507c..54e6ff6272c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1474,7 +1474,10 @@ impl<'a> Parser<'a> { 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), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4c2bc6ebf31..cd9f84db5e5 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -63,6 +63,7 @@ enum BlockMode { /// Whether or not we should force collection of tokens for an AST node, /// regardless of whether or not it has attributes +#[derive(Clone, Copy, PartialEq)] pub enum ForceCollect { Yes, No, diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 0c43e304f1e..30a6b61407f 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,5 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Nonterminal, NonterminalKind, Token}; +use rustc_ast::AstLike; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; @@ -102,7 +103,7 @@ impl<'a> Parser<'a> { // which requires having captured tokens available. Since we cannot determine // in advance whether or not a proc-macro will be (transitively) invoked, // we always capture tokens for any `Nonterminal` which needs them. - Ok(match kind { + let mut nt = match kind { NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { Some(item) => token::NtItem(item), None => { @@ -169,7 +170,19 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, msg)); } } - }) + }; + + // If tokens are supported at all, they should be collected. + if matches!(nt.tokens_mut(), Some(None)) { + panic!( + "Missing tokens for nt {:?} at {:?}: {:?}", + nt, + nt.span(), + pprust::nonterminal_to_string(&nt) + ); + } + + Ok(nt) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0abefbd6a12..418122202be 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -859,7 +859,8 @@ impl<'a> Parser<'a> { /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> { if qself.is_some() { - return self.error_qpath_before_pat(&path, "{"); + // Feature gate the use of qualified paths in patterns + self.sess.gated_spans.gate(sym::more_qualified_paths, path.span); } self.bump(); let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { @@ -869,27 +870,17 @@ impl<'a> Parser<'a> { (vec![], true) }); self.bump(); - Ok(PatKind::Struct(path, fields, etc)) + Ok(PatKind::Struct(qself, path, fields, etc)) } /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`). fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> { - if qself.is_some() { - return self.error_qpath_before_pat(&path, "("); - } let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_allow_top_alt(None, RecoverComma::No))?; - Ok(PatKind::TupleStruct(path, fields)) - } - - /// Error when there's a qualified path, e.g. `<Foo as Bar>::Baz` - /// as the path of e.g., a tuple or record struct pattern. - fn error_qpath_before_pat(&mut self, path: &Path, token: &str) -> PResult<'a, PatKind> { - let msg = &format!("unexpected `{}` after qualified path", token); - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, msg); - err.span_label(path.span, "the qualified path"); - Err(err) + if qself.is_some() { + self.sess.gated_spans.gate(sym::more_qualified_paths, path.span); + } + Ok(PatKind::TupleStruct(qself, path, fields)) } /// Parses the fields of a struct-like pattern. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9cc600d9ede..953c6915068 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -352,49 +352,59 @@ impl<'a> Parser<'a> { debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); match self.parse_angle_args() { Ok(args) => Ok(args), - Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { - // Cancel error from being unable to find `>`. We know the error - // must have been this due to a non-zero unmatched angle bracket - // count. - e.cancel(); - + Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { // Swap `self` with our backup of the parser state before attempting to parse // generic arguments. let snapshot = mem::replace(self, snapshot.unwrap()); - debug!( - "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ - snapshot.count={:?}", - snapshot.unmatched_angle_bracket_count, - ); - // Eat the unmatched angle brackets. - for _ in 0..snapshot.unmatched_angle_bracket_count { - self.eat_lt(); - } - - // Make a span over ${unmatched angle bracket count} characters. - let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); - self.struct_span_err( - span, - &format!( - "unmatched angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - ) - .span_suggestion( - span, - &format!( - "remove extra angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count) + .fold(true, |a, _| a && self.eat_lt()); + + if !all_angle_brackets { + // If there are other tokens in between the extraneous `<`s, we cannot simply + // suggest to remove them. This check also prevents us from accidentally ending + // up in the middle of a multibyte character (issue #84104). + let _ = mem::replace(self, snapshot); + Err(e) + } else { + // Cancel error from being unable to find `>`. We know the error + // must have been this due to a non-zero unmatched angle bracket + // count. + e.cancel(); + + debug!( + "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \ + snapshot.count={:?}", + snapshot.unmatched_angle_bracket_count, + ); + + // Make a span over ${unmatched angle bracket count} characters. + // This is safe because `all_angle_brackets` ensures that there are only `<`s, + // i.e. no multibyte characters, in this range. + let span = + lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); + self.struct_span_err( + span, + &format!( + "unmatched angle bracket{}", + pluralize!(snapshot.unmatched_angle_bracket_count) + ), + ) + .span_suggestion( + span, + &format!( + "remove extra angle bracket{}", + pluralize!(snapshot.unmatched_angle_bracket_count) + ), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); - // Try again without unmatched angle bracket characters. - self.parse_angle_args() + // Try again without unmatched angle bracket characters. + self.parse_angle_args() + } } Err(e) => Err(e), } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index b40eed8c5d1..9ef3f61ec34 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -73,7 +73,11 @@ impl<'a> Parser<'a> { // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. // Also, we avoid stealing syntax from `parse_item_`. - self.parse_stmt_path_start(lo, attrs, force_collect)? + if force_collect == ForceCollect::Yes { + self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs)) + } else { + self.parse_stmt_path_start(lo, attrs) + }? } else if let Some(item) = self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)? { @@ -85,7 +89,13 @@ impl<'a> Parser<'a> { self.mk_stmt(lo, StmtKind::Empty) } else if self.token != token::CloseDelim(token::Brace) { // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?; + let e = if force_collect == ForceCollect::Yes { + self.collect_tokens_no_attrs(|this| { + this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs)) + }) + } else { + self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs)) + }?; self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) } else { self.error_outer_attrs(&attrs.take_for_recovery()); @@ -93,13 +103,8 @@ impl<'a> Parser<'a> { })) } - fn parse_stmt_path_start( - &mut self, - lo: Span, - attrs: AttrWrapper, - force_collect: ForceCollect, - ) -> PResult<'a, Stmt> { - let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { + fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> { + let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let path = this.parse_path(PathStyle::Expr)?; if this.eat(&token::Not) { @@ -112,7 +117,7 @@ impl<'a> Parser<'a> { } let expr = if this.eat(&token::OpenDelim(token::Brace)) { - this.parse_struct_expr(path, AttrVec::new(), true)? + this.parse_struct_expr(None, path, AttrVec::new(), true)? } else { let hi = this.prev_token.span; this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 89cf2d7876e..de5a5632600 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -334,7 +334,6 @@ impl<'a> Parser<'a> { mut bounds: GenericBounds, plus: bool, ) -> PResult<'a, TyKind> { - assert_ne!(self.token, token::Question); if plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?); diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 50db69f4209..9d653de910f 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -10,7 +10,6 @@ test(attr(deny(warnings))) )] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(bool_to_option)] pub use Alignment::*; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bf574bbfbb5..b18ef302962 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -577,7 +577,7 @@ impl CheckAttrVisitor<'tcx> { target: Target, specified_inline: &mut Option<(bool, Span)>, ) -> bool { - if target == Target::Use { + if target == Target::Use || target == Target::ExternCrate { let do_inline = meta.name_or_empty() == sym::inline; if let Some((prev_inline, prev_span)) = *specified_inline { if do_inline != prev_inline { @@ -705,7 +705,7 @@ impl CheckAttrVisitor<'tcx> { 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 @@ -757,7 +757,6 @@ impl CheckAttrVisitor<'tcx> { | sym::html_no_source | sym::html_playground_url | sym::html_root_url - | sym::include | sym::inline | sym::issue_tracker_base_url | sym::keyword @@ -792,6 +791,30 @@ impl CheckAttrVisitor<'tcx> { ); 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(); }, ); diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 0be7ef7e12a..28633faa205 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,12 +5,11 @@ //! 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] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1342762bb07..5a79a9cc6ec 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ #![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)] @@ -157,6 +156,7 @@ where let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) } + ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { ControlFlow::CONTINUE } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 00d886000fa..4175fb6925a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -2,13 +2,9 @@ #![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] @@ -26,7 +22,7 @@ use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_val 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; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index c789aa2fa59..b4191c135b4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,7 +3,7 @@ //! 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}; @@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lock; 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> { @@ -25,6 +25,7 @@ pub struct QueryCtxt<'tcx> { impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { type Target = TyCtxt<'tcx>; + #[inline] fn deref(&self) -> &Self::Target { &self.tcx } @@ -42,10 +43,6 @@ impl HasDepContext for QueryCtxt<'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) } @@ -60,39 +57,6 @@ impl QueryContext for QueryCtxt<'tcx> { } 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 @@ -457,20 +421,7 @@ macro_rules! define_queries { } 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) { diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 2517793ecea..95edc1e93a5 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -61,7 +61,7 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { 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; diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7a0fc320663..71e67dfee53 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -19,9 +19,8 @@ use std::marker::PhantomData; 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; @@ -45,6 +44,7 @@ rustc_index::newtype_index! { 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 { @@ -78,7 +78,7 @@ struct DepGraphData<K: DepKind> { /// 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, @@ -109,7 +109,8 @@ where 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, @@ -117,16 +118,23 @@ impl<K: DepKind> DepGraph<K> { ) -> DepGraph<K> { let prev_graph_node_count = prev_graph.node_count(); + let current = + CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats); + + // 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, @@ -288,30 +296,47 @@ impl<K: DepKind> DepGraph<K> { 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()) @@ -488,6 +513,117 @@ impl<K: DepKind> DepGraph<K> { } } + 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, @@ -512,123 +648,7 @@ impl<K: DepKind> DepGraph<K> { 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 @@ -797,7 +817,7 @@ impl<K: DepKind> DepGraph<K> { } } - 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) } @@ -857,7 +877,7 @@ rustc_index::newtype_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`. /// @@ -982,7 +1002,7 @@ impl<K: DepKind> CurrentDepGraph<K> { fn intern_node( &self, profiler: &SelfProfilerRef, - prev_graph: &PreviousDepGraph<K>, + prev_graph: &SerializedDepGraph<K>, key: DepNode<K>, edges: EdgesVec, fingerprint: Option<Fingerprint>, @@ -1080,7 +1100,7 @@ impl<K: DepKind> CurrentDepGraph<K> { 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); @@ -1112,7 +1132,7 @@ impl<K: DepKind> CurrentDepGraph<K> { #[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); diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 1b6ecf3e637..15e2633c4f1 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,13 +1,11 @@ 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}; diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs deleted file mode 100644 index 6303bbf53b9..00000000000 --- a/compiler/rustc_query_system/src/dep_graph/prev.rs +++ /dev/null @@ -1,56 +0,0 @@ -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() - } -} diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 6f3d1fb7199..73c00fc49ba 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -37,17 +37,19 @@ rustc_index::newtype_index! { #[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> { @@ -57,6 +59,7 @@ impl<K: DepKind> Default for SerializedDepGraph<K> { fingerprints: Default::default(), edge_list_indices: Default::default(), edge_list_data: Default::default(), + index: Default::default(), } } } @@ -67,6 +70,30 @@ impl<K: DepKind> SerializedDepGraph<K> { 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>> @@ -95,21 +122,21 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< let mut edge_list_data = Vec::with_capacity(edge_count); for _index in 0..node_count { - d.read_struct("NodeInfo", 3, |d| { - let dep_node: DepNode<K> = d.read_struct_field("node", 0, Decodable::decode)?; + d.read_struct(|d| { + let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?; let _i: SerializedDepNodeIndex = nodes.push(dep_node); debug_assert_eq!(_i.index(), _index); let fingerprint: Fingerprint = - d.read_struct_field("fingerprint", 1, Decodable::decode)?; + d.read_struct_field("fingerprint", Decodable::decode)?; let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint); debug_assert_eq!(_i.index(), _index); - d.read_struct_field("edges", 2, |d| { + d.read_struct_field("edges", |d| { d.read_seq(|d, len| { let start = edge_list_data.len().try_into().unwrap(); - for e in 0..len { - let edge = d.read_seq_elt(e, Decodable::decode)?; + for _ in 0..len { + let edge = d.read_seq_elt(Decodable::decode)?; edge_list_data.push(edge); } let end = edge_list_data.len().try_into().unwrap(); @@ -121,7 +148,10 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< })?; } - 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 }) } } diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index be72baefb9e..0d4fb34265c 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,11 +1,8 @@ #![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; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index aef8a13ccef..927e8117f05 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -19,7 +19,6 @@ use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIn 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. @@ -64,9 +63,6 @@ impl QueryStackFrame { } 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>>; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 39dfdd78cc4..c1f9fa39e98 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,7 +2,7 @@ //! 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}; @@ -19,7 +19,7 @@ use rustc_data_structures::thin_vec::ThinVec; #[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}; @@ -431,7 +431,7 @@ fn try_execute_query<CTX, C>( ) -> 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( @@ -452,11 +452,15 @@ where } }; - // 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 { @@ -464,17 +468,14 @@ where 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); @@ -490,7 +491,7 @@ where // 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( @@ -511,7 +512,7 @@ where } 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 } @@ -693,7 +694,7 @@ fn get_query_impl<CTX, C>( 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) } @@ -743,15 +744,28 @@ fn force_query_impl<CTX, C>( 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| { @@ -765,7 +779,7 @@ fn force_query_impl<CTX, C>( }); let lookup = match cached { - Ok(()) => return, + Ok(()) => return true, Err(lookup) => lookup, }; @@ -773,17 +787,20 @@ fn force_query_impl<CTX, C>( 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 { @@ -800,7 +817,7 @@ pub fn get_query<Q, CTX>( ) -> 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; @@ -816,11 +833,15 @@ where 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) } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6ea46f5c528..03d94f43897 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -425,27 +425,32 @@ impl<'a> Resolver<'a> { } 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, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ffa825b7d46..a21d8197bdb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1613,10 +1613,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.r.record_partial_res(pat.id, PartialRes::new(res)); self.r.record_pat_span(pat.id, pat.span); } - PatKind::TupleStruct(ref path, ref sub_patterns) => { + PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => { self.smart_resolve_path( pat.id, - None, + qself.as_ref(), path, PathSource::TupleStruct( pat.span, @@ -1627,8 +1627,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); } - PatKind::Struct(ref path, ..) => { - self.smart_resolve_path(pat.id, None, path, PathSource::Struct); + PatKind::Struct(ref qself, ref path, ..) => { + self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Struct); } PatKind::Or(ref ps) => { // Add a new set of bindings to the stack. `Or` here records that when a @@ -1763,13 +1763,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // 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 } @@ -1939,7 +1959,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { 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() { @@ -2268,7 +2288,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } ExprKind::Struct(ref se) => { - self.smart_resolve_path(expr.id, None, &se.path, PathSource::Struct); + self.smart_resolve_path(expr.id, se.qself.as_ref(), &se.path, PathSource::Struct); visit::walk_expr(self, expr); } @@ -2415,12 +2435,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // 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. diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index efa5d7e7b11..ca7cdc4caf5 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1841,14 +1841,6 @@ fn object_lifetime_defaults_for_item( } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - // FIXME(#37666) this works around a limitation in the region inferencer - fn hack<F>(&mut self, f: F) - where - F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), - { - f(self) - } - fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F) where F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), @@ -2252,7 +2244,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; self.with(scope, move |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); - this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` + walk(this); }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 300d2c01cb5..6d5531d3307 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -16,7 +16,6 @@ #![feature(format_args_capture)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] @@ -234,9 +233,16 @@ enum ResolutionError<'a> { /* 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. @@ -903,7 +909,7 @@ pub struct Resolver<'a> { /// `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 @@ -1132,8 +1138,8 @@ impl ResolverAstLowering for Resolver<'_> { 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> { @@ -1192,7 +1198,7 @@ impl<'a> Resolver<'a> { session: &'a Session, krate: &Crate, crate_name: &str, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box<MetadataLoaderDyn>, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; @@ -1280,7 +1286,7 @@ impl<'a> Resolver<'a> { 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, @@ -2602,7 +2608,7 @@ impl<'a> Resolver<'a> { let res_error = if rib_ident.name == kw::SelfUpper { ResolutionError::SelfInTyParamDefault } else { - ResolutionError::ForwardDeclaredTyParam + ResolutionError::ForwardDeclaredGenericParam }; self.report_error(span, res_error); } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 6c308ad89db..297383bfed1 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,6 +1,5 @@ #![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; @@ -824,20 +823,6 @@ impl<'tcx> SaveContext<'tcx> { // 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'); - }); - } } } diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs index ae6d27e037b..80a7f650188 100644 --- a/compiler/rustc_serialize/src/collection_impls.rs +++ b/compiler/rustc_serialize/src/collection_impls.rs @@ -21,8 +21,8 @@ impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> { d.read_seq(|d, len| { let mut vec = SmallVec::with_capacity(len); // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error> - for i in 0..len { - vec.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + vec.push(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(vec) }) @@ -44,8 +44,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> { fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> { d.read_seq(|d, len| { let mut list = LinkedList::new(); - for i in 0..len { - list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(list) }) @@ -67,8 +67,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> { fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> { d.read_seq(|d, len| { let mut deque: VecDeque<T> = VecDeque::with_capacity(len); - for i in 0..len { - deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(deque) }) @@ -84,7 +84,7 @@ where e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; - e.emit_map_elt_val(i, |e| val.encode(e))?; + e.emit_map_elt_val(|e| val.encode(e))?; } Ok(()) }) @@ -99,9 +99,9 @@ where fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> { d.read_map(|d, len| { let mut map = BTreeMap::new(); - for i in 0..len { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?; - let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?; + for _ in 0..len { + let key = d.read_map_elt_key(|d| Decodable::decode(d))?; + let val = d.read_map_elt_val(|d| Decodable::decode(d))?; map.insert(key, val); } Ok(map) @@ -130,8 +130,8 @@ where fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> { d.read_seq(|d, len| { let mut set = BTreeSet::new(); - for i in 0..len { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(set) }) @@ -148,7 +148,7 @@ where e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; - e.emit_map_elt_val(i, |e| val.encode(e))?; + e.emit_map_elt_val(|e| val.encode(e))?; } Ok(()) }) @@ -165,9 +165,9 @@ where d.read_map(|d, len| { let state = Default::default(); let mut map = HashMap::with_capacity_and_hasher(len, state); - for i in 0..len { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?; - let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?; + for _ in 0..len { + let key = d.read_map_elt_key(|d| Decodable::decode(d))?; + let val = d.read_map_elt_val(|d| Decodable::decode(d))?; map.insert(key, val); } Ok(map) @@ -209,8 +209,8 @@ where d.read_seq(|d, len| { let state = Default::default(); let mut set = HashSet::with_capacity_and_hasher(len, state); - for i in 0..len { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(set) }) @@ -227,7 +227,7 @@ where e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; - e.emit_map_elt_val(i, |e| val.encode(e))?; + e.emit_map_elt_val(|e| val.encode(e))?; } Ok(()) }) @@ -244,9 +244,9 @@ where d.read_map(|d, len| { let state = Default::default(); let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state); - for i in 0..len { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?; - let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?; + for _ in 0..len { + let key = d.read_map_elt_key(|d| Decodable::decode(d))?; + let val = d.read_map_elt_val(|d| Decodable::decode(d))?; map.insert(key, val); } Ok(map) @@ -278,8 +278,8 @@ where d.read_seq(|d, len| { let state = Default::default(); let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state); - for i in 0..len { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + set.insert(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(set) }) diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs index 78a102c5c23..b79adb6f7bc 100644 --- a/compiler/rustc_serialize/src/json.rs +++ b/compiler/rustc_serialize/src/json.rs @@ -560,7 +560,7 @@ impl<'a> crate::Encoder for Encoder<'a> { Ok(()) } - fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult + fn emit_enum<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { @@ -589,46 +589,20 @@ impl<'a> crate::Encoder for Encoder<'a> { } } - fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult + fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { + if !first { write!(self.writer, ",")?; } f(self) } - fn emit_enum_struct_variant<F>( - &mut self, - name: &str, - id: usize, - cnt: usize, - f: F, - ) -> EncodeResult - where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult + fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { @@ -641,14 +615,14 @@ impl<'a> crate::Encoder for Encoder<'a> { Ok(()) } - fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult + fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { + if !first { write!(self.writer, ",")?; } escape_str(self.writer, name)?; @@ -675,25 +649,6 @@ impl<'a> crate::Encoder for Encoder<'a> { self.emit_seq_elt(idx, f) } - fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut Encoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_seq_elt(idx, f) - } - fn emit_option<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, @@ -774,7 +729,7 @@ impl<'a> crate::Encoder for Encoder<'a> { Ok(()) } - fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult + fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult, { @@ -892,7 +847,7 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult + fn emit_enum<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { @@ -930,54 +885,28 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { } } - fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult + fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx != 0 { + if !first { writeln!(self.writer, ",")?; } spaces(self.writer, self.curr_indent)?; f(self) } - fn emit_enum_struct_variant<F>( - &mut self, - name: &str, - id: usize, - cnt: usize, - f: F, - ) -> EncodeResult + fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - if len == 0 { + if no_fields { write!(self.writer, "{{}}")?; } else { write!(self.writer, "{{")?; @@ -991,14 +920,14 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult + fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { if self.is_emitting_map_key { return Err(EncoderError::BadHashmapKey); } - if idx == 0 { + if first { writeln!(self.writer)?; } else { writeln!(self.writer, ",")?; @@ -1028,25 +957,6 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { self.emit_seq_elt(idx, f) } - fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult - where - F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, - { - if self.is_emitting_map_key { - return Err(EncoderError::BadHashmapKey); - } - self.emit_seq_elt(idx, f) - } - fn emit_option<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, @@ -1149,7 +1059,7 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> { Ok(()) } - fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult + fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, { @@ -2373,7 +2283,7 @@ impl crate::Decoder for Decoder { Ok(()) } - fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> + fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { @@ -2410,33 +2320,14 @@ impl crate::Decoder for Decoder { f(self, idx) } - fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> + fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { f(self) } - fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> - where - F: FnMut(&mut Decoder, usize) -> DecodeResult<T>, - { - self.read_enum_variant(names, f) - } - - fn read_enum_struct_variant_field<T, F>( - &mut self, - _name: &str, - idx: usize, - f: F, - ) -> DecodeResult<T> - where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, - { - self.read_enum_variant_arg(idx, f) - } - - fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T> + fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { @@ -2445,7 +2336,7 @@ impl crate::Decoder for Decoder { Ok(value) } - fn read_struct_field<T, F>(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult<T> + fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { @@ -2483,25 +2374,11 @@ impl crate::Decoder for Decoder { }) } - fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> - where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, - { - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> DecodeResult<T> - where - F: FnOnce(&mut Decoder) -> DecodeResult<T>, - { - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> + fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { - self.read_tuple_arg(idx, f) + self.read_seq_elt(f) } fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> @@ -2527,7 +2404,7 @@ impl crate::Decoder for Decoder { f(self, len) } - fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> + fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { @@ -2547,14 +2424,14 @@ impl crate::Decoder for Decoder { f(self, len) } - fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> + fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { f(self) } - fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> + fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Decoder) -> DecodeResult<T>, { diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index cf5a9118275..c79786a839f 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -14,10 +14,7 @@ Core encoding and decoding interfaces. #![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))] diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index d3e5f306970..bb3c537ef19 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -37,7 +37,7 @@ pub trait Encoder { // Compound types: #[inline] - fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error> + fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -59,40 +59,15 @@ pub trait Encoder { } #[inline] - fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error> + fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { f(self) } - fn emit_enum_struct_variant<F>( - &mut self, - v_name: &str, - v_id: usize, - len: usize, - f: F, - ) -> Result<(), Self::Error> - where - F: FnOnce(&mut Self) -> Result<(), Self::Error>, - { - self.emit_enum_variant(v_name, v_id, len, f) - } - - fn emit_enum_struct_variant_field<F>( - &mut self, - _f_name: &str, - f_idx: usize, - f: F, - ) -> Result<(), Self::Error> - where - F: FnOnce(&mut Self) -> Result<(), Self::Error>, - { - self.emit_enum_variant_arg(f_idx, f) - } - #[inline] - fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> + fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -100,12 +75,7 @@ pub trait Encoder { } #[inline] - fn emit_struct_field<F>( - &mut self, - _f_name: &str, - _f_idx: usize, - f: F, - ) -> Result<(), Self::Error> + fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -128,26 +98,12 @@ pub trait Encoder { f(self) } - fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error> - where - F: FnOnce(&mut Self) -> Result<(), Self::Error>, - { - self.emit_tuple(len, f) - } - - fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> - where - F: FnOnce(&mut Self) -> Result<(), Self::Error>, - { - self.emit_tuple_arg(f_idx, f) - } - // Specialized types: fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { - self.emit_enum("Option", f) + self.emit_enum(f) } #[inline] @@ -195,7 +151,7 @@ pub trait Encoder { } #[inline] - fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -229,7 +185,7 @@ pub trait Decoder { // Compound types: #[inline] - fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error> + fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -246,34 +202,15 @@ pub trait Decoder { } #[inline] - fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error> + fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { f(self) } - fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> - where - F: FnMut(&mut Self, usize) -> Result<T, Self::Error>, - { - self.read_enum_variant(names, f) - } - - fn read_enum_struct_variant_field<T, F>( - &mut self, - _f_name: &str, - f_idx: usize, - f: F, - ) -> Result<T, Self::Error> - where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, - { - self.read_enum_variant_arg(f_idx, f) - } - #[inline] - fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, Self::Error> + fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -281,12 +218,7 @@ pub trait Decoder { } #[inline] - fn read_struct_field<T, F>( - &mut self, - _f_name: &str, - _f_idx: usize, - f: F, - ) -> Result<T, Self::Error> + fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -302,33 +234,19 @@ pub trait Decoder { } #[inline] - fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error> + fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { f(self) } - fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F) -> Result<T, Self::Error> - where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, - { - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> - where - F: FnOnce(&mut Self) -> Result<T, Self::Error>, - { - self.read_tuple_arg(a_idx, f) - } - // Specialized types: fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>, { - self.read_enum("Option", move |this| { + self.read_enum(move |this| { this.read_enum_variant(&["None", "Some"], move |this, idx| match idx { 0 => f(this, false), 1 => f(this, true), @@ -346,7 +264,7 @@ pub trait Decoder { } #[inline] - fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> + fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -362,7 +280,7 @@ pub trait Decoder { } #[inline] - fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> + fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -370,7 +288,7 @@ pub trait Decoder { } #[inline] - fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error> + fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>, { @@ -550,8 +468,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> { default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); + for _ in 0..len { + v.push(d.read_seq_elt(|d| Decodable::decode(d))?); } Ok(v) }) @@ -571,7 +489,7 @@ impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] { assert!(len == N); let mut v = [0u8; N]; for i in 0..len { - v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?; + v[i] = d.read_seq_elt(|d| Decodable::decode(d))?; } Ok(v) }) @@ -615,12 +533,12 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> { impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_enum("Result", |s| match *self { + s.emit_enum(|s| match *self { Ok(ref v) => { - s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s))) + s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s))) } Err(ref v) => { - s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s))) + s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s))) } }) } @@ -628,10 +546,10 @@ impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> { fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> { - d.read_enum("Result", |d| { + d.read_enum(|d| { d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr { - 0 => Ok(Ok(d.read_enum_variant_arg(0, |d| T1::decode(d))?)), - 1 => Ok(Err(d.read_enum_variant_arg(0, |d| T2::decode(d))?)), + 0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)), + 1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)), _ => { panic!( "Encountered invalid discriminant while \ @@ -668,8 +586,7 @@ macro_rules! tuple { fn decode(d: &mut D) -> Result<($($name,)+), D::Error> { let len: usize = count!($($name)+); d.read_tuple(len, |d| { - let mut i = 0; - let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> { + let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> { Decodable::decode(d) })?,)+); Ok(ret) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f517c483758..e197c43b301 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -677,6 +677,7 @@ impl Default for Options { 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()), @@ -1092,6 +1093,13 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { 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"), @@ -1156,7 +1164,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { 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; @@ -1189,7 +1198,19 @@ pub fn get_cmd_lint_options( 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").into_iter().map(|name| name.replace('-', "_")).collect(); + + (lint_opts, describe_lints, lint_cap, force_warns) } /// Parses the `--color` flag. @@ -1507,7 +1528,10 @@ fn collect_print_requests( 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); @@ -1923,9 +1947,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { 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 { @@ -2097,6 +2122,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { optimize: opt_level, debuginfo, lint_opts, + force_warns, lint_cap, describe_lints, output_types, @@ -2392,6 +2418,7 @@ impl PpMode { /// we have an opt-in scheme here, so one is hopefully forced to think about /// how the hash should be calculated when adding a new command-line argument. crate mod dep_tracking { + use super::LdImpl; use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, @@ -2424,46 +2451,32 @@ crate mod dep_tracking { )+}; } - 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, @@ -2481,21 +2494,12 @@ crate mod dep_tracking { 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) + Option<LdImpl>, ); impl<T1, T2> DepTrackingHash for (T1, T2) @@ -2527,6 +2531,16 @@ crate mod dep_tracking { } } + 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>, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 7971f7ef9ef..8d00a9a959e 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,5 @@ #![feature(crate_visibility_modifier)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c9f95ed1224..1946bfd78cc 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -130,6 +130,7 @@ top_level_options!( 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], @@ -368,7 +369,8 @@ mod desc { 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`)"; + pub const parse_gcc_ld: &str = "one of: no value, `lld`"; } mod parse { @@ -863,6 +865,15 @@ mod parse { } true } + + crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool { + match v { + None => *slot = None, + Some("lld") => *slot = Some(LdImpl::Lld), + _ => return false, + } + true + } } options! { @@ -1066,6 +1077,7 @@ options! { "set the optimization fuel quota for a crate"), function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), + gcc_ld: Option<LdImpl> = (None, parse_gcc_ld, [TRACKED], "implementation of ld used by cc"), graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], "use dark-themed colors in graphviz output (default: no)"), graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], @@ -1320,3 +1332,8 @@ pub enum WasiExecModel { Command, Reactor, } + +#[derive(Clone, Copy, Hash)] +pub enum LdImpl { + Lld, +} diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 777eea3f68d..cc1e4bb198a 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -127,6 +127,11 @@ pub fn filename_for_metadata( 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 diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1348b02b878..86b8389a670 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -452,6 +452,7 @@ impl Session { 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() } @@ -524,6 +525,7 @@ impl Session { self.diagnostic().struct_note_without_error(msg) } + #[inline] pub fn diagnostic(&self) -> &rustc_errors::Handler { &self.parse_sess.span_diagnostic } @@ -1512,6 +1514,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) { 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. diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 95bb0ad7ba2..bb4ac22d9c8 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,7 +1,7 @@ use crate::crate_disambiguator::CrateDisambiguator; use crate::HashStableContext; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; @@ -10,65 +10,23 @@ use std::borrow::Borrow; 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 } } @@ -76,10 +34,7 @@ impl CrateNum { 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) } } @@ -97,15 +52,6 @@ impl<D: Decoder> Decodable<D> for CrateNum { } } -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 @@ -271,20 +217,20 @@ impl DefId { impl<E: Encoder> Encodable<E> for DefId { default fn encode(&self, s: &mut E) -> Result<(), E::Error> { - s.emit_struct("DefId", 2, |s| { - s.emit_struct_field("krate", 0, |s| self.krate.encode(s))?; + s.emit_struct(false, |s| { + s.emit_struct_field("krate", true, |s| self.krate.encode(s))?; - s.emit_struct_field("index", 1, |s| self.index.encode(s)) + s.emit_struct_field("index", false, |s| self.index.encode(s)) }) } } impl<D: Decoder> Decodable<D> for DefId { default fn decode(d: &mut D) -> Result<DefId, D::Error> { - d.read_struct("DefId", 2, |d| { + d.read_struct(|d| { Ok(DefId { - krate: d.read_struct_field("krate", 0, Decodable::decode)?, - index: d.read_struct_field("index", 1, Decodable::decode)?, + krate: d.read_struct_field("krate", Decodable::decode)?, + index: d.read_struct_field("index", Decodable::decode)?, }) }) } @@ -362,13 +308,49 @@ impl<D: Decoder> Decodable<D> for LocalDefId { rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId); impl<CTX: HashStableContext> HashStable<CTX> for DefId { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + } +} + +impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId { + #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - hcx.hash_def_id(*self, hasher) + self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); } } impl<CTX: HashStableContext> HashStable<CTX> for CrateNum { + #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - hcx.hash_crate_num(*self, hasher) + self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + } +} + +impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefId { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash { + hcx.def_path_hash(*self) + } +} + +impl<CTX: HashStableContext> ToStableHashKey<CTX> for LocalDefId { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash { + hcx.def_path_hash(self.to_def_id()) + } +} + +impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash { + self.as_def_id().to_stable_hash_key(hcx) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 8f3b8cc2d0e..23efaf6f4f3 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -29,7 +29,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::SESSION_GLOBALS; use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP}; -use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::def_id::{CrateNum, DefId, DefPathHash, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -1330,9 +1330,12 @@ fn update_disambiguator(expn_id: ExpnId) { } impl<'a> crate::HashStableContext for DummyHashStableContext<'a> { - fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) { - def_id.krate.as_u32().hash_stable(self, hasher); - def_id.index.as_u32().hash_stable(self, hasher); + #[inline] + fn def_path_hash(&self, def_id: DefId) -> DefPathHash { + DefPathHash(Fingerprint::new( + def_id.krate.as_u32().into(), + def_id.index.as_u32().into(), + )) } fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> { @@ -1345,9 +1348,6 @@ fn update_disambiguator(expn_id: ExpnId) { &CACHE } - fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) { - krate.as_u32().hash_stable(self, hasher); - } fn hash_spans(&self) -> bool { true } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0301b364591..b4fe7c980de 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -16,7 +16,6 @@ #![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)] @@ -41,7 +40,7 @@ pub use hygiene::SyntaxContext; use hygiene::Transparency; pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind}; pub mod def_id; -use def_id::{CrateNum, DefId, LOCAL_CRATE}; +use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE}; pub mod lev_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -147,11 +146,12 @@ impl Hash for RealFileName { // an added assert statement impl<S: Encoder> Encodable<S> for RealFileName { fn encode(&self, encoder: &mut S) -> Result<(), S::Error> { - encoder.emit_enum("RealFileName", |encoder| match *self { + encoder.emit_enum(|encoder| match *self { RealFileName::LocalPath(ref local_path) => { encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| { Ok({ - encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?; + encoder + .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?; }) }) } @@ -162,8 +162,10 @@ impl<S: Encoder> Encodable<S> for RealFileName { // if they have been remapped by --remap-path-prefix assert!(local_path.is_none()); Ok({ - encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?; - encoder.emit_enum_variant_arg(1, |encoder| virtual_name.encode(encoder))?; + encoder + .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?; + encoder + .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?; }) }), }) @@ -828,17 +830,17 @@ impl Default for Span { impl<E: Encoder> Encodable<E> for Span { default fn encode(&self, s: &mut E) -> Result<(), E::Error> { let span = self.data(); - s.emit_struct("Span", 2, |s| { - s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?; - s.emit_struct_field("hi", 1, |s| span.hi.encode(s)) + s.emit_struct(false, |s| { + s.emit_struct_field("lo", true, |s| span.lo.encode(s))?; + s.emit_struct_field("hi", false, |s| span.hi.encode(s)) }) } } impl<D: Decoder> Decodable<D> for Span { default fn decode(s: &mut D) -> Result<Span, D::Error> { - s.read_struct("Span", 2, |d| { - let lo = d.read_struct_field("lo", 0, Decodable::decode)?; - let hi = d.read_struct_field("hi", 1, Decodable::decode)?; + s.read_struct(|d| { + let lo = d.read_struct_field("lo", Decodable::decode)?; + let hi = d.read_struct_field("hi", Decodable::decode)?; Ok(Span::new(lo, hi, SyntaxContext::root())) }) @@ -1235,12 +1237,12 @@ pub struct SourceFile { impl<S: Encoder> Encodable<S> for SourceFile { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("SourceFile", 8, |s| { - s.emit_struct_field("name", 0, |s| self.name.encode(s))?; - s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?; - s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?; - s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?; - s.emit_struct_field("lines", 5, |s| { + s.emit_struct(false, |s| { + s.emit_struct_field("name", true, |s| self.name.encode(s))?; + s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?; + s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?; + s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?; + s.emit_struct_field("lines", false, |s| { let lines = &self.lines[..]; // Store the length. s.emit_u32(lines.len() as u32)?; @@ -1298,25 +1300,24 @@ impl<S: Encoder> Encodable<S> for SourceFile { Ok(()) })?; - s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?; - s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?; - s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?; - s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?; - s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s)) + s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?; + s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?; + s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?; + s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?; + s.emit_struct_field("cnum", false, |s| self.cnum.encode(s)) }) } } impl<D: Decoder> Decodable<D> for SourceFile { fn decode(d: &mut D) -> Result<SourceFile, D::Error> { - d.read_struct("SourceFile", 8, |d| { - let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; + d.read_struct(|d| { + let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?; let src_hash: SourceFileHash = - d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; - let start_pos: BytePos = - d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?; - let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| { + d.read_struct_field("src_hash", |d| Decodable::decode(d))?; + let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?; + let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?; + let lines: Vec<BytePos> = d.read_struct_field("lines", |d| { let num_lines: u32 = Decodable::decode(d)?; let mut lines = Vec::with_capacity(num_lines as usize); @@ -1345,13 +1346,13 @@ impl<D: Decoder> Decodable<D> for SourceFile { Ok(lines) })?; let multibyte_chars: Vec<MultiByteChar> = - d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?; + d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?; let non_narrow_chars: Vec<NonNarrowChar> = - d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; - let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?; + d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?; + let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?; let normalized_pos: Vec<NormalizedPos> = - d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?; - let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?; + d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?; + let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?; Ok(SourceFile { name, start_pos, @@ -1927,13 +1928,12 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { /// This is a hack to allow using the [`HashStable_Generic`] derive macro /// instead of implementing everything in rustc_middle. pub trait HashStableContext { - fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher); + fn def_path_hash(&self, def_id: DefId) -> DefPathHash; /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`. /// This method allows us to have multiple `HashStableContext` implementations /// that hash things in a different way, without the results of one polluting /// the cache of the other. fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>; - fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher); fn hash_spans(&self) -> bool; fn span_data_to_lines_and_cols( &mut self, diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 0dadd419200..1d45cd172b3 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -407,7 +407,7 @@ impl SourceMap { } fn span_to_string(&self, sp: Span, prefer_local: bool) -> String { - if self.files.borrow().source_files.is_empty() && sp.is_dummy() { + if self.files.borrow().source_files.is_empty() || sp.is_dummy() { return "no-location".to_string(); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 46ef308cbf2..fb37c5e9c1e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -328,6 +328,7 @@ symbols! { box_free, box_patterns, box_syntax, + bpf_target_feature, braced_empty_structs, branch, breakpoint, @@ -755,6 +756,7 @@ symbols! { modifiers, module, module_path, + more_qualified_paths, more_struct_aliases, movbe_target_feature, move_ref_pattern, @@ -1332,6 +1334,7 @@ symbols! { wrapping_add, wrapping_mul, wrapping_sub, + wreg, write_bytes, xmm_reg, ymm_reg, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 7d186c330ba..025eaffcbd3 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -126,9 +126,7 @@ fn get_symbol_hash<'tcx>( substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { - tcx.original_crate_name(instantiating_crate) - .as_str() - .hash_stable(&mut hcx, &mut hasher); + tcx.crate_name(instantiating_crate).as_str().hash_stable(&mut hcx, &mut hasher); tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher); } @@ -255,7 +253,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { } 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( diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 7fb24ad1ed8..f716ce1efce 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -90,7 +90,6 @@ #![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"] diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index a70b374fc6d..828f1ac0a79 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -594,7 +594,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { 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 name = self.tcx.crate_name(cnum).as_str(); self.push_ident(&name); Ok(self) } diff --git a/compiler/rustc_target/src/abi/call/bpf.rs b/compiler/rustc_target/src/abi/call/bpf.rs new file mode 100644 index 00000000000..466c525531c --- /dev/null +++ b/compiler/rustc_target/src/abi/call/bpf.rs @@ -0,0 +1,31 @@ +// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td +use crate::abi::call::{ArgAbi, FnAbi}; + +fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { + if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 { + ret.make_indirect(); + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { + if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 { + arg.make_indirect(); + } else { + arg.extend_integer_width_to(32); + } +} + +pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) { + if !fn_abi.ret.is_ignore() { + classify_ret(&mut fn_abi.ret); + } + + for arg in &mut fn_abi.args { + if arg.is_ignore() { + continue; + } + classify_arg(arg); + } +} diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 0cf2441d84e..6e0e1403740 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -6,6 +6,7 @@ mod aarch64; mod amdgpu; mod arm; mod avr; +mod bpf; mod hexagon; mod mips; mod mips64; @@ -654,6 +655,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } "asmjs" => wasm::compute_c_abi_info(cx, self), + "bpf" => bpf::compute_abi_info(self), a => return Err(format!("unrecognized arch \"{}\" in target specification", a)), } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index dae72e1b2c8..8e71ded3d1d 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -222,6 +222,7 @@ pub trait HasDataLayout { } impl HasDataLayout for TargetDataLayout { + #[inline] fn data_layout(&self) -> &TargetDataLayout { self } @@ -752,11 +753,7 @@ impl FieldsShape { match *self { FieldsShape::Primitive => 0, FieldsShape::Union(count) => count.get(), - FieldsShape::Array { count, .. } => { - let usize_count = count as usize; - assert_eq!(usize_count as u64, count); - usize_count - } + FieldsShape::Array { count, .. } => count.try_into().unwrap(), FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(), } } @@ -790,11 +787,7 @@ impl FieldsShape { unreachable!("FieldsShape::memory_index: `Primitive`s have no fields") } FieldsShape::Union(_) | FieldsShape::Array { .. } => i, - FieldsShape::Arbitrary { ref memory_index, .. } => { - let r = memory_index[i]; - assert_eq!(r as usize as u32, r); - r as usize - } + FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(), } } @@ -862,6 +855,7 @@ pub enum Abi { 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, @@ -881,11 +875,13 @@ impl Abi { } /// 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(_)) } diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs new file mode 100644 index 00000000000..ecb6bdc95ce --- /dev/null +++ b/compiler/rustc_target/src/asm/bpf.rs @@ -0,0 +1,129 @@ +use super::{InlineAsmArch, InlineAsmType, Target}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Bpf BpfInlineAsmRegClass { + reg, + wreg, + } +} + +impl BpfInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, I64; }, + Self::wreg => types! { "alu32": I8, I16, I32; }, + } + } +} + +fn only_alu32( + _arch: InlineAsmArch, + mut has_feature: impl FnMut(&str) -> bool, + _target: &Target, +) -> Result<(), &'static str> { + if !has_feature("alu32") { + Err("register can't be used without the `alu32` target feature") + } else { + Ok(()) + } +} + +def_regs! { + Bpf BpfInlineAsmReg BpfInlineAsmRegClass { + r0: reg = ["r0"], + r1: reg = ["r1"], + r2: reg = ["r2"], + r3: reg = ["r3"], + r4: reg = ["r4"], + r5: reg = ["r5"], + r6: reg = ["r6"], + r7: reg = ["r7"], + r8: reg = ["r8"], + r9: reg = ["r9"], + w0: wreg = ["w0"] % only_alu32, + w1: wreg = ["w1"] % only_alu32, + w2: wreg = ["w2"] % only_alu32, + w3: wreg = ["w3"] % only_alu32, + w4: wreg = ["w4"] % only_alu32, + w5: wreg = ["w5"] % only_alu32, + w6: wreg = ["w6"] % only_alu32, + w7: wreg = ["w7"] % only_alu32, + w8: wreg = ["w8"] % only_alu32, + w9: wreg = ["w9"] % only_alu32, + + #error = ["r10", "w10"] => + "the stack pointer cannot be used as an operand for inline asm", + } +} + +impl BpfInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + out.write_str(self.name()) + } + + pub fn overlapping_regs(self, mut cb: impl FnMut(BpfInlineAsmReg)) { + cb(self); + + macro_rules! reg_conflicts { + ( + $( + $r:ident : $w:ident + ),* + ) => { + match self { + $( + Self::$r => { + cb(Self::$w); + } + Self::$w => { + cb(Self::$r); + } + )* + } + }; + } + + reg_conflicts! { + r0 : w0, + r1 : w1, + r2 : w2, + r3 : w3, + r4 : w4, + r5 : w5, + r6 : w6, + r7 : w7, + r8 : w8, + r9 : w9 + } + } +} diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index c17c2961434..305ea7d50e6 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -148,6 +148,7 @@ macro_rules! types { mod aarch64; mod arm; +mod bpf; mod hexagon; mod mips; mod nvptx; @@ -159,6 +160,7 @@ mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; +pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; @@ -184,6 +186,7 @@ pub enum InlineAsmArch { PowerPC64, SpirV, Wasm32, + Bpf, } impl FromStr for InlineAsmArch { @@ -205,6 +208,7 @@ impl FromStr for InlineAsmArch { "mips64" => Ok(Self::Mips64), "spirv" => Ok(Self::SpirV), "wasm32" => Ok(Self::Wasm32), + "bpf" => Ok(Self::Bpf), _ => Err(()), } } @@ -233,6 +237,7 @@ pub enum InlineAsmReg { Mips(MipsInlineAsmReg), SpirV(SpirVInlineAsmReg), Wasm(WasmInlineAsmReg), + Bpf(BpfInlineAsmReg), // Placeholder for invalid register constraints for the current target Err, } @@ -247,6 +252,7 @@ impl InlineAsmReg { Self::PowerPC(r) => r.name(), Self::Hexagon(r) => r.name(), Self::Mips(r) => r.name(), + Self::Bpf(r) => r.name(), Self::Err => "<reg>", } } @@ -260,6 +266,7 @@ impl InlineAsmReg { Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), + Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Err => InlineAsmRegClass::Err, } } @@ -304,6 +311,9 @@ impl InlineAsmReg { InlineAsmArch::Wasm32 => { Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Bpf => { + Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -323,6 +333,7 @@ impl InlineAsmReg { Self::PowerPC(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), + Self::Bpf(r) => r.emit(out, arch, modifier), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -336,6 +347,7 @@ impl InlineAsmReg { Self::PowerPC(_) => cb(self), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::Mips(_) => cb(self), + Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Err => unreachable!("Use of InlineAsmReg::Err"), } } @@ -364,6 +376,7 @@ pub enum InlineAsmRegClass { Mips(MipsInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), Wasm(WasmInlineAsmRegClass), + Bpf(BpfInlineAsmRegClass), // Placeholder for invalid register constraints for the current target Err, } @@ -381,6 +394,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.name(), Self::SpirV(r) => r.name(), Self::Wasm(r) => r.name(), + Self::Bpf(r) => r.name(), Self::Err => rustc_span::symbol::sym::reg, } } @@ -400,6 +414,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), + Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -426,6 +441,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), Self::Wasm(r) => r.suggest_modifier(arch, ty), + Self::Bpf(r) => r.suggest_modifier(arch, ty), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -448,6 +464,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), Self::Wasm(r) => r.default_modifier(arch), + Self::Bpf(r) => r.default_modifier(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -469,6 +486,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch), + Self::Bpf(r) => r.supported_types(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -493,6 +511,7 @@ impl InlineAsmRegClass { } InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?), }) } @@ -510,6 +529,7 @@ impl InlineAsmRegClass { Self::Mips(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), Self::Wasm(r) => r.valid_modifiers(arch), + Self::Bpf(r) => r.valid_modifiers(arch), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), } } @@ -679,5 +699,10 @@ pub fn allocatable_registers( wasm::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Bpf => { + let mut map = bpf::regclass_map(); + bpf::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 48ace9b65b6..cb8f6b9656c 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,11 +9,11 @@ #![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}; diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs index 2218c6c6da7..5682039b865 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { 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, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs index 758950bd344..8a832546d09 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { 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, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs index e594ceec1b7..2187015b627 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs @@ -18,7 +18,6 @@ pub fn target() -> Target { 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, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index a83de77dc2a..cb6c06b3711 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { 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, diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index c9f622820de..de92b167f00 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -16,7 +16,6 @@ pub fn target() -> Target { executables: true, relocation_model: RelocModel::Static, disable_redzone: true, - linker_is_gnu: true, max_atomic_width: Some(128), panic_strategy: PanicStrategy::Abort, unsupported_abis: super::arm_base::unsupported_abis(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 0811871c993..2566eeae14a 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -16,7 +16,6 @@ pub fn target() -> Target { executables: true, relocation_model: RelocModel::Static, disable_redzone: true, - linker_is_gnu: true, max_atomic_width: Some(128), panic_strategy: PanicStrategy::Abort, unsupported_abis: super::arm_base::unsupported_abis(), diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index bc2ec670901..8530db179d9 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -22,10 +22,12 @@ pub fn opts(os: &str) -> TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, + linker_is_gnu: false, executables: 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(), diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index 538c4ca8697..e7f7bb343d0 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -44,7 +44,6 @@ pub fn opts(os: &str, arch: Arch) -> TargetOptions { executables: true, link_env_remove: link_env_remove(arch), has_elf_tls: false, - eliminate_frame_pointer: false, ..super::apple_base::opts(os) } } diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 69ccce875ab..2cb2661a526 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -16,7 +16,6 @@ pub fn target(target_cpu: String) -> Target { linker: Some("avr-gcc".to_owned()), executables: true, - linker_is_gnu: true, eh_frame_header: false, pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])] .into_iter() diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs new file mode 100644 index 00000000000..764cc735d75 --- /dev/null +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -0,0 +1,42 @@ +use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions}; +use crate::{abi::Endian, spec::abi::Abi}; + +pub fn opts(endian: Endian) -> TargetOptions { + TargetOptions { + allow_asm: true, + endian, + linker_flavor: LinkerFlavor::BpfLinker, + atomic_cas: false, + executables: true, + dynamic_linking: true, + no_builtins: true, + panic_strategy: PanicStrategy::Abort, + position_independent_executables: true, + // Disable MergeFunctions since: + // - older kernels don't support bpf-to-bpf calls + // - on newer kernels, userspace still needs to relocate before calling + // BPF_PROG_LOAD and not all BPF libraries do that yet + merge_functions: MergeFunctions::Disabled, + obj_is_bitcode: true, + requires_lto: false, + singlethread: true, + max_atomic_width: Some(64), + unsupported_abis: vec![ + Abi::Cdecl, + Abi::Stdcall { unwind: false }, + Abi::Stdcall { unwind: true }, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall { unwind: false }, + Abi::Thiscall { unwind: true }, + Abi::Aapcs, + Abi::Win64, + Abi::SysV64, + Abi::PtxKernel, + Abi::Msp430Interrupt, + Abi::X86Interrupt, + Abi::AmdGpuKernel, + ], + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/bpfeb_unknown_none.rs new file mode 100644 index 00000000000..a45da82eb40 --- /dev/null +++ b/compiler/rustc_target/src/spec/bpfeb_unknown_none.rs @@ -0,0 +1,12 @@ +use crate::spec::Target; +use crate::{abi::Endian, spec::bpf_base}; + +pub fn target() -> Target { + Target { + llvm_target: "bpfeb".to_string(), + data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(), + pointer_width: 64, + arch: "bpf".to_string(), + options: bpf_base::opts(Endian::Big), + } +} diff --git a/compiler/rustc_target/src/spec/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/bpfel_unknown_none.rs new file mode 100644 index 00000000000..6c9afdf35ae --- /dev/null +++ b/compiler/rustc_target/src/spec/bpfel_unknown_none.rs @@ -0,0 +1,12 @@ +use crate::spec::Target; +use crate::{abi::Endian, spec::bpf_base}; + +pub fn target() -> Target { + Target { + llvm_target: "bpfel".to_string(), + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(), + pointer_width: 64, + arch: "bpf".to_string(), + options: bpf_base::opts(Endian::Little), + } +} diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index fb94498c131..e13a640d4d2 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index 5d3c28e5f29..bef2fce7c83 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index 13264dffeb4..23a2e65749e 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -27,7 +27,6 @@ pub fn opts() -> TargetOptions { executables: true, families: vec!["unix".to_string()], is_like_fuchsia: true, - linker_is_gnu: true, pre_link_args, pre_link_objects: crt_objects::new(&[ (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]), diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs index fae56f6a82d..2b95523d6f7 100644 --- a/compiler/rustc_target/src/spec/haiku_base.rs +++ b/compiler/rustc_target/src/spec/haiku_base.rs @@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions { executables: true, families: vec!["unix".to_string()], relro_level: RelroLevel::Full, - linker_is_gnu: true, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs index ad013047e6a..75ca1f79b12 100644 --- a/compiler/rustc_target/src/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -13,7 +13,6 @@ pub fn opts() -> TargetOptions { linker: Some("rust-lld".to_owned()), executables: true, has_elf_tls: true, - linker_is_gnu: true, pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs index 6d18a14d6ae..c55a46e69a8 100644 --- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs +++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs @@ -14,7 +14,6 @@ pub fn opts() -> TargetOptions { linker: Some("rust-lld".to_owned()), executables: true, has_elf_tls: true, - linker_is_gnu: true, pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs index 2b8e046c46b..9d9da50be7a 100644 --- a/compiler/rustc_target/src/spec/illumos_base.rs +++ b/compiler/rustc_target/src/spec/illumos_base.rs @@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, families: vec!["unix".to_string()], is_like_solaris: true, + linker_is_gnu: false, limit_rdylib_exports: false, // Linker doesn't support this eliminate_frame_pointer: false, eh_frame_header: false, diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index 65c343a5f21..f6e3102f617 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions { executables: true, panic_strategy: PanicStrategy::Abort, linker: Some("ld".to_string()), + linker_is_gnu: false, families: vec!["unix".to_string()], ..Default::default() } diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index 184659e22d9..af81bc714c7 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index 64f47b4aa9b..145aa4a5894 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -8,7 +8,6 @@ pub fn opts() -> TargetOptions { // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved stack_probes: StackProbeType::Call, eliminate_frame_pointer: false, - linker_is_gnu: true, position_independent_executables: true, needs_plt: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 08c290e6ff1..dc14e4bdf94 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -21,7 +21,6 @@ pub fn target() -> Target { cpu: "mips2".to_string(), executables: true, linker: Some("rust-lld".to_owned()), - linker_is_gnu: true, relocation_model: RelocModel::Static, // PSP FPU only supports single precision floats. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4bffd6e8ddd..0f2aaeb533a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -57,6 +57,7 @@ mod apple_base; mod apple_sdk_base; mod arm_base; mod avr_gnu_base; +mod bpf_base; mod dragonfly_base; mod freebsd_base; mod fuchsia_base; @@ -93,6 +94,7 @@ pub enum LinkerFlavor { Msvc, Lld(LldFlavor), PtxLinker, + BpfLinker, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -161,6 +163,7 @@ flavor_mappings! { ((LinkerFlavor::Ld), "ld"), ((LinkerFlavor::Msvc), "msvc"), ((LinkerFlavor::PtxLinker), "ptx-linker"), + ((LinkerFlavor::BpfLinker), "bpf-linker"), ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), @@ -897,6 +900,9 @@ supported_targets! { ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu), ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32), ("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32), + + ("bpfeb-unknown-none", bpfeb_unknown_none), + ("bpfel-unknown-none", bpfel_unknown_none), } /// Everything `rustc` knows about how to compile for a specific target. @@ -922,6 +928,7 @@ pub trait HasTargetSpec { } impl HasTargetSpec for Target { + #[inline] fn target_spec(&self) -> &Target { self } @@ -1086,7 +1093,7 @@ pub struct TargetOptions { /// Version of DWARF to use if not using the default. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub dwarf_version: Option<u32>, - /// Whether the linker support GNU-like arguments such as -O. Defaults to false. + /// Whether the linker support GNU-like arguments such as -O. Defaults to true. pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak @@ -1307,7 +1314,7 @@ impl Default for TargetOptions { is_like_fuchsia: false, is_like_wasm: false, dwarf_version: None, - linker_is_gnu: false, + linker_is_gnu: true, allows_weak_linkage: true, has_rpath: false, no_default_libraries: true, diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index cc2578aa578..6e3a241a86e 100644 --- a/compiler/rustc_target/src/spec/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs @@ -17,6 +17,7 @@ pub fn target() -> Target { // 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 diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 4ed7685ca07..f1ed4c154d2 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions { is_like_windows: true, is_like_msvc: true, lld_flavor: LldFlavor::Link, + linker_is_gnu: false, pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index 602fb6eb641..6bb6083d47c 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, no_default_libraries: false, has_rpath: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 15d8e4843f9..97960a75b09 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -14,6 +14,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::PtxLinker, // The linker can be installed from `crates.io`. linker: Some("rust-ptx-linker".to_string()), + linker_is_gnu: false, // With `ptx-linker` approach, it can be later overridden via link flags. cpu: "sm_30".to_string(), diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index 8f33bacd922..29b415e7726 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, abi_return_struct_as_int: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs index 72052b9e2e2..fcf5db3746d 100644 --- a/compiler/rustc_target/src/spec/redox_base.rs +++ b/compiler/rustc_target/src/spec/redox_base.rs @@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs index 4c922eb5cea..bc32b501688 100644 --- a/compiler/rustc_target/src/spec/solaris_base.rs +++ b/compiler/rustc_target/src/spec/solaris_base.rs @@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, families: vec!["unix".to_string()], is_like_solaris: true, + linker_is_gnu: false, limit_rdylib_exports: false, // Linker doesn't support this eh_frame_header: false, diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index ef58824f381..f996009f830 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -28,7 +28,6 @@ pub fn target() -> Target { options: TargetOptions { linker_flavor: LinkerFlavor::Ld, linker: Some("arm-none-eabi-ld".to_string()), - linker_is_gnu: true, // extra args passed to the external assembler (assuming `arm-none-eabi-as`): // * activate t32/a32 interworking diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs index 0e8e87f2dff..a91e7717865 100644 --- a/compiler/rustc_target/src/spec/vxworks_base.rs +++ b/compiler/rustc_target/src/spec/vxworks_base.rs @@ -10,7 +10,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, has_elf_tls: true, crt_static_default: true, diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index ddf28b423f0..302139395d3 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -34,7 +34,6 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".to_string(), linker: None, - linker_is_gnu: true, is_like_emscripten: true, panic_strategy: PanicStrategy::Unwind, post_link_args, diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index 87e740de08e..4c954a1e567 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -102,12 +102,7 @@ pub fn options() -> TargetOptions { // we use the LLD shipped with the Rust toolchain by default 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, + linker_is_gnu: false, pre_link_args, diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 5808391ee06..35a52896f6f 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -66,7 +66,6 @@ pub fn opts() -> TargetOptions { // FIXME(#13846) this should be enabled for windows function_sections: false, linker: Some("gcc".to_string()), - linker_is_gnu: true, dynamic_linking: true, executables: true, dll_prefix: String::new(), diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index 90705c526f4..06eb33d8d82 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -57,7 +57,6 @@ pub fn target() -> Target { vendor: "fortanix".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, - linker_is_gnu: true, linker: Some("rust-lld".to_owned()), max_atomic_width: Some(64), cpu: "x86-64".into(), diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 3f24a33f7d5..ac2e0ebae32 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -6,6 +6,7 @@ use rustc_infer::infer::InferCtxt; 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)] @@ -231,7 +232,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa .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(); } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index bf3c8643f0d..e932b1bca7c 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -19,7 +19,6 @@ #![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 diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 7e67bc118ec..89ec211f262 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -2,21 +2,22 @@ use crate::infer::InferCtxtExt as _; use crate::traits::{self, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::free_regions::FreeRegionRelations; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt}; use rustc_span::Span; use std::ops::ControlFlow; -pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>; +pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that @@ -26,19 +27,6 @@ pub struct OpaqueTypeDecl<'tcx> { /// The opaque type (`ty::Opaque`) for this declaration. pub opaque_type: Ty<'tcx>, - /// The substitutions that we apply to the opaque type that this - /// `impl Trait` desugars to. e.g., if: - /// - /// fn foo<'a, 'b, T>() -> impl Trait<'a> - /// - /// winds up desugared to: - /// - /// type Foo<'x, X> = impl Trait<'x> - /// fn foo<'a, 'b, T>() -> Foo<'a, T> - /// - /// then `substs` would be `['a, T]`. - pub substs: SubstsRef<'tcx>, - /// The span of this particular definition of the opaque type. So /// for example: /// @@ -125,7 +113,7 @@ pub trait InferCtxtExt<'tcx> { fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( &self, - def_id: DefId, + opaque_type_key: OpaqueTypeKey<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, mode: GenerateMemberConstraints, free_region_relations: &FRR, @@ -136,23 +124,13 @@ pub trait InferCtxtExt<'tcx> { &self, concrete_ty: Ty<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, + opaque_type_key: OpaqueTypeKey<'tcx>, 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, - substs: SubstsRef<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: Ty<'tcx>, span: Span, ) -> Ty<'tcx>; @@ -379,10 +357,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) { debug!("constrain_opaque_types()"); - for (&def_id, opaque_defn) in opaque_types { + for &(opaque_type_key, opaque_defn) in opaque_types { self.constrain_opaque_type( - def_id, - opaque_defn, + opaque_type_key, + &opaque_defn, GenerateMemberConstraints::WhenRequired, free_region_relations, ); @@ -392,11 +370,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// See `constrain_opaque_types` for documentation. fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( &self, - def_id: DefId, + opaque_type_key: OpaqueTypeKey<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, mode: GenerateMemberConstraints, free_region_relations: &FRR, ) { + let def_id = opaque_type_key.def_id; + debug!("constrain_opaque_type()"); debug!("constrain_opaque_type: def_id={:?}", def_id); debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); @@ -435,9 +415,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let bounds = tcx.explicit_item_bounds(def_id); debug!("constrain_opaque_type: predicates: {:#?}", bounds); let bounds: Vec<_> = - bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect(); + bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); debug!("constrain_opaque_type: bounds={:#?}", bounds); - let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); + let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds.into_iter()); @@ -449,7 +429,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } if let GenerateMemberConstraints::IfNoStaticBound = mode { - self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); + self.generate_member_constraint( + concrete_ty, + opaque_defn, + opaque_type_key, + first_own_region, + ); } return; } @@ -463,7 +448,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // second. let mut least_region = None; - for subst_arg in &opaque_defn.substs[first_own_region..] { + for subst_arg in &opaque_type_key.substs[first_own_region..] { let subst_region = match subst_arg.unpack() { GenericArgKind::Lifetime(r) => r, GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue, @@ -490,13 +475,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // ['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, - def_id, + opaque_type_key, first_own_region, ); } @@ -509,7 +491,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let GenerateMemberConstraints::IfNoStaticBound = mode { if least_region != tcx.lifetimes.re_static { - self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); + self.generate_member_constraint( + concrete_ty, + opaque_defn, + opaque_type_key, + first_own_region, + ); } } concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { @@ -529,14 +516,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, concrete_ty: Ty<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, + opaque_type_key: OpaqueTypeKey<'tcx>, first_own_region: usize, ) { // Create the set of choice regions: each region in the hidden // type can be equal to any of the region parameters of the // opaque type definition. let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new( - opaque_defn.substs[first_own_region..] + opaque_type_key.substs[first_own_region..] .iter() .filter_map(|arg| match arg.unpack() { GenericArgKind::Lifetime(r) => Some(r), @@ -549,7 +536,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { op: |r| { self.member_constraint( - opaque_type_def_id, + opaque_type_key.def_id, opaque_defn.definition_span, concrete_ty, r, @@ -559,60 +546,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } - /// 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 @@ -638,11 +571,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// `opaque_defn.concrete_ty` fn infer_opaque_definition_from_instantiation( &self, - def_id: DefId, - substs: SubstsRef<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: Ty<'tcx>, span: Span, ) -> Ty<'tcx> { + let OpaqueTypeKey { def_id, substs } = opaque_type_key; + debug!( "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", def_id, instantiated_ty @@ -1073,7 +1007,9 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ), }; if in_definition_scope { - return self.fold_opaque_ty(ty, def_id.to_def_id(), substs, origin); + let opaque_type_key = + OpaqueTypeKey { def_id: def_id.to_def_id(), substs }; + return self.fold_opaque_ty(ty, opaque_type_key, origin); } debug!( @@ -1095,18 +1031,18 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { fn fold_opaque_ty( &mut self, ty: Ty<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, origin: hir::OpaqueTyOrigin, ) -> Ty<'tcx> { let infcx = self.infcx; let tcx = infcx.tcx; + let OpaqueTypeKey { def_id, substs } = opaque_type_key; debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs); // Use the same type variable if the exact same opaque type appears more // than once in the return type (e.g., if it's passed to a type alias). - if let Some(opaque_defn) = self.opaque_types.get(&def_id) { + if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) { debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); return opaque_defn.concrete_ty; } @@ -1144,10 +1080,9 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let definition_span = self.value_span; self.opaque_types.insert( - def_id, + OpaqueTypeKey { def_id, substs }, OpaqueTypeDecl { opaque_type: ty, - substs, definition_span, concrete_ty: ty_var, has_required_region_bounds: !required_region_bounds.is_empty(), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8961cdaebf3..b1a938836b7 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -97,6 +97,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } + Node::Cast(_, _, ty) => { + let ty = ty.subst(tcx, ct.substs); + if ty.has_infer_types_or_consts() { + failure_kind = FailureKind::MentionsInfer; + } else if ty.has_param_types_or_consts() { + failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); + } + + ControlFlow::CONTINUE + } Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE } @@ -304,6 +314,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes[func].used = true; nodes.iter().for_each(|&n| self.nodes[n].used = true); } + Node::Cast(_, operand, _) => { + self.nodes[operand].used = true; + } } // Nodes start as unused. @@ -408,11 +421,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); Ok(()) } + Rvalue::Cast(cast_kind, ref operand, ty) => { + let operand = self.operand_to_node(span, operand)?; + self.locals[local] = + self.add_node(Node::Cast(cast_kind, operand, ty), span); + Ok(()) + } _ => self.error(Some(span), "unsupported rvalue")?, } } // These are not actually relevant for us here, so we can ignore them. - StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()), + StatementKind::AscribeUserType(..) + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) => Ok(()), _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, } } @@ -594,6 +615,7 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } + Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -676,6 +698,11 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } + (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) => + { + try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) + } _ => false, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index db396356d67..19c3385dd4c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1878,6 +1878,10 @@ impl<'v> Visitor<'v> for FindTypeParam { 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 diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1ea34e5814e..0ca0245a203 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -186,6 +186,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; 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()) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8bbd2da5375..5c35b515f3d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{ 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; @@ -2313,7 +2314,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { 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), )); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fc9739f70d4..120680092ba 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,7 +6,7 @@ use rustc_errors::ErrorReported; 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}; @@ -591,7 +591,16 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ) } (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), + )) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d5e1bd3f9ea..7ebef7f8883 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -838,6 +838,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } + Node::Cast(_, _, ty) => self.visit_ty(ty), Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE } @@ -859,6 +860,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } + Node::Cast(_, _, ty) => self.visit_ty(ty), Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a292de148a6..ea5eb2b6866 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -557,6 +557,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 @@ -591,7 +608,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) } (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) + } } } } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 144c7281b67..ebc7b0d0d99 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -7,7 +7,6 @@ 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; @@ -394,11 +393,6 @@ fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguat 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>, @@ -545,7 +539,6 @@ pub fn provide(providers: &mut ty::query::Providers) { param_env_reveal_all_normalized, trait_of_item, crate_disambiguator, - original_crate_name, instance_def_size_estimate, issue33140_self_ty, impl_defaultness, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 0dbcd483c45..2d102127dd9 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(min_specialization)] + #[macro_use] extern crate bitflags; #[macro_use] diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index b760a54f08c..3cbc3d231f8 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -35,6 +35,7 @@ use crate::type_error_struct; 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; @@ -347,15 +348,52 @@ impl<'a, 'tcx> CastCheck<'tcx> { 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())); } @@ -375,11 +413,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { 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, ); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 92d7ea26003..70d85796d00 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::layout::MAX_SIMD_LANES; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt}; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; @@ -716,10 +716,10 @@ fn check_opaque_meets_bounds<'tcx>( infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span), ); - for (def_id, opaque_defn) in opaque_type_map { + for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map { match infcx .at(&misc_cause, param_env) - .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs)) + .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs)) { Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok), Err(ty_err) => tcx.sess.delay_span_bug( @@ -1214,10 +1214,19 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { } } + // 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, diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index e5fcdcfa743..33bc25accb3 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -8,6 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; 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; @@ -16,6 +17,7 @@ use rustc_span::Span; use super::method::probe; use std::fmt; +use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_coerce_suggestions( @@ -412,14 +414,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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) }; @@ -427,10 +431,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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(); @@ -570,32 +570,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, + )); + } } } ( @@ -643,7 +649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - _ 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(); diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index de6336b254b..01276495c18 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -310,6 +310,7 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4de8216884a..96569ae0e77 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1522,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, ty); - match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { + match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { self.tcx.sess.delay_span_bug( diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 1dacbade1bd..2e9bef15f90 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -2,13 +2,14 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; use rustc_infer::infer; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt}; use rustc_span::{self, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::opaque_types::OpaqueTypeDecl; @@ -58,7 +59,7 @@ pub struct Inherited<'a, 'tcx> { // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - pub(super) opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>, + pub(super) opaque_types: RefCell<VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>>, /// A map from inference variables created from opaque /// type instantiations (`ty::Infer`) to the actual opaque diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 2320a29e6d8..16382c7e7a4 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -383,6 +383,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, @@ -391,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 { @@ -449,6 +485,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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")); } diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index a63aec07ad1..652b82f1063 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 71e222c560a..6baa185406e 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1588,6 +1588,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { 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)); } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index e472add6e80..032cc7ee233 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -475,8 +475,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } fn visit_opaque_types(&mut self, span: Span) { - for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local()); + for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() { + let hir_id = + self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local()); let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id); debug_assert!(!instantiated_ty.has_escaping_bound_vars()); @@ -494,50 +495,47 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // ``` // figures out the concrete type with `U`, but the stored type is with `T`. let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( - def_id, - opaque_defn.substs, + opaque_type_key, instantiated_ty, span, ); let mut skip_add = false; - if let ty::Opaque(defin_ty_def_id, _substs) = *definition_ty.kind() { + if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() { if let hir::OpaqueTyOrigin::Misc | hir::OpaqueTyOrigin::TyAlias = opaque_defn.origin { - if def_id == defin_ty_def_id { + if opaque_type_key.def_id == definition_ty_def_id { debug!( "skipping adding concrete definition for opaque type {:?} {:?}", - opaque_defn, defin_ty_def_id + opaque_defn, opaque_type_key.def_id ); skip_add = true; } } } - if !opaque_defn.substs.needs_infer() { + if !opaque_type_key.substs.needs_infer() { // We only want to add an entry into `concrete_opaque_types` // if we actually found a defining usage of this opaque type. // Otherwise, we do nothing - we'll either find a defining usage // in some other location, or we'll end up emitting an error due // to the lack of defining usage if !skip_add { - let new = ty::ResolvedOpaqueTy { - concrete_type: definition_ty, - substs: opaque_defn.substs, - }; - - let old = self.typeck_results.concrete_opaque_types.insert(def_id, new); - if let Some(old) = old { - if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { + let old_concrete_ty = self + .typeck_results + .concrete_opaque_types + .insert(opaque_type_key, definition_ty); + if let Some(old_concrete_ty) = old_concrete_ty { + if old_concrete_ty != definition_ty { span_bug!( span, "`visit_opaque_types` tried to write different types for the same \ opaque type: {:?}, {:?}, {:?}, {:?}", - def_id, + opaque_type_key.def_id, definition_ty, opaque_defn, - old, + old_concrete_ty, ); } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0528f8812f9..ee3ac3b62d9 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2597,6 +2597,7 @@ fn from_target_feature( Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, Some(sym::f16c_target_feature) => rust_features.f16c_target_feature, Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, + Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; @@ -2770,7 +2771,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } 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 || tcx.sess.opts.actually_rustdoc { + // 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) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + } else if !tcx.features().target_feature_11 { let mut err = feature_err( &tcx.sess.parse_sess, sym::target_feature_11, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 5197b620f90..abe5d69a3b3 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -9,7 +9,7 @@ use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -349,8 +349,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let concrete_ty = tcx .mir_borrowck(owner.expect_local()) .concrete_opaque_types - .get(&def_id.to_def_id()) - .map(|opaque| opaque.concrete_type) + .get_by(|(key, _)| key.def_id == def_id.to_def_id()) + .map(|concrete_ty| *concrete_ty) .unwrap_or_else(|| { tcx.sess.delay_span_bug( DUMMY_SP, @@ -515,7 +515,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } // Calling `mir_borrowck` can lead to cycle errors through // const-checking, avoid calling it if we don't have to. - if !self.tcx.typeck(def_id).concrete_opaque_types.contains_key(&self.def_id) { + if self + .tcx + .typeck(def_id) + .concrete_opaque_types + .get_by(|(key, _)| key.def_id == self.def_id) + .is_none() + { debug!( "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", self.def_id, def_id, @@ -523,11 +529,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { return; } // Use borrowck to get the type with unerased regions. - let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id); - if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { + let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; + if let Some((opaque_type_key, concrete_type)) = + concrete_opaque_types.iter().find(|(key, _)| key.def_id == self.def_id) + { debug!( "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", - self.def_id, def_id, ty, + self.def_id, def_id, concrete_type, ); // FIXME(oli-obk): trace the actual span from inference to improve errors. @@ -538,7 +546,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // using `delay_span_bug`, just in case `wfcheck` slips up. let opaque_generics = self.tcx.generics_of(self.def_id); let mut used_params: FxHashSet<_> = FxHashSet::default(); - for (i, arg) in substs.iter().enumerate() { + for (i, arg) in opaque_type_key.substs.iter().enumerate() { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) => { @@ -699,8 +707,8 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty let owner_typeck_results = tcx.typeck(scope_def_id); let concrete_ty = owner_typeck_results .concrete_opaque_types - .get(&opaque_ty_def_id) - .map(|opaque| opaque.concrete_type) + .get_by(|(key, _)| key.def_id == opaque_ty_def_id) + .map(|concrete_ty| *concrete_ty) .unwrap_or_else(|| { tcx.sess.delay_span_bug( DUMMY_SP, @@ -741,6 +749,40 @@ fn infer_placeholder_type( span: Span, item_ident: Ident, ) -> Ty<'_> { + // Attempts to make the type nameable by turning FnDefs into FnPtrs. + struct MakeNameable<'tcx> { + success: bool, + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> MakeNameable<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + MakeNameable { success: true, tcx } + } + } + + impl TypeFolder<'tcx> for MakeNameable<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !self.success { + return ty; + } + + match ty.kind() { + ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)), + // FIXME: non-capturing closures should also suggest a function pointer + ty::Closure(..) | ty::Generator(..) => { + self.success = false; + ty + } + _ => ty.super_fold_with(self), + } + } + } + let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id); // If this came from a free `const` or `static mut?` item, @@ -752,24 +794,47 @@ fn infer_placeholder_type( // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. err.suggestions.clear(); - err.span_suggestion( - span, - "provide a type for the item", - format!("{}: {}", item_ident, ty), - Applicability::MachineApplicable, - ) - .emit_unless(ty.references_error()); + + // Suggesting unnameable types won't help. + let mut mk_nameable = MakeNameable::new(tcx); + let ty = mk_nameable.fold_ty(ty); + let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; + if let Some(sugg_ty) = sugg_ty { + err.span_suggestion( + span, + "provide a type for the item", + format!("{}: {}", item_ident, sugg_ty), + Applicability::MachineApplicable, + ); + } else { + err.span_note( + tcx.hir().body(body_id).value.span, + &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + ); + } + + err.emit_unless(ty.references_error()); } None => { let mut diag = bad_placeholder_type(tcx, vec![span]); if !ty.references_error() { - diag.span_suggestion( - span, - "replace `_` with the correct type", - ty.to_string(), - Applicability::MaybeIncorrect, - ); + let mut mk_nameable = MakeNameable::new(tcx); + let ty = mk_nameable.fold_ty(ty); + let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; + if let Some(sugg_ty) = sugg_ty { + diag.span_suggestion( + span, + "replace with the correct type", + sugg_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_note( + tcx.hir().body(body_id).value.span, + &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + ); + } } diag.emit(); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 47299722325..92ef8297472 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -65,7 +65,6 @@ This API is completely unstable and subject to change. #![feature(is_sorted)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index aed36b12f3a..bccc19774e0 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -605,30 +605,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { 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), ); @@ -642,26 +647,34 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { }; 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), ); diff --git a/config.toml.example b/config.toml.example index 16952a5ced8..7fa5353d09b 100644 --- a/config.toml.example +++ b/config.toml.example @@ -94,7 +94,7 @@ changelog-seen = 2 # support. You'll need to write a target specification at least, and most # likely, teach rustc about the C ABI of the target. Get in touch with the # Rust team and file an issue if you need assistance in porting! -#targets = "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" +#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are @@ -563,6 +563,14 @@ changelog-seen = 2 # 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. diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index c9bdcaa78f3..91eec10d575 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -551,19 +551,13 @@ const LEN: usize = 16384; #[bench] fn bench_chain_collect(b: &mut Bencher) { let data = black_box([0; LEN]); - b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::<Vec<_>>()); + b.iter(|| data.iter().cloned().chain([1]).collect::<Vec<_>>()); } #[bench] fn bench_chain_chain_collect(b: &mut Bencher) { let data = black_box([0; LEN]); - b.iter(|| { - data.iter() - .cloned() - .chain([1].iter().cloned()) - .chain([2].iter().cloned()) - .collect::<Vec<_>>() - }); + b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::<Vec<_>>()); } #[bench] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index eb91af8c61c..13b42442dcf 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1209,7 +1209,7 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl<T> From<T> for Box<T> { - /// Converts a generic type `T` into a `Box<T>` + /// Converts a `T` into a `Box<T>` /// /// The conversion allocates on the heap and moves `t` /// from the stack into it. diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index a5481fd175e..1a58ad51f78 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -64,7 +64,15 @@ pub struct Iter<'a, T: 'a> { #[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() } } @@ -82,19 +90,24 @@ impl<T> Clone for Iter<'_, T> { /// 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() } } @@ -442,27 +455,6 @@ impl<T> LinkedList<T> { } } - /// Moves all elements from `other` to the begin of the list. - #[unstable(feature = "linked_list_prepend", issue = "none")] - pub fn prepend(&mut self, other: &mut Self) { - match self.head { - None => mem::swap(self, other), - Some(mut head) => { - // `as_mut` is okay here because we have exclusive access to the entirety - // of both lists. - if let Some(mut other_tail) = other.tail.take() { - unsafe { - head.as_mut().prev = Some(other_tail); - other_tail.as_mut().next = Some(head); - } - - self.head = other.head.take(); - self.len += mem::replace(&mut other.len, 0); - } - } - } - } - /// Provides a forward iterator. /// /// # Examples @@ -514,7 +506,7 @@ impl<T> LinkedList<T> { #[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. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7d6fbf1c438..5d03be35e46 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2416,7 +2416,6 @@ impl<T> VecDeque<T> { /// 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(); @@ -2432,7 +2431,6 @@ impl<T> VecDeque<T> { /// 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(); @@ -2441,7 +2439,7 @@ impl<T> VecDeque<T> { /// 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 @@ -2476,7 +2474,6 @@ impl<T> VecDeque<T> { /// 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(); @@ -2487,7 +2484,7 @@ impl<T> VecDeque<T> { /// 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, @@ -2530,7 +2527,6 @@ impl<T> VecDeque<T> { /// 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), @@ -2543,7 +2539,7 @@ impl<T> VecDeque<T> { /// 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 @@ -2574,7 +2570,6 @@ impl<T> VecDeque<T> { /// # Examples /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into(); @@ -2584,7 +2579,7 @@ impl<T> VecDeque<T> { /// 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, diff --git a/library/alloc/src/collections/vec_deque/pair_slices.rs b/library/alloc/src/collections/vec_deque/pair_slices.rs index 812765d0b0d..7b87090fb07 100644 --- a/library/alloc/src/collections/vec_deque/pair_slices.rs +++ b/library/alloc/src/collections/vec_deque/pair_slices.rs @@ -1,4 +1,3 @@ -use core::array; use core::cmp::{self}; use core::mem::replace; @@ -37,7 +36,7 @@ impl<'a, 'b, T> PairSlices<'a, 'b, T> { } pub fn remainder(self) -> impl Iterator<Item = &'b [T]> { - array::IntoIter::new([self.b0, self.b1]) + IntoIterator::into_iter([self.b0, self.b1]) } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3bc376482e9..7b0291c5f2e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -59,7 +59,6 @@ #![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))) @@ -88,8 +87,7 @@ #![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)] @@ -111,14 +109,12 @@ #![feature(iter_zip)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(maybe_uninit_ref)] #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] #![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)] @@ -146,6 +142,7 @@ #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(bindings_after_at)] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 800952f7a5e..f131182a896 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1859,6 +1859,18 @@ where 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 { @@ -2303,7 +2315,7 @@ impl<T: ?Sized> Weak<T> { } #[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 diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ec09595e357..93f5fe45cd6 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -48,7 +48,7 @@ use core::fmt; use core::hash; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; -use core::iter::FusedIterator; +use core::iter::{from_fn, FusedIterator}; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] @@ -843,6 +843,42 @@ impl String { 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 @@ -1254,32 +1290,49 @@ impl String { { use core::str::pattern::Searcher; - let matches = { + let rejections = { let mut searcher = pat.into_searcher(self); - let mut matches = Vec::new(); - - while let Some(m) = searcher.next_match() { - matches.push(m); - } - - matches + // Per Searcher::next: + // + // A Match result needs to contain the whole matched pattern, + // however Reject results may be split up into arbitrary many + // adjacent fragments. Both ranges may have zero length. + // + // In practice the implementation of Searcher::next_match tends to + // be more efficient, so we use it here and do some work to invert + // matches into rejections since that's what we want to copy below. + let mut front = 0; + let rejections: Vec<_> = from_fn(|| { + let (start, end) = searcher.next_match()?; + let prev_front = front; + front = end; + Some((prev_front, start)) + }) + .collect(); + rejections.into_iter().chain(core::iter::once((front, self.len()))) }; - let len = self.len(); - let mut shrunk_by = 0; + let mut len = 0; + let ptr = self.vec.as_mut_ptr(); + + for (start, end) in rejections { + let count = end - start; + if start != len { + // SAFETY: per Searcher::next: + // + // The stream of Match and Reject values up to a Done will + // contain index ranges that are adjacent, non-overlapping, + // covering the whole haystack, and laying on utf8 + // boundaries. + unsafe { + ptr::copy(ptr.add(start), ptr.add(len), count); + } + } + len += count; + } - // SAFETY: start and end will be on utf8 byte boundaries per - // the Searcher docs unsafe { - for (start, end) in matches { - ptr::copy( - self.vec.as_mut_ptr().add(end - shrunk_by), - self.vec.as_mut_ptr().add(start - shrunk_by), - len - end, - ); - shrunk_by += end - start; - } - self.vec.set_len(len - shrunk_by); + self.vec.set_len(len); } } @@ -2438,6 +2491,9 @@ impl AsRef<[u8]> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl From<&str> for String { + /// Converts a `&str` into a [`String`]. + /// + /// The result is allocated on the heap. #[inline] fn from(s: &str) -> String { s.to_owned() @@ -2447,7 +2503,7 @@ impl From<&str> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_mut_str_for_string", since = "1.44.0")] impl From<&mut str> for String { - /// Converts a `&mut str` into a `String`. + /// Converts a `&mut str` into a [`String`]. /// /// The result is allocated on the heap. #[inline] @@ -2459,6 +2515,9 @@ impl From<&mut str> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_ref_string", since = "1.35.0")] impl From<&String> for String { + /// Converts a `&String` into a [`String`]. + /// + /// This clones `s` and returns the clone. #[inline] fn from(s: &String) -> String { s.clone() @@ -2469,7 +2528,7 @@ impl From<&String> for String { #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From<Box<str>> for String { - /// Converts the given boxed `str` slice to a `String`. + /// Converts the given boxed `str` slice to a [`String`]. /// It is notable that the `str` slice is owned. /// /// # Examples @@ -2491,7 +2550,7 @@ impl From<Box<str>> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_str", since = "1.20.0")] impl From<String> for Box<str> { - /// Converts the given `String` to a boxed `str` slice that is owned. + /// Converts the given [`String`] to a boxed `str` slice that is owned. /// /// # Examples /// @@ -2512,6 +2571,22 @@ impl From<String> for Box<str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From<Cow<'a, str>> for String { + /// Converts a clone-on-write string to an owned + /// instance of [`String`]. + /// + /// This extracts the owned string, + /// clones the string if it is not already owned. + /// + /// # Example + /// + /// ``` + /// # use std::borrow::Cow; + /// // If the string is not owned... + /// let cow: Cow<str> = Cow::Borrowed("eggplant"); + /// // It will allocate on the heap and copy the string. + /// let owned: String = String::from(cow); + /// assert_eq!(&owned[..], "eggplant"); + /// ``` fn from(s: Cow<'a, str>) -> String { s.into_owned() } @@ -2520,7 +2595,7 @@ impl<'a> From<Cow<'a, str>> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Cow<'a, str> { - /// Converts a string slice into a Borrowed variant. + /// Converts a string slice into a [`Borrowed`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2530,6 +2605,8 @@ impl<'a> From<&'a str> for Cow<'a, str> { /// # use std::borrow::Cow; /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant")); /// ``` + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed #[inline] fn from(s: &'a str) -> Cow<'a, str> { Cow::Borrowed(s) @@ -2539,7 +2616,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<String> for Cow<'a, str> { - /// Converts a String into an Owned variant. + /// Converts a [`String`] into an [`Owned`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2551,6 +2628,8 @@ impl<'a> From<String> for Cow<'a, str> { /// let s2 = "eggplant".to_string(); /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2)); /// ``` + /// + /// [`Owned`]: crate::borrow::Cow::Owned #[inline] fn from(s: String) -> Cow<'a, str> { Cow::Owned(s) @@ -2560,7 +2639,7 @@ impl<'a> From<String> for Cow<'a, str> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "cow_from_string_ref", since = "1.28.0")] impl<'a> From<&'a String> for Cow<'a, str> { - /// Converts a String reference into a Borrowed variant. + /// Converts a [`String`] reference into a [`Borrowed`] variant. /// No heap allocation is performed, and the string /// is not copied. /// @@ -2571,6 +2650,8 @@ impl<'a> From<&'a String> for Cow<'a, str> { /// let s = "eggplant".to_string(); /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant")); /// ``` + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed #[inline] fn from(s: &'a String) -> Cow<'a, str> { Cow::Borrowed(s.as_str()) @@ -2603,7 +2684,7 @@ impl<'a> FromIterator<String> for Cow<'a, str> { #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] impl From<String> for Vec<u8> { - /// Converts the given `String` to a vector `Vec` that holds values of type `u8`. + /// Converts the given [`String`] to a vector [`Vec`] that holds values of type [`u8`]. /// /// # Examples /// @@ -2749,6 +2830,14 @@ impl FusedIterator for Drain<'_> {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_char_for_string", since = "1.46.0")] impl From<char> for String { + /// Allocates an owned [`String`] from a single character. + /// + /// # Example + /// ```rust + /// let c: char = 'a'; + /// let s: String = String::from(c); + /// assert_eq!("a", &s[..]); + /// ``` #[inline] fn from(c: char) -> Self { c.to_string() diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 17927f5f5fd..a8fa028fc90 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2015,7 +2015,7 @@ impl<T> Default for Weak<T> { } #[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 @@ -2413,6 +2413,18 @@ where 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 { diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 73d15d30647..64943a273c9 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -5,6 +5,12 @@ use super::Vec; #[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) } @@ -12,6 +18,12 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { #[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) } @@ -19,6 +31,12 @@ impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> { #[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()) } diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index b5739970b6e..0efc4893c3c 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -69,3 +69,36 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> { 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, +); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1c33ff555d6..4a1d564e2ab 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -921,7 +921,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// ``` /// let mut vec = Vec::with_capacity(10); - /// vec.extend([1, 2, 3].iter().cloned()); + /// vec.extend([1, 2, 3]); /// assert_eq!(vec.capacity(), 10); /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); @@ -950,7 +950,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` /// #![feature(shrink_to)] /// let mut vec = Vec::with_capacity(10); - /// vec.extend([1, 2, 3].iter().cloned()); + /// vec.extend([1, 2, 3]); /// assert_eq!(vec.capacity(), 10); /// vec.shrink_to(4); /// assert!(vec.capacity() >= 4); @@ -984,7 +984,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// ``` /// let mut vec = Vec::with_capacity(10); - /// vec.extend([1, 2, 3].iter().cloned()); + /// vec.extend([1, 2, 3]); /// /// assert_eq!(vec.capacity(), 10); /// let slice = vec.into_boxed_slice(); @@ -1619,6 +1619,8 @@ impl<T, A: Allocator> Vec<T, A> { 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 { @@ -1631,9 +1633,8 @@ impl<T, A: Allocator> Vec<T, A> { /* 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 @@ -2585,7 +2586,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` /// let mut v = vec![1, 2, 3]; /// let new = [7, 8]; - /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect(); + /// let u: Vec<_> = v.splice(..2, new).collect(); /// assert_eq!(v, &[7, 8, 3]); /// assert_eq!(u, &[1, 2]); /// ``` diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index bbfcc68daef..efa6868473e 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,6 +1,5 @@ use core::mem::ManuallyDrop; use core::ptr::{self}; -use core::slice::{self}; use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; @@ -19,9 +18,7 @@ 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> { @@ -65,33 +62,3 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> { 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) - } -} diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index 0a27b5b62ec..bad765c7f51 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -14,7 +14,7 @@ use super::{Drain, Vec}; /// ``` /// let mut v = vec![0, 1, 2]; /// let new = [7, 8]; -/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); +/// let iter: std::vec::Splice<_> = v.splice(1.., new); /// ``` #[derive(Debug)] #[stable(feature = "vec_splice", since = "1.21.0")] diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index c02ba267056..ce40b5c9b0a 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -195,3 +195,18 @@ fn shared_from_iter_trustedlen_no_fuse() { 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` +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 25a83a0b014..3143afa269d 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -17,7 +17,6 @@ #![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)] diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs index 501b4f0f816..efb39a60966 100644 --- a/library/alloc/tests/rc.rs +++ b/library/alloc/tests/rc.rs @@ -191,3 +191,18 @@ fn shared_from_iter_trustedlen_no_fuse() { 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` +} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index ad69234403b..c203cdafecb 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -793,7 +793,7 @@ fn test_drain_leak() { fn test_splice() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - v.splice(2..4, a.iter().cloned()); + v.splice(2..4, a); assert_eq!(v, &[1, 2, 10, 11, 12, 5]); v.splice(1..3, Some(20)); assert_eq!(v, &[1, 20, 11, 12, 5]); @@ -803,7 +803,7 @@ fn test_splice() { fn test_splice_inclusive_range() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect(); + let t1: Vec<_> = v.splice(2..=3, a).collect(); assert_eq!(v, &[1, 2, 10, 11, 12, 5]); assert_eq!(t1, &[3, 4]); let t2: Vec<_> = v.splice(1..=2, Some(20)).collect(); @@ -816,7 +816,7 @@ fn test_splice_inclusive_range() { fn test_splice_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - v.splice(5..6, a.iter().cloned()); + v.splice(5..6, a); } #[test] @@ -824,7 +824,7 @@ fn test_splice_out_of_bounds() { fn test_splice_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - v.splice(5..=5, a.iter().cloned()); + v.splice(5..=5, a); } #[test] @@ -848,7 +848,7 @@ fn test_splice_unbounded() { fn test_splice_forget() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - std::mem::forget(v.splice(2..4, a.iter().cloned())); + std::mem::forget(v.splice(2..4, a)); assert_eq!(v, &[1, 2]); } @@ -2234,48 +2234,50 @@ fn test_vec_dedup() { #[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); diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index c36542f6314..aedbeab6610 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -139,7 +139,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { // 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() } } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 8b56c9560aa..37af3557fdd 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -1,6 +1,4 @@ -//! 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).* @@ -158,7 +156,6 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] { // 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; @@ -419,7 +416,7 @@ impl<T, const N: usize> [T; N] { { // SAFETY: we know for certain that this iterator will yield exactly `N` // items. - unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) } + unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) } } /// 'Zips up' two arrays into a single array of pairs. @@ -440,7 +437,7 @@ impl<T, const N: usize> [T; N] { /// ``` #[unstable(feature = "array_zip", issue = "80094")] pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] { - let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs)); + let mut iter = IntoIterator::into_iter(self).zip(rhs); // SAFETY: we know for certain that this iterator will yield exactly `N` // items. diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index dcab2cd2d9d..80d0890551f 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1,6 +1,5 @@ //! impl char {} -use crate::intrinsics::likely; use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; @@ -58,7 +57,7 @@ impl char { /// ]; /// /// assert_eq!( - /// decode_utf16(v.iter().cloned()) + /// decode_utf16(v) /// .map(|r| r.map_err(|e| e.unpaired_surrogate())) /// .collect::<Vec<_>>(), /// vec![ @@ -82,7 +81,7 @@ impl char { /// ]; /// /// assert_eq!( - /// decode_utf16(v.iter().cloned()) + /// decode_utf16(v) /// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) /// .collect::<String>(), /// "𝄞mus�ic�" @@ -332,21 +331,16 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option<u32> { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); - // the code is split up here to improve execution speed for cases where - // the `radix` is constant and 10 or smaller - let val = if likely(radix <= 10) { - // If not a digit, a number greater than radix will be created. - (self as u32).wrapping_sub('0' as u32) - } else { - match self { - '0'..='9' => self as u32 - '0' as u32, - 'a'..='z' => self as u32 - 'a' as u32 + 10, - 'A'..='Z' => self as u32 - 'A' as u32 + 10, - _ => return None, + // If not a digit, a number greater than radix will be created. + let mut digit = (self as u32).wrapping_sub('0' as u32); + if radix > 10 { + if digit < 10 { + return Some(digit); } - }; - - if val < radix { Some(val) } else { None } + // Force the 6th bit to be set to ensure ascii is lower case. + digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10); + } + (digit < radix).then_some(digit) } /// Returns an iterator that yields the hexadecimal Unicode escape of a diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3f0acf435fe..ecea898504d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -274,7 +274,7 @@ pub trait Eq: PartialEq<Self> { // // 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) {} diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index afef790ca64..02ac4fb8006 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1245,12 +1245,13 @@ impl<'a> Formatter<'a> { /// // 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"); /// ``` diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index cc4cf54a2f7..15952c6806f 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -24,8 +24,7 @@ use crate::task::{Context, Poll}; /// `.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"] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0034de9ad1b..70ab27cbfac 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1742,157 +1742,6 @@ extern "rust-intrinsic" { /// Allocate at compile time. Should not be called at runtime. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub fn const_allocate(size: usize, align: usize) -> *mut u8; - - /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. - /// - /// For regions of memory which might overlap, use [`copy`] instead. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but - /// with the argument order swapped. - /// - /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// * The region of memory beginning at `src` with a size of `count * - /// size_of::<T>()` bytes must *not* overlap with the region of memory - /// beginning at `dst` with the same size. - /// - /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::<T>()`) is - /// `0`, the pointers must be non-null and properly aligned. - /// - /// [`read`]: crate::ptr::read - /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value - /// [valid]: crate::ptr#safety - /// - /// # Examples - /// - /// Manually implement [`Vec::append`]: - /// - /// ``` - /// use std::ptr; - /// - /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. - /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) { - /// let src_len = src.len(); - /// let dst_len = dst.len(); - /// - /// // Ensure that `dst` has enough capacity to hold all of `src`. - /// dst.reserve(src_len); - /// - /// unsafe { - /// // The call to offset is always safe because `Vec` will never - /// // allocate more than `isize::MAX` bytes. - /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); - /// let src_ptr = src.as_ptr(); - /// - /// // Truncate `src` without dropping its contents. We do this first, - /// // to avoid problems in case something further down panics. - /// src.set_len(0); - /// - /// // The two regions cannot overlap because mutable references do - /// // not alias, and two different vectors cannot own the same - /// // memory. - /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); - /// - /// // Notify `dst` that it now holds the contents of `src`. - /// dst.set_len(dst_len + src_len); - /// } - /// } - /// - /// let mut a = vec!['r']; - /// let mut b = vec!['u', 's', 't']; - /// - /// append(&mut a, &mut b); - /// - /// assert_eq!(a, &['r', 'u', 's', 't']); - /// assert!(b.is_empty()); - /// ``` - /// - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append - #[doc(alias = "memcpy")] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); - - /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source - /// and destination may overlap. - /// - /// If the source and destination will *never* overlap, - /// [`copy_nonoverlapping`] can be used instead. - /// - /// `copy` is semantically equivalent to C's [`memmove`], but with the argument - /// order swapped. Copying takes place as if the bytes were copied from `src` - /// to a temporary array and then copied from the array to `dst`. - /// - /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::<T>()`) is - /// `0`, the pointers must be non-null and properly aligned. - /// - /// [`read`]: crate::ptr::read - /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value - /// [valid]: crate::ptr#safety - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// use std::ptr; - /// - /// /// # Safety - /// /// - /// /// * `ptr` must be correctly aligned for its type and non-zero. - /// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. - /// /// * Those elements must not be used after calling this function unless `T: Copy`. - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> { - /// let mut dst = Vec::with_capacity(elts); - /// - /// // SAFETY: Our precondition ensures the source is aligned and valid, - /// // and `Vec::with_capacity` ensures that we have usable space to write them. - /// ptr::copy(ptr, dst.as_mut_ptr(), elts); - /// - /// // SAFETY: We created it with this much capacity earlier, - /// // and the previous `copy` has initialized these elements. - /// dst.set_len(elts); - /// dst - /// } - /// ``` - #[doc(alias = "memmove")] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] - pub fn copy<T>(src: *const T, dst: *mut T, count: usize); } // Some functions are defined here because they accidentally got made @@ -1906,6 +1755,192 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool { !ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0 } +/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the argument order swapped. +/// +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::<T>()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::<T>()`) is +/// `0`, the pointers must be non-null and properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to offset is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[doc(alias = "memcpy")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } + + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) + && !(is_aligned_and_not_null(src) + && is_aligned_and_not_null(dst) + && is_nonoverlapping(src, dst, count)) + { + // Not panicking to keep codegen impact smaller. + abort(); + }*/ + + // SAFETY: the safety contract for `copy_nonoverlapping` must be + // upheld by the caller. + unsafe { copy_nonoverlapping(src, dst, count) } +} + +/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but with the argument +/// order swapped. Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::<T>()`) is +/// `0`, the pointers must be non-null and properly aligned. +/// +/// [`read`]: crate::ptr::read +/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value +/// [valid]: crate::ptr#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> { +/// let mut dst = Vec::with_capacity(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. +/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); +/// dst +/// } +/// ``` +#[doc(alias = "memmove")] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] +#[inline] +pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy<T>(src: *const T, dst: *mut T, count: usize); + } + + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { + // Not panicking to keep codegen impact smaller. + abort(); + }*/ + + // SAFETY: the safety contract for `copy` must be upheld by the caller. + unsafe { copy(src, dst, count) } +} + /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to /// `val`. /// diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 92f82ae2325..beda8c32c6b 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,8 +1,5 @@ use crate::cmp; -use crate::iter::{ - adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable, - TrustedLen, TrustedRandomAccess, -}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::{ControlFlow, Try}; /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -114,15 +111,6 @@ where self.try_fold(init, ok(fold)).unwrap() } - - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item - where - Self: TrustedRandomAccess, - { - // SAFETY: the caller must uphold the contract for - // `Iterator::__iterator_get_unchecked`. - unsafe { try_get_unchecked(&mut self.iter, idx) } - } } #[unstable(issue = "none", feature = "inplace_iteration")] @@ -219,12 +207,3 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<I> TrustedRandomAccess for Take<I> -where - I: TrustedRandomAccess, -{ - const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT; -} diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 2f8f504d8fc..c95324c80ba 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -434,7 +434,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B /// 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()` /// diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 2a179f0b1d7..bfb27da505e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -384,6 +384,8 @@ pub use self::traits::FusedIterator; 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, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 8d0b2b9f55c..de5d77e96ee 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,21 +3,23 @@ use crate::convert::TryFrom; 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` @@ -55,7 +57,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// /// * `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* @@ -81,7 +82,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// * 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`") } @@ -106,7 +106,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// 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) } @@ -127,7 +126,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// /// * `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* @@ -153,7 +151,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// * 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`") } @@ -178,7 +175,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// 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) } @@ -237,7 +233,7 @@ macro_rules! step_integer_impls { $( #[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] @@ -269,7 +265,7 @@ macro_rules! step_integer_impls { #[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] @@ -333,7 +329,7 @@ macro_rules! step_integer_impls { $( #[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] @@ -358,7 +354,7 @@ macro_rules! step_integer_impls { #[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] @@ -408,7 +404,7 @@ step_integer_impls! { } #[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; @@ -512,15 +508,27 @@ macro_rules! range_incl_exact_iter_impl { )*) } -#[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 @@ -528,17 +536,59 @@ impl<A: Step> Iterator for ops::Range<A> { } #[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 @@ -552,6 +602,56 @@ impl<A: Step> Iterator for ops::Range<A> { } #[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() } @@ -631,32 +731,36 @@ range_incl_exact_iter_impl! { 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> {} @@ -684,18 +788,130 @@ impl<A: Step> Iterator for ops::RangeFrom<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; } @@ -711,6 +927,90 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { } #[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() { return (0, Some(0)); @@ -751,32 +1051,13 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { } #[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] @@ -813,18 +1094,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { 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] @@ -856,32 +1126,13 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { } #[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] @@ -899,8 +1150,9 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { } } +// 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> {} diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 13a2e24cadd..e2a407509b1 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -198,7 +198,7 @@ pub trait FromIterator<A>: Sized { /// } /// ``` #[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. diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c2e280ff07d..11dea400a46 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -26,40 +26,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[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", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ @@ -80,11 +46,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} 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 \ syntax `start..end` or the inclusive range syntax `start..=end`" @@ -92,8 +53,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} 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 { @@ -178,7 +138,7 @@ pub trait Iterator { /// A more complex example: /// /// ``` - /// // The even numbers from zero to ten. + /// // The even numbers in the range of zero to nine. /// let iter = (0..10).filter(|x| x % 2 == 0); /// /// // We might iterate from zero to ten times. Knowing that it's five @@ -2608,6 +2568,18 @@ 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: @@ -2631,8 +2603,20 @@ pub trait Iterator { /// 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 /// diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 22b5ffdf886..ebf37f97bc6 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -1,3 +1,5 @@ +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 @@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {} #[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 {} diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index 880f8d831fd..ffd745a46b1 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -13,5 +13,7 @@ pub use self::exact_size::ExactSizeIterator; 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}; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f652c52db53..949ef27f018 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -51,7 +51,6 @@ #![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))), @@ -66,6 +65,7 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] +#![feature(bool_to_option)] #![feature(cfg_target_has_atomic)] #![feature(const_heap)] #![feature(const_alloc_layout)] @@ -82,12 +82,12 @@ #![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)] @@ -110,8 +110,7 @@ #![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)] @@ -127,7 +126,6 @@ #![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)] @@ -162,14 +160,15 @@ #![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)] +#![cfg_attr(bootstrap, feature(target_feature_11))] #![deny(unsafe_op_in_unsafe_fn)] +#![deny(or_patterns_back_compat)] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] @@ -304,8 +303,7 @@ pub mod primitive; 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)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index b46a7aa138c..7eb65483b99 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -138,7 +138,7 @@ macro_rules! assert_ne { #[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 => { @@ -150,7 +150,7 @@ macro_rules! assert_matches { } } }); - ($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 => { @@ -315,7 +315,7 @@ macro_rules! debug_assert_matches { #[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 @@ -595,7 +595,7 @@ macro_rules! unreachable { /// 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 diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 5b99f6954e6..d86939454be 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -44,7 +44,7 @@ use crate::ptr; /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] -#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct ManuallyDrop<T: ?Sized> { value: T, @@ -160,16 +160,3 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { &mut self.value } } - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl<T: Clone> Clone for ManuallyDrop<T> { - #[inline] - fn clone(&self) -> ManuallyDrop<T> { - ManuallyDrop { value: self.value.clone() } - } - - #[inline] - fn clone_from(&mut self, other: &Self) { - self.value.clone_from(&other.value) - } -} diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 10219201a40..623fd745a5e 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -665,7 +665,6 @@ impl<T> MaybeUninit<T> { /// ### Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); @@ -683,7 +682,6 @@ impl<T> MaybeUninit<T> { /// ### *Incorrect* usages of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<Vec<u32>>::uninit(); @@ -692,7 +690,6 @@ impl<T> MaybeUninit<T> { /// ``` /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{cell::Cell, mem::MaybeUninit}; /// /// let b = MaybeUninit::<Cell<bool>>::uninit(); @@ -703,7 +700,7 @@ impl<T> MaybeUninit<T> { /// // Reference to an uninitialized `Cell<bool>`: UB! /// } /// ``` - #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn assume_init_ref(&self) -> &T { @@ -733,7 +730,6 @@ impl<T> MaybeUninit<T> { /// ### Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] } @@ -769,7 +765,6 @@ impl<T> MaybeUninit<T> { /// You cannot use `.assume_init_mut()` to initialize a value: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::mem::MaybeUninit; /// /// let mut b = MaybeUninit::<bool>::uninit(); @@ -785,7 +780,6 @@ impl<T> MaybeUninit<T> { /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{io, mem::MaybeUninit}; /// /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> @@ -802,7 +796,6 @@ impl<T> MaybeUninit<T> { /// Nor can you use direct field access to do field-by-field gradual initialization: /// /// ```rust,no_run - /// #![feature(maybe_uninit_ref)] /// use std::{mem::MaybeUninit, ptr}; /// /// struct Foo { @@ -823,10 +816,7 @@ impl<T> MaybeUninit<T> { /// foo.assume_init() /// }; /// ``` - // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references - // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make - // a final decision about the rules before stabilization. - #[unstable(feature = "maybe_uninit_ref", issue = "63568")] + #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")] #[inline(always)] pub const unsafe fn assume_init_mut(&mut self) -> &mut T { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5bf47c3951d..c6750c52d16 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -682,8 +682,7 @@ pub unsafe fn uninitialized<T>() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] -pub const fn swap<T>(x: &mut T, y: &mut T) { +pub fn swap<T>(x: &mut T, y: &mut T) { // SAFETY: the raw pointers have been created from safe mutable references satisfying all the // constraints on `ptr::swap_nonoverlapping_one` unsafe { @@ -813,8 +812,7 @@ pub fn take<T: Default>(dest: &mut T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] -#[rustc_const_unstable(feature = "const_replace", issue = "83164")] -pub const fn replace<T>(dest: &mut T, src: T) -> T { +pub fn replace<T>(dest: &mut T, src: T) -> T { // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and // nothing here can panic. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 0d6d919d998..c47a2e8b05c 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -727,8 +727,8 @@ impl f32 { /// /// 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. @@ -854,35 +854,6 @@ impl f32 { 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 diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 42214e7b50d..cfcc08b9add 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -741,8 +741,8 @@ impl f64 { /// /// 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. @@ -868,35 +868,6 @@ impl f64 { 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 diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 47b2b30563c..a0efe681285 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -407,8 +407,15 @@ macro_rules! int_impl { } /// 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", @@ -446,8 +453,15 @@ macro_rules! int_impl { } /// 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", @@ -485,8 +499,15 @@ macro_rules! int_impl { } /// 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", @@ -645,6 +666,31 @@ macro_rules! int_impl { 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`. /// @@ -666,6 +712,31 @@ macro_rules! int_impl { 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`. /// @@ -1842,36 +1913,6 @@ macro_rules! int_impl { 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. /// diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6b9b435d47f..dd9b9330aee 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -42,7 +42,8 @@ macro_rules! nonzero_integers { pub struct $Ty($Int); impl $Ty { - /// Creates a non-zero without checking the value. + /// Creates a non-zero without checking whether the value is non-zero. + /// This results in undefined behaviour if the value is zero. /// /// # Safety /// @@ -285,6 +286,576 @@ nonzero_integers_div! { NonZeroUsize(usize); } +// A bunch of methods for unsigned nonzero types only. +macro_rules! nonzero_unsigned_operations { + ( $( $Ty: ident($Int: ty); )+ ) => { + $( + impl $Ty { + /// Add an unsigned integer to a non-zero value. + /// Check for overflow and return [`None`] on overflow + /// As a consequence, the result cannot wrap to zero. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), one.checked_add(1)); + /// assert_eq!(None, max.checked_add(1)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_add(self, other: $Int) -> Option<$Ty> { + if let Some(result) = self.get().checked_add(other) { + // SAFETY: $Int::checked_add returns None on overflow + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Add an unsigned integer to a non-zero value. + #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(two, one.saturating_add(1)); + /// assert_eq!(max, max.saturating_add(1)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_add(self, other: $Int) -> $Ty { + // SAFETY: $Int::saturating_add returns $Int::MAX on overflow + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } + } + + /// Add an unsigned integer to a non-zero value, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + /// + /// assert_eq!(two, unsafe { one.unchecked_add(1) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub unsafe fn unchecked_add(self, other: $Int) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } + } + + /// Returns the smallest power of two greater than or equal to n. + /// Check for overflow and return [`None`] + /// if the next power of two is greater than the type’s maximum value. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(two), two.checked_next_power_of_two() ); + /// assert_eq!(Some(four), three.checked_next_power_of_two() ); + /// assert_eq!(None, max.checked_next_power_of_two() ); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_next_power_of_two(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_next_power_of_two() { + // SAFETY: The next power of two is positive + // and overflow is checked. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } + } + )+ + } +} + +nonzero_unsigned_operations! { + NonZeroU8(u8); + NonZeroU16(u16); + NonZeroU32(u32); + NonZeroU64(u64); + NonZeroU128(u128); + NonZeroUsize(usize); +} + +// A bunch of methods for signed nonzero types only. +macro_rules! nonzero_signed_operations { + ( $( $Ty: ident($Int: ty) -> $Uty: ident($Uint: ty); )+ ) => { + $( + impl $Ty { + /// Computes the absolute value of self. + #[doc = concat!("See [`", stringify!($Int), "::abs`]")] + /// for documentation on overflow behaviour. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + /// + /// assert_eq!(pos, pos.abs()); + /// assert_eq!(pos, neg.abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn abs(self) -> $Ty { + // SAFETY: This cannot overflow to zero. + unsafe { $Ty::new_unchecked(self.get().abs()) } + } + + /// Checked absolute value. + /// Check for overflow and returns [`None`] if + #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] + /// The result cannot be zero. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!(Some(pos), neg.checked_abs()); + /// assert_eq!(None, min.checked_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_abs(self) -> Option<$Ty> { + if let Some(nz) = self.get().checked_abs() { + // SAFETY: absolute value of nonzero cannot yield zero values. + Some(unsafe { $Ty::new_unchecked(nz) }) + } else { + None + } + } + + /// Computes the absolute value of self, + /// with overflow information, see + #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + /// + /// assert_eq!((pos, false), pos.overflowing_abs()); + /// assert_eq!((pos, false), neg.overflowing_abs()); + /// assert_eq!((min, true), min.overflowing_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn overflowing_abs(self) -> ($Ty, bool) { + let (nz, flag) = self.get().overflowing_abs(); + ( + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(nz) }, + flag, + ) + } + + /// Saturating absolute value, see + #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.saturating_abs()); + /// assert_eq!(pos, neg.saturating_abs()); + /// assert_eq!(max, min.saturating_abs()); + /// assert_eq!(max, min_plus.saturating_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().saturating_abs()) } + } + + /// Wrapping absolute value, see + #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")] + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(pos, pos.wrapping_abs()); + /// assert_eq!(pos, neg.wrapping_abs()); + /// assert_eq!(min, min.wrapping_abs()); + /// # // FIXME: add once Neg is implemented? + /// # // assert_eq!(max, (-max).wrapping_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn wrapping_abs(self) -> $Ty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) } + } + + /// Computes the absolute value of self + /// without any wrapping or panicking. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + #[doc = concat!("# use std::num::", stringify!($Uty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")] + #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let i_min = ", stringify!($Ty), "::new(", + stringify!($Int), "::MIN)?;")] + #[doc = concat!("let u_max = ", stringify!($Uty), "::new(", + stringify!($Uint), "::MAX / 2 + 1)?;")] + /// + /// assert_eq!(u_pos, i_pos.unsigned_abs()); + /// assert_eq!(u_pos, i_neg.unsigned_abs()); + /// assert_eq!(u_max, i_min.unsigned_abs()); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn unsigned_abs(self) -> $Uty { + // SAFETY: absolute value of nonzero cannot yield zero values. + unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } + } + } + )+ + } +} + +nonzero_signed_operations! { + NonZeroI8(i8) -> NonZeroU8(u8); + NonZeroI16(i16) -> NonZeroU16(u16); + NonZeroI32(i32) -> NonZeroU32(u32); + NonZeroI64(i64) -> NonZeroU64(u64); + NonZeroI128(i128) -> NonZeroU128(u128); + NonZeroIsize(isize) -> NonZeroUsize(usize); +} + +// A bunch of methods for both signed and unsigned nonzero types. +macro_rules! nonzero_unsigned_signed_operations { + ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { + $( + impl $Ty { + /// Multiply two non-zero integers together. + /// Check for overflow and return [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(Some(four), two.checked_mul(two)); + /// assert_eq!(None, max.checked_mul(two)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { + if let Some(result) = self.get().checked_mul(other.get()) { + // SAFETY: checked_mul returns None on overflow + // and `other` is also non-null + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Multiply two non-zero integers together. + #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(four, two.saturating_mul(two)); + /// assert_eq!(max, four.saturating_mul(max)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_mul(self, other: $Ty) -> $Ty { + // SAFETY: saturating_mul returns u*::MAX on overflow + // and `other` is also non-null + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } + } + + /// Multiply two non-zero integers together, + /// assuming overflow cannot occur. + /// Overflow is unchecked, and it is undefined behaviour to overflow + /// *even if the result would wrap to a non-zero value*. + /// The behaviour is undefined as soon as + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("`self * rhs > ", stringify!($Int), "::MAX`, ", + "or `self * rhs < ", stringify!($Int), "::MIN`.") + } + if unsigned { + concat!("`self * rhs > ", stringify!($Int), "::MAX`.") + } + }] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + /// + /// assert_eq!(four, unsafe { two.unchecked_mul(two) }); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + // SAFETY: The caller ensures there is no overflow. + unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } + } + + /// Raise non-zero value to an integer power. + /// Check for overflow and return [`None`] on overflow. + /// As a consequence, the result cannot wrap to zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let half_max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX / 2)?;")] + /// + /// assert_eq!(Some(twenty_seven), three.checked_pow(3)); + /// assert_eq!(None, half_max.checked_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn checked_pow(self, other: u32) -> Option<$Ty> { + if let Some(result) = self.get().checked_pow(other) { + // SAFETY: checked_pow returns None on overflow + // so the result cannot be zero. + Some(unsafe { $Ty::new_unchecked(result) }) + } else { + None + } + } + + /// Raise non-zero value to an integer power. + #[doc = sign_dependent_expr!{ + $signedness ? + if signed { + concat!("Return [`", stringify!($Int), "::MIN`] ", + "or [`", stringify!($Int), "::MAX`] on overflow.") + } + if unsigned { + concat!("Return [`", stringify!($Int), "::MAX`] on overflow.") + } + }] + /// + /// # Examples + /// + /// ``` + /// #![feature(nonzero_ops)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] + #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] + #[doc = concat!("let max = ", stringify!($Ty), "::new(", + stringify!($Int), "::MAX)?;")] + /// + /// assert_eq!(twenty_seven, three.saturating_pow(3)); + /// assert_eq!(max, max.saturating_pow(3)); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_ops", issue = "84186")] + #[inline] + pub const fn saturating_pow(self, other: u32) -> $Ty { + // SAFETY: saturating_pow returns u*::MAX on overflow + // so the result cannot be zero. + unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } + } + } + )+ + } +} + +// Use this when the generated code should differ between signed and unsigned types. +macro_rules! sign_dependent_expr { + (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $signed_case + }; + (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => { + $unsigned_case + }; +} + +nonzero_unsigned_signed_operations! { + unsigned NonZeroU8(u8); + unsigned NonZeroU16(u16); + unsigned NonZeroU32(u32); + unsigned NonZeroU64(u64); + unsigned NonZeroU128(u128); + unsigned NonZeroUsize(usize); + signed NonZeroI8(i8); + signed NonZeroI16(i16); + signed NonZeroI32(i32); + signed NonZeroI64(i64); + signed NonZeroI128(i128); + signed NonZeroIsize(isize); +} + macro_rules! nonzero_unsigned_is_power_of_two { ( $( $Ty: ident )+ ) => { $( diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index f9fd28b6a8c..e512d90ef37 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -417,8 +417,15 @@ macro_rules! uint_impl { } /// 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", @@ -456,8 +463,15 @@ macro_rules! uint_impl { } /// 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", @@ -495,8 +509,15 @@ macro_rules! uint_impl { } /// 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", @@ -655,6 +676,31 @@ macro_rules! uint_impl { 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`. /// @@ -676,6 +722,31 @@ macro_rules! uint_impl { 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. /// @@ -1672,36 +1743,6 @@ macro_rules! uint_impl { 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. /// diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index dbb51540bd4..9d9398fb56d 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -63,6 +63,7 @@ pub enum ControlFlow<B, C = ()> { } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[cfg(bootstrap)] impl<B, C> ops::TryV1 for ControlFlow<B, C> { type Output = C; type Error = B; @@ -186,9 +187,8 @@ impl<B, C> ControlFlow<B, C> { #[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)), @@ -196,9 +196,8 @@ impl<R: ops::TryV1> ControlFlow<R, R::Output> { } /// 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, @@ -206,12 +205,14 @@ impl<R: ops::TryV1> ControlFlow<R, R::Output> { } } +/// 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)), @@ -219,9 +220,8 @@ impl<R: ops::TryV2> ControlFlow<R, R::Output> { } /// 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, diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index beef74de617..139a8c0eec9 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -147,6 +147,7 @@ mod function; mod generator; mod index; mod range; +#[cfg(bootstrap)] mod r#try; mod try_trait; mod unsize; @@ -187,6 +188,7 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; pub use self::r#try::Try; #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] +#[cfg(bootstrap)] pub(crate) use self::r#try::Try as TryV1; #[unstable(feature = "try_trait_v2", issue = "84277")] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index dbeb3912130..bb948376bc7 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -674,10 +674,10 @@ pub enum Bound<T> { 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), @@ -686,8 +686,9 @@ impl<T> Bound<T> { } } - /// Converts from `&mut Bound<T>` to `Bound<&T>`. + /// Converts from `&mut Bound<T>` to `Bound<&mut 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), @@ -695,6 +696,39 @@ impl<T> Bound<T> { 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> { diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 87044ed2fce..1d9bc452618 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -259,6 +259,18 @@ pub trait Try: FromResidual { 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_desugaring = "QuestionMark", + _Self = "std::option::Option<T>", ), // `Option`-in-`Option` always works, as there's only one possible // residual, so this can also be phrased strongly. @@ -272,9 +284,10 @@ pub trait Try: FromResidual { 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`" @@ -282,6 +295,18 @@ pub trait Try: FromResidual { 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", from_desugaring = "QuestionMark" ), message = "the `?` operator can only be used in {ItemContext} \ diff --git a/library/core/src/option.rs b/library/core/src/option.rs index cfc1768dee9..4e7afca6a49 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -83,6 +83,8 @@ //! * [`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` @@ -1641,9 +1643,11 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { #[rustc_diagnostic_item = "none_error"] #[unstable(feature = "try_trait", issue = "42327")] #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[cfg(bootstrap)] pub struct NoneError; #[unstable(feature = "try_trait", issue = "42327")] +#[cfg(bootstrap)] impl<T> ops::TryV1 for Option<T> { type Output = T; type Error = NoneError; diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 8f57db49496..79753c1fb66 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -11,9 +11,9 @@ pub mod v1; /// 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::*; } @@ -21,9 +21,9 @@ pub mod rust_2015 { /// 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::*; } @@ -31,11 +31,17 @@ pub mod rust_2018 { /// 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}; } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 214d7c8bc15..6a6cee0911f 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -430,8 +430,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { } #[inline] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] -pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { +pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary // reinterpretation of values as (chunkable) byte arrays, and the loop in the // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back @@ -564,8 +563,7 @@ const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_replace", issue = "83164")] -pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T { +pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be // cast to a mutable reference (valid for writes, aligned, initialized), // and cannot overlap `src` since `dst` must point to a distinct @@ -871,14 +869,18 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] -pub const unsafe fn write<T>(dst: *mut T, src: T) { +pub unsafe fn write<T>(dst: *mut T, src: T) { + // We are calling the intrinsics directly to avoid function calls in the generated code + // as `intrinsics::copy_nonoverlapping` is a wrapper function. + extern "rust-intrinsic" { + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } + // SAFETY: the caller must guarantee that `dst` is valid for writes. // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { copy_nonoverlapping(&src as *const T, dst, 1); - // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 750279ac0db..a6424041542 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1002,9 +1002,8 @@ impl<T: ?Sized> *mut T { /// /// [`ptr::write`]: crate::ptr::write() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")] #[inline(always)] - pub const unsafe fn write(self, val: T) + pub unsafe fn write(self, val: T) where T: Sized, { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 21e406194bc..babd0a0b552 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1627,6 +1627,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } #[unstable(feature = "try_trait", issue = "42327")] +#[cfg(bootstrap)] impl<T, E> ops::TryV1 for Result<T, E> { type Output = T; type Error = E; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 0923175414e..0e5c5ee726e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2100,9 +2100,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. /// @@ -2153,9 +2155,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. /// @@ -2224,9 +2228,11 @@ impl<T> [T] { /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any - /// one of the matches could be returned. If the value is not found then - /// [`Result::Err`] is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. + /// one of the matches could be returned. The index is chosen + /// deterministically, but is subject to change in future versions of Rust. + /// If the value is not found then [`Result::Err`] is returned, containing + /// the index where a matching element could be inserted while maintaining + /// sorted order. /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// @@ -3096,7 +3102,11 @@ impl<T> [T] { // 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); } } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 188639e7962..9cf89623d88 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -129,6 +129,7 @@ impl<T> From<T> for Poll<T> { } #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg(bootstrap)] impl<T, E> ops::TryV1 for Poll<Result<T, E>> { type Output = Poll<T>; type Error = E; @@ -184,6 +185,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg(bootstrap)] impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> { type Output = Poll<Option<T>>; type Error = E; diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs index b0dc9903464..b36d6f0d404 100644 --- a/library/core/tests/any.rs +++ b/library/core/tests/any.rs @@ -114,3 +114,16 @@ fn any_unsized() { 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)),); +} diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index ce7480ce2ee..0ae625bdb68 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::{self, IntoIter}; +use core::array; use core::convert::TryFrom; #[test] @@ -41,14 +41,14 @@ fn array_try_from() { #[test] fn iterator_collect() { let arr = [0, 1, 2, 5, 9]; - let v: Vec<_> = IntoIter::new(arr.clone()).collect(); + let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect(); assert_eq!(&arr[..], &v[..]); } #[test] fn iterator_rev_collect() { let arr = [0, 1, 2, 5, 9]; - let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect(); + let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect(); assert_eq!(&v[..], &[9, 5, 2, 1, 0]); } @@ -56,11 +56,11 @@ fn iterator_rev_collect() { fn iterator_nth() { let v = [0, 1, 2, 3, 4]; for i in 0..v.len() { - assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]); + assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]); } - assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None); + assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None); - let mut iter = IntoIter::new(v); + let mut iter = IntoIterator::into_iter(v); assert_eq!(iter.nth(2).unwrap(), v[2]); assert_eq!(iter.nth(1).unwrap(), v[4]); } @@ -68,17 +68,17 @@ fn iterator_nth() { #[test] fn iterator_last() { let v = [0, 1, 2, 3, 4]; - assert_eq!(IntoIter::new(v).last().unwrap(), 4); - assert_eq!(IntoIter::new([0]).last().unwrap(), 0); + assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4); + assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0); - let mut it = IntoIter::new([0, 9, 2, 4]); + let mut it = IntoIterator::into_iter([0, 9, 2, 4]); assert_eq!(it.next_back(), Some(4)); assert_eq!(it.last(), Some(2)); } #[test] fn iterator_clone() { - let mut it = IntoIter::new([0, 2, 4, 6, 8]); + let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]); assert_eq!(it.next(), Some(0)); assert_eq!(it.next_back(), Some(8)); let mut clone = it.clone(); @@ -92,7 +92,7 @@ fn iterator_clone() { #[test] fn iterator_fused() { - let mut it = IntoIter::new([0, 9, 2]); + let mut it = IntoIterator::into_iter([0, 9, 2]); assert_eq!(it.next(), Some(0)); assert_eq!(it.next(), Some(9)); assert_eq!(it.next(), Some(2)); @@ -105,7 +105,7 @@ fn iterator_fused() { #[test] fn iterator_len() { - let mut it = IntoIter::new([0, 1, 2, 5, 9]); + let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]); assert_eq!(it.size_hint(), (5, Some(5))); assert_eq!(it.len(), 5); assert_eq!(it.is_empty(), false); @@ -121,7 +121,7 @@ fn iterator_len() { assert_eq!(it.is_empty(), false); // Empty - let it = IntoIter::new([] as [String; 0]); + let it = IntoIterator::into_iter([] as [String; 0]); assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.len(), 0); assert_eq!(it.is_empty(), true); @@ -130,9 +130,9 @@ fn iterator_len() { #[test] fn iterator_count() { let v = [0, 1, 2, 3, 4]; - assert_eq!(IntoIter::new(v.clone()).count(), 5); + assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5); - let mut iter2 = IntoIter::new(v); + let mut iter2 = IntoIterator::into_iter(v); iter2.next(); iter2.next(); assert_eq!(iter2.count(), 3); @@ -140,13 +140,13 @@ fn iterator_count() { #[test] fn iterator_flat_map() { - assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10)); + assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10)); } #[test] fn iterator_debug() { let arr = [0, 1, 2, 5, 9]; - assert_eq!(format!("{:?}", IntoIter::new(arr)), "IntoIter([0, 1, 2, 5, 9])",); + assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",); } #[test] @@ -176,14 +176,14 @@ fn iterator_drops() { // Simple: drop new iterator. let i = Cell::new(0); { - IntoIter::new(five(&i)); + IntoIterator::into_iter(five(&i)); } assert_eq!(i.get(), 5); // Call `next()` once. let i = Cell::new(0); { - let mut iter = IntoIter::new(five(&i)); + let mut iter = IntoIterator::into_iter(five(&i)); let _x = iter.next(); assert_eq!(i.get(), 0); assert_eq!(iter.count(), 4); @@ -194,7 +194,7 @@ fn iterator_drops() { // Check `clone` and calling `next`/`next_back`. let i = Cell::new(0); { - let mut iter = IntoIter::new(five(&i)); + let mut iter = IntoIterator::into_iter(five(&i)); iter.next(); assert_eq!(i.get(), 1); iter.next_back(); @@ -217,7 +217,7 @@ fn iterator_drops() { // Check via `nth`. let i = Cell::new(0); { - let mut iter = IntoIter::new(five(&i)); + let mut iter = IntoIterator::into_iter(five(&i)); let _x = iter.nth(2); assert_eq!(i.get(), 2); let _y = iter.last(); @@ -227,13 +227,13 @@ fn iterator_drops() { // Check every element. let i = Cell::new(0); - for (index, _x) in IntoIter::new(five(&i)).enumerate() { + for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() { assert_eq!(i.get(), index); } assert_eq!(i.get(), 5); let i = Cell::new(0); - for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() { + for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() { assert_eq!(i.get(), index); } assert_eq!(i.get(), 5); diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index c16f54081ce..51eca1e05d3 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -67,10 +67,20 @@ fn test_to_digit() { assert_eq!('A'.to_digit(16), Some(10)); assert_eq!('b'.to_digit(16), Some(11)); assert_eq!('B'.to_digit(16), Some(11)); + assert_eq!('A'.to_digit(36), Some(10)); assert_eq!('z'.to_digit(36), Some(35)); assert_eq!('Z'.to_digit(36), Some(35)); - assert_eq!(' '.to_digit(10), None); + assert_eq!('['.to_digit(36), None); + assert_eq!('`'.to_digit(36), None); + assert_eq!('{'.to_digit(36), None); assert_eq!('$'.to_digit(36), None); + assert_eq!('@'.to_digit(16), None); + assert_eq!('G'.to_digit(16), None); + assert_eq!('g'.to_digit(16), None); + assert_eq!(' '.to_digit(10), None); + assert_eq!('/'.to_digit(10), None); + assert_eq!(':'.to_digit(10), None); + assert_eq!(':'.to_digit(11), None); } #[test] diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803ec..4acd059ab03 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -49,53 +49,3 @@ fn mut_ptr_read() { const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); } - -#[test] -fn write() { - use core::ptr; - - const fn write_aligned() -> i32 { - let mut res = 0; - unsafe { - ptr::write(&mut res as *mut _, 42); - } - res - } - const ALIGNED: i32 = write_aligned(); - assert_eq!(ALIGNED, 42); - - const fn write_unaligned() -> [u16; 2] { - let mut two_aligned = [0u16; 2]; - unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; - ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); - } - two_aligned - } - const UNALIGNED: [u16; 2] = write_unaligned(); - assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -} - -#[test] -fn mut_ptr_write() { - const fn aligned() -> i32 { - let mut res = 0; - unsafe { - (&mut res as *mut i32).write(42); - } - res - } - const ALIGNED: i32 = aligned(); - assert_eq!(ALIGNED, 42); - - const fn write_unaligned() -> [u16; 2] { - let mut two_aligned = [0u16; 2]; - unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; - unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); - } - two_aligned - } - const UNALIGNED: [u16; 2] = write_unaligned(); - assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]); -} diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 000c15f72c8..797bfd957f9 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -236,9 +236,7 @@ fn test_zip_trusted_random_access_composition() { fn test_double_ended_zip() { let xs = [1, 2, 3, 4, 5, 6]; let ys = [1, 2, 3, 7]; - let a = xs.iter().cloned(); - let b = ys.iter().cloned(); - let mut it = a.zip(b); + let mut it = xs.iter().cloned().zip(ys); assert_eq!(it.next(), Some((1, 1))); assert_eq!(it.next(), Some((2, 2))); assert_eq!(it.next_back(), Some((4, 7))); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db12d79c00c..16051b3bc36 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -40,11 +40,9 @@ #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] -#![feature(step_trait_ext)] #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] -#![feature(try_trait)] #![feature(try_trait_v2)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 5dcd1e6af36..d95ea6530c2 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -5,10 +5,7 @@ #![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)] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 99a0c67fc11..d32a3f1f832 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -13,10 +13,7 @@ #![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)] diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index aeecbd49662..717201aef10 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -39,7 +39,7 @@ pub struct Buffer<T: Copy> { 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>), } @@ -78,18 +78,44 @@ impl<T: Copy> 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)); } } @@ -131,9 +157,9 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> { } } - 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) } @@ -141,6 +167,6 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> { mem::drop(to_vec(b)); } - Buffer { data, len, capacity, extend_from_slice, drop } + Buffer { data, len, capacity, reserve, drop } } } diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 5c2f9ec9848..588e6ded0f4 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -27,7 +27,7 @@ macro_rules! rpc_encode_decode { (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()); } } @@ -114,7 +114,7 @@ impl<S> DecodeMut<'_, '_, S> for () { impl<S> Encode<S> for u8 { fn encode(self, w: &mut Writer, _: &mut S) { - w.write_all(&[self]).unwrap(); + w.push(self); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 281999fe715..26fbf50e2df 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -12,7 +12,6 @@ #![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))), @@ -21,8 +20,7 @@ #![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)] @@ -33,6 +31,7 @@ #![feature(restricted_std)] #![feature(rustc_attrs)] #![feature(min_specialization)] +#![feature(bound_cloned)] #![recursion_limit = "256"] #[unstable(feature = "proc_macro_internals", issue = "27812")] @@ -45,7 +44,7 @@ mod diagnostic; pub use diagnostic::{Diagnostic, Level, MultiSpan}; use std::cmp::Ordering; -use std::ops::{Bound, RangeBounds}; +use std::ops::RangeBounds; use std::path::PathBuf; use std::str::FromStr; use std::{error, fmt, iter, mem}; @@ -1164,16 +1163,7 @@ impl Literal { // was 'c' or whether it was '\u{63}'. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> { - // HACK(eddyb) something akin to `Option::cloned`, but for `Bound<&T>`. - fn cloned_bound<T: Clone>(bound: Bound<&T>) -> Bound<T> { - match bound { - Bound::Included(x) => Bound::Included(x.clone()), - Bound::Excluded(x) => Bound::Excluded(x.clone()), - Bound::Unbounded => Bound::Unbounded, - } - } - - self.0.subspan(cloned_bound(range.start_bound()), cloned_bound(range.end_bound())).map(Span) + self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span) } } diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 474058a547f..7b7ca8029b4 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -14,4 +14,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.67" +cc = "1.0.68" diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 922c2c2bb8c..415d874c7fa 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } 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'] } diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 2a4ef553be3..be7e099b73a 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -672,6 +672,7 @@ impl CString { } /// 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. diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 6891bd8a664..7a2a49ba7d7 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -87,6 +87,11 @@ impl<S: Seek + ?Sized> Seek for &mut S { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result<u64> { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<B: BufRead + ?Sized> BufRead for &mut B { @@ -186,6 +191,11 @@ impl<S: Seek + ?Sized> Seek for Box<S> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result<u64> { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<B: BufRead + ?Sized> BufRead for Box<B> { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a8f3412c611..4c154dbe01a 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -509,8 +509,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ /// [`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. @@ -526,7 +525,12 @@ pub trait Read { /// /// 1. This reader has reached its "end of file" and will likely no longer /// be able to produce bytes. Note that this does not mean that the - /// reader will *always* no longer be able to produce bytes. + /// reader will *always* no longer be able to produce bytes. As an example, + /// on Linux, this method will call the `recv` syscall for a [`TcpStream`], + /// where returning zero indicates the connection was shut down correctly. While + /// for [`File`], it is possible to reach the end of file and get zero as result, + /// but if more data is appended to the file, future calls to `read` will return + /// more data. /// 2. The buffer specified was 0 bytes in length. /// /// It is not an error if the returned value `n` is smaller than the buffer size, @@ -568,6 +572,7 @@ pub trait Read { /// /// [`Ok(n)`]: Ok /// [`File`]: crate::fs::File + /// [`TcpStream`]: crate::net::TcpStream /// /// ```no_run /// use std::io; @@ -1301,8 +1306,7 @@ impl Initializer { /// /// [`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. /// diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 39ed62425ce..5b8e83766f0 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -987,13 +987,13 @@ mod mod_keyword {} /// Capture a [closure]'s environment by value. /// /// `move` converts any variables captured by reference or mutable reference -/// to owned by value variables. +/// to variables captured by value. /// /// ```rust -/// let capture = "hello"; -/// let closure = move || { -/// println!("rust says {}", capture); -/// }; +/// let data = vec![1, 2, 3]; +/// let closure = move || println!("captured {:?} by value", data); +/// +/// // data is no longer available, it is owned by the closure /// ``` /// /// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though @@ -1004,31 +1004,29 @@ mod mod_keyword {} /// ```rust /// fn create_fn() -> impl Fn() { /// let text = "Fn".to_owned(); -/// /// move || println!("This is a: {}", text) /// } /// -/// let fn_plain = create_fn(); -/// -/// fn_plain(); +/// let fn_plain = create_fn(); +/// fn_plain(); /// ``` /// /// `move` is often used when [threads] are involved. /// /// ```rust -/// let x = 5; +/// let data = vec![1, 2, 3]; /// /// std::thread::spawn(move || { -/// println!("captured {} by value", x) +/// println!("captured {:?} by value", data) /// }).join().unwrap(); /// -/// // x is no longer available +/// // data was moved to the spawned thread, so we cannot use it here /// ``` /// /// `move` is also valid before an async block. /// /// ```rust -/// let capture = "hello"; +/// let capture = "hello".to_owned(); /// let block = async move { /// println!("rust says {} from async block", capture); /// }; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 442b5628d1d..6f94a0599ed 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -190,7 +190,6 @@ #![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))), @@ -260,8 +259,7 @@ #![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)] @@ -288,7 +286,6 @@ #![feature(log_syntax)] #![feature(map_try_insert)] #![feature(maybe_uninit_extra)] -#![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] @@ -300,7 +297,6 @@ #![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)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 9b629e19be5..2b6d0d7d5da 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1,11 +1,3 @@ -#![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; @@ -126,6 +118,7 @@ pub struct Ipv6Addr { #[allow(missing_docs)] #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[unstable(feature = "ip", issue = "27709")] pub enum Ipv6MulticastScope { InterfaceLocal, LinkLocal, @@ -199,6 +192,7 @@ impl IpAddr { /// 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 { @@ -249,6 +243,7 @@ impl IpAddr { /// ); /// ``` #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_documentation(&self) -> bool { match self { @@ -319,7 +314,7 @@ impl Ipv4Addr { Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } } } - /// An IPv4 address with the address pointing to localhost: 127.0.0.1. + /// An IPv4 address with the address pointing to localhost: `127.0.0.1` /// /// # Examples /// @@ -332,7 +327,7 @@ impl Ipv4Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - /// An IPv4 address representing an unspecified address: 0.0.0.0 + /// An IPv4 address representing an unspecified address: `0.0.0.0` /// /// This corresponds to the constant `INADDR_ANY` in other languages. /// @@ -348,7 +343,7 @@ impl Ipv4Addr { #[stable(feature = "ip_constructors", since = "1.30.0")] pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); - /// An IPv4 address representing the broadcast address: 255.255.255.255 + /// An IPv4 address representing the broadcast address: `255.255.255.255` /// /// # Examples /// @@ -379,7 +374,7 @@ impl Ipv4Addr { self.inner.s_addr.to_ne_bytes() } - /// Returns [`true`] for the special 'unspecified' address (0.0.0.0). + /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`). /// /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. @@ -401,7 +396,7 @@ impl Ipv4Addr { self.inner.s_addr == 0 } - /// Returns [`true`] if this is a loopback address (127.0.0.0/8). + /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`). /// /// This property is defined by [IETF RFC 1122]. /// @@ -426,9 +421,9 @@ impl Ipv4Addr { /// /// The private address ranges are defined in [IETF RFC 1918] and include: /// - /// - 10.0.0.0/8 - /// - 172.16.0.0/12 - /// - 192.168.0.0/16 + /// - `10.0.0.0/8` + /// - `172.16.0.0/12` + /// - `192.168.0.0/16` /// /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// @@ -457,7 +452,7 @@ impl Ipv4Addr { } } - /// Returns [`true`] if the address is link-local (169.254.0.0/16). + /// Returns [`true`] if the address is link-local (`169.254.0.0/16`). /// /// This property is defined by [IETF RFC 3927]. /// @@ -490,7 +485,7 @@ impl Ipv4Addr { /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`]) /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`]) /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole - /// 0.0.0.0/8 block + /// `0.0.0.0/8` block /// - addresses reserved for future protocols (see /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable @@ -549,6 +544,7 @@ impl Ipv4Addr { /// 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 @@ -587,6 +583,7 @@ impl Ipv4Addr { /// 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) @@ -620,6 +617,7 @@ impl Ipv4Addr { /// 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 @@ -644,6 +642,7 @@ impl Ipv4Addr { /// 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 @@ -677,14 +676,15 @@ impl Ipv4Addr { /// 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() } - /// Returns [`true`] if this is a multicast address (224.0.0.0/4). + /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`). /// - /// Multicast addresses have a most significant octet between 224 and 239, + /// Multicast addresses have a most significant octet between `224` and `239`, /// and is defined by [IETF RFC 5771]. /// /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 @@ -705,9 +705,9 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Returns [`true`] if this is a broadcast address (255.255.255.255). + /// Returns [`true`] if this is a broadcast address (`255.255.255.255`). /// - /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. + /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919]. /// /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// @@ -730,9 +730,9 @@ impl Ipv4Addr { /// /// This is defined in [IETF RFC 5737]: /// - /// - 192.0.2.0/24 (TEST-NET-1) - /// - 198.51.100.0/24 (TEST-NET-2) - /// - 203.0.113.0/24 (TEST-NET-3) + /// - `192.0.2.0/24` (TEST-NET-1) + /// - `198.51.100.0/24` (TEST-NET-2) + /// - `203.0.113.0/24` (TEST-NET-3) /// /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// @@ -760,7 +760,7 @@ impl Ipv4Addr { /// Converts this address to an IPv4-compatible [`IPv6` address]. /// - /// a.b.c.d becomes ::a.b.c.d + /// `a.b.c.d` becomes `::a.b.c.d` /// /// This isn't typically the method you want; these addresses don't typically /// function on modern systems. Use `to_ipv6_mapped` instead. @@ -774,7 +774,7 @@ impl Ipv4Addr { /// /// assert_eq!( /// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff) /// ); /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] @@ -789,7 +789,7 @@ impl Ipv4Addr { /// Converts this address to an IPv4-mapped [`IPv6` address]. /// - /// a.b.c.d becomes ::ffff:a.b.c.d + /// `a.b.c.d` becomes `::ffff:a.b.c.d` /// /// [`IPv6` address]: Ipv6Addr /// @@ -799,7 +799,7 @@ impl Ipv4Addr { /// use std::net::{Ipv4Addr, Ipv6Addr}; /// /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), - /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); + /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff)); /// ``` #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")] #[stable(feature = "rust1", since = "1.0.0")] @@ -1172,7 +1172,7 @@ impl Ipv6Addr { ] } - /// Returns [`true`] for the special 'unspecified' address (::). + /// Returns [`true`] for the special 'unspecified' address (`::`). /// /// This property is defined in [IETF RFC 4291]. /// @@ -1234,6 +1234,7 @@ impl Ipv6Addr { /// 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() { @@ -1260,27 +1261,17 @@ impl Ipv6Addr { /// 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`). - /// - /// 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: + /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291]. + /// Any address that is not a [multicast address] (`ff00::/8`) is unicast. /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111010| 0 | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// - /// 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. + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast /// /// # Examples /// @@ -1289,54 +1280,46 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local_strict()); + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); /// - /// 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()); + /// // Any address that is not a multicast address (`ff00::/8`) is unicast. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true); + /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false); /// ``` - /// - /// # 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()`] - /// - /// [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")] + #[unstable(feature = "ip", issue = "27709")] #[inline] - pub const fn is_unicast_link_local_strict(&self) -> bool { - matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() } - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. /// - /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], - /// i.e. addresses with the following format: + /// 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| arbitratry value | interface ID | + /// |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. /// - /// 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. + /// 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. + /// + /// [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 /// @@ -1345,36 +1328,25 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// 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, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); + /// // 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(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 } - /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The + /// Returns [`true`] if this is a deprecated unicast site-local address (`fec0::/10`). The /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as: /// /// ```no_rust @@ -1403,12 +1375,13 @@ impl Ipv6Addr { /// /// # Warning /// - /// As per [RFC 3879], the whole `FEC0::/10` prefix is + /// As per [RFC 3879], the whole `fec0::/10` prefix is /// deprecated. New software must not support site-local /// addresses. /// /// [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 @@ -1432,6 +1405,7 @@ impl Ipv6Addr { /// 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) @@ -1468,9 +1442,10 @@ impl Ipv6Addr { /// 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() + self.is_unicast() && !self.is_loopback() && !self.is_unicast_link_local() && !self.is_unique_local() @@ -1494,6 +1469,7 @@ impl Ipv6Addr { /// 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() { @@ -1512,7 +1488,7 @@ impl Ipv6Addr { } } - /// Returns [`true`] if this is a multicast address (ff00::/8). + /// Returns [`true`] if this is a multicast address (`ff00::/8`). /// /// This property is defined by [IETF RFC 4291]. /// @@ -1555,6 +1531,7 @@ impl Ipv6Addr { /// 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() { @@ -1568,7 +1545,7 @@ impl Ipv6Addr { /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is /// neither IPv4-compatible or IPv4-mapped. /// - /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d + /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d` /// /// [`IPv4` address]: Ipv4Addr /// diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index ef0d4edc434..05f8dea0b7c 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -480,7 +480,6 @@ fn ipv6_properties() { 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; @@ -524,11 +523,6 @@ fn ipv6_properties() { } 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 { @@ -587,7 +581,6 @@ fn ipv6_properties() { 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; @@ -621,11 +614,7 @@ fn ipv6_properties() { 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::", @@ -650,7 +639,7 @@ fn ipv6_properties() { 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!( @@ -897,9 +886,6 @@ fn ipv6_const() { 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); diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 9cf51be2836..913c71d4108 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -906,7 +906,7 @@ impl DirBuilderExt for fs::DirBuilder { /// } /// ``` #[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()) } diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index b10dde42482..9e3880dfd41 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -55,6 +55,7 @@ pub use core::panic::{Location, PanicInfo}; /// 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); } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 02957e75a74..0b9c9fb479f 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -19,7 +19,7 @@ use crate::process; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; -use crate::sys_common::rwlock::RWLock; +use crate::sys_common::rwlock::StaticRWLock; use crate::sys_common::thread_info; use crate::thread; @@ -74,7 +74,7 @@ enum Hook { Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)), } -static HOOK_LOCK: RWLock = RWLock::new(); +static HOOK_LOCK: StaticRWLock = StaticRWLock::new(); static mut HOOK: Hook = Hook::Default; /// Registers a custom panic hook, replacing any that was previously registered. @@ -117,10 +117,10 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) { } unsafe { - HOOK_LOCK.write(); + let guard = HOOK_LOCK.write(); let old_hook = HOOK; HOOK = Hook::Custom(Box::into_raw(hook)); - HOOK_LOCK.write_unlock(); + drop(guard); if let Hook::Custom(ptr) = old_hook { #[allow(unused_must_use)] @@ -165,10 +165,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> { } unsafe { - HOOK_LOCK.write(); + let guard = HOOK_LOCK.write(); let hook = HOOK; HOOK = Hook::Default; - HOOK_LOCK.write_unlock(); + drop(guard); match hook { Hook::Default => Box::new(default_hook), @@ -193,7 +193,7 @@ fn default_hook(info: &PanicInfo<'_>) { Some(s) => *s, None => match info.payload().downcast_ref::<String>() { Some(s) => &s[..], - None => "Box<Any>", + None => "Box<dyn Any>", }, }; let thread = thread_info::current_thread(); @@ -608,7 +608,7 @@ fn rust_panic_with_hook( unsafe { let mut info = PanicInfo::internal_constructor(message, location); - HOOK_LOCK.read(); + let _guard = HOOK_LOCK.read(); match HOOK { // Some platforms (like wasm) know that printing to stderr won't ever actually // print anything, and if that's the case we can skip the default @@ -626,7 +626,6 @@ fn rust_panic_with_hook( (*ptr)(&info); } }; - HOOK_LOCK.read_unlock(); } if panics > 1 { diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9c5615f58c4..ede147aca12 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1420,6 +1420,9 @@ impl Clone for PathBuf { #[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; @@ -1429,6 +1432,9 @@ impl From<&Path> for Box<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 { @@ -1471,6 +1477,9 @@ impl Clone for Box<Path> { #[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()) @@ -1575,6 +1584,10 @@ impl Default for PathBuf { #[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) @@ -1583,6 +1596,10 @@ impl<'a> From<&'a Path> for Cow<'a, Path> { #[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) @@ -1591,6 +1608,10 @@ impl<'a> From<PathBuf> for Cow<'a, Path> { #[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()) @@ -1599,6 +1620,9 @@ impl<'a> From<&'a PathBuf> for Cow<'a, 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() @@ -2462,10 +2486,10 @@ impl Path { /// 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 /// @@ -2513,10 +2537,10 @@ impl Path { /// 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 /// @@ -2545,10 +2569,10 @@ impl Path { /// 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 /// diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 1b4facdd049..12d52cc8e0b 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -88,9 +88,9 @@ pub mod v1; /// 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::*; } @@ -98,9 +98,9 @@ pub mod rust_2015 { /// 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::*; } @@ -108,13 +108,13 @@ pub mod rust_2018 { /// 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::*; } diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 96ab32104ea..8a3e425350a 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -345,6 +345,9 @@ mod prim_never {} mod prim_char {} #[doc(primitive = "unit")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// The `()` type, also called "unit". /// @@ -537,8 +540,7 @@ mod prim_pointer {} /// /// # Examples /// -#[cfg_attr(bootstrap, doc = "```ignore")] -#[cfg_attr(not(bootstrap), doc = "```")] +/// ``` /// let mut array: [i32; 3] = [0; 3]; /// /// array[1] = 1; @@ -578,8 +580,7 @@ mod prim_pointer {} /// `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]; /// @@ -634,8 +635,7 @@ mod prim_pointer {} /// * 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]; diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 773ab18b2ce..e7c5479ab9b 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -294,8 +294,14 @@ impl<T: ?Sized> Mutex<T> { /// # 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 /// diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index b01bcec1361..0d00f74eaa1 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -3,9 +3,7 @@ mod tests; use crate::cell::UnsafeCell; use crate::fmt; -use crate::mem; use crate::ops::{Deref, DerefMut}; -use crate::ptr; use crate::sync::{poison, LockResult, TryLockError, TryLockResult}; use crate::sys_common::rwlock as sys; @@ -66,7 +64,7 @@ use crate::sys_common::rwlock as sys; /// [`Mutex`]: super::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLock<T: ?Sized> { - inner: Box<sys::RWLock>, + inner: sys::MovableRWLock, poison: poison::Flag, data: UnsafeCell<T>, } @@ -130,7 +128,7 @@ impl<T> RwLock<T> { #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> RwLock<T> { RwLock { - inner: box sys::RWLock::new(), + inner: sys::MovableRWLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), } @@ -199,11 +197,17 @@ impl<T: ?Sized> RwLock<T> { /// /// # 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 /// /// ``` @@ -281,10 +285,17 @@ impl<T: ?Sized> RwLock<T> { /// /// # 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 /// @@ -363,24 +374,8 @@ impl<T: ?Sized> RwLock<T> { where T: Sized, { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `RwLock` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let RwLock { inner, poison, data } = self`. - let (inner, poison, data) = { - let RwLock { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. - drop(inner); - - poison::map_result(poison.borrow(), |_| data.into_inner()) - } + let data = self.data.into_inner(); + poison::map_result(self.poison.borrow(), |_| data) } /// Returns a mutable reference to the underlying data. @@ -412,14 +407,6 @@ impl<T: ?Sized> RwLock<T> { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> { - fn drop(&mut self) { - // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. - unsafe { self.inner.destroy() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut d = f.debug_struct("RwLock"); diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 06442e925f4..d2058180121 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -8,6 +8,8 @@ pub struct RWLock { state: UnsafeCell<State>, } +pub type MovableRWLock = Box<RWLock>; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 0c96e3fcddc..2d038b51896 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -13,6 +13,8 @@ pub struct RWLock { writer: SpinMutex<WaitVariable<bool>>, } +pub type MovableRWLock = Box<RWLock>; + // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below) // // # Safety diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index ef14865fbcd..f8ca67c844c 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1329,7 +1329,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { 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()) })?; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 57d91441b6f..ca9cc8ca7ba 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -210,7 +210,6 @@ cfg_if::cfg_if! { 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")] diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index e6b61062d15..d5a15964c08 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -62,7 +62,7 @@ impl Socket { 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 @@ -99,7 +99,7 @@ impl Socket { 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()))?; @@ -204,7 +204,7 @@ impl Socket { 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) diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index bbc4691d963..41ca9762390 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -20,8 +20,7 @@ use crate::str; use crate::sys::cvt; use crate::sys::fd; use crate::sys::memchr; -use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock}; -use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; +use crate::sys_common::rwlock::{StaticRWLock, StaticRWLockReadGuard}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -490,8 +489,8 @@ pub unsafe fn environ() -> *mut *const *const c_char { static ENV_LOCK: StaticRWLock = StaticRWLock::new(); -pub fn env_read_lock() -> RWLockReadGuard { - ENV_LOCK.read_with_guard() +pub fn env_read_lock() -> StaticRWLockReadGuard { + ENV_LOCK.read() } /// Returns a vector of (variable, value) byte-vector pairs for all the @@ -551,7 +550,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = ENV_LOCK.write(); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) } } @@ -560,7 +559,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - let _guard = ENV_LOCK.write_with_guard(); + let _guard = ENV_LOCK.write(); cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) } } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 7f8065e7500..ed55e1aa715 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -495,7 +495,7 @@ impl ExitStatus { 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. diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index eecdb624b9c..c17822f5125 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -1,5 +1,8 @@ +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::*; @@ -187,8 +190,16 @@ impl ExitStatus { 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> { @@ -235,3 +246,18 @@ impl fmt::Display for ExitStatus { } } } + +#[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()) + } +} diff --git a/library/std/src/sys/unix/rwlock.rs b/library/std/src/sys/unix/rwlock.rs index d97d9d712fc..b1faf12c226 100644 --- a/library/std/src/sys/unix/rwlock.rs +++ b/library/std/src/sys/unix/rwlock.rs @@ -7,6 +7,8 @@ pub struct RWLock { num_readers: AtomicUsize, } +pub type MovableRWLock = Box<RWLock>; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} @@ -139,55 +141,3 @@ impl RWLock { } } } - -pub struct StaticRWLock(RWLock); - -impl StaticRWLock { - pub const fn new() -> StaticRWLock { - StaticRWLock(RWLock::new()) - } - - /// Acquires shared access to the underlying lock, blocking the current - /// thread to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn read_with_guard(&'static self) -> RWLockReadGuard { - // SAFETY: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.read(); - } - RWLockReadGuard(&self.0) - } - - /// Acquires write access to the underlying lock, blocking the current thread - /// to do so. - /// - /// The lock is automatically unlocked when the returned guard is dropped. - #[inline] - pub fn write_with_guard(&'static self) -> RWLockWriteGuard { - // SAFETY: All methods require static references, therefore self - // cannot be moved between invocations. - unsafe { - self.0.write(); - } - RWLockWriteGuard(&self.0) - } -} - -pub struct RWLockReadGuard(&'static RWLock); - -impl Drop for RWLockReadGuard { - fn drop(&mut self) { - unsafe { self.0.read_unlock() } - } -} - -pub struct RWLockWriteGuard(&'static RWLock); - -impl Drop for RWLockWriteGuard { - fn drop(&mut self) { - unsafe { self.0.write_unlock() } - } -} diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs index 6982b2b155f..8438adeb5b5 100644 --- a/library/std/src/sys/unsupported/rwlock.rs +++ b/library/std/src/sys/unsupported/rwlock.rs @@ -5,6 +5,8 @@ pub struct RWLock { mode: Cell<isize>, } +pub type MovableRWLock = RWLock; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} // no threads on this platform diff --git a/library/std/src/sys/wasm/atomics/rwlock.rs b/library/std/src/sys/wasm/atomics/rwlock.rs index 06442e925f4..64eaa2fc482 100644 --- a/library/std/src/sys/wasm/atomics/rwlock.rs +++ b/library/std/src/sys/wasm/atomics/rwlock.rs @@ -8,6 +8,8 @@ pub struct RWLock { state: UnsafeCell<State>, } +pub type MovableRWLock = RWLock; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 50d6e8cf27a..b7efc884473 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -631,7 +631,7 @@ pub struct timeval { pub tv_usec: c_long, } -// Functions forbidden when targeting UWP +// Desktop specific functions & types cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; @@ -645,7 +645,7 @@ if #[cfg(not(target_vendor = "uwp"))] { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ExceptionAddress: LPVOID, pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] + pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS], } pub enum CONTEXT {} @@ -656,8 +656,8 @@ if #[cfg(not(target_vendor = "uwp"))] { pub ContextRecord: *mut CONTEXT, } - pub type PVECTORED_EXCEPTION_HANDLER = extern "system" - fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; + pub type PVECTORED_EXCEPTION_HANDLER = + extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; #[repr(C)] #[derive(Copy, Clone)] @@ -691,44 +691,66 @@ if #[cfg(not(target_vendor = "uwp"))] { pub const TOKEN_READ: DWORD = 0x20008; + #[link(name = "advapi32")] extern "system" { + // Forbidden when targeting UWP #[link_name = "SystemFunction036"] pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; - pub fn ReadConsoleW(hConsoleInput: HANDLE, - lpBuffer: LPVOID, - nNumberOfCharsToRead: DWORD, - lpNumberOfCharsRead: LPDWORD, - pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL; + // Allowed but unused by UWP + pub fn OpenProcessToken( + ProcessHandle: HANDLE, + DesiredAccess: DWORD, + TokenHandle: *mut HANDLE, + ) -> BOOL; + } - pub fn WriteConsoleW(hConsoleOutput: HANDLE, - lpBuffer: LPCVOID, - nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: LPDWORD, - lpReserved: LPVOID) -> BOOL; + #[link(name = "userenv")] + extern "system" { + // Allowed but unused by UWP + pub fn GetUserProfileDirectoryW( + hToken: HANDLE, + lpProfileDir: LPWSTR, + lpcchSize: *mut DWORD, + ) -> BOOL; + } - pub fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: LPDWORD) -> BOOL; + #[link(name = "kernel32")] + extern "system" { + // Functions forbidden when targeting UWP + pub fn ReadConsoleW( + hConsoleInput: HANDLE, + lpBuffer: LPVOID, + nNumberOfCharsToRead: DWORD, + lpNumberOfCharsRead: LPDWORD, + pInputControl: PCONSOLE_READCONSOLE_CONTROL, + ) -> BOOL; + + pub fn WriteConsoleW( + hConsoleOutput: HANDLE, + lpBuffer: LPCVOID, + nNumberOfCharsToWrite: DWORD, + lpNumberOfCharsWritten: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + + pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; // Allowed but unused by UWP - pub fn OpenProcessToken(ProcessHandle: HANDLE, - DesiredAccess: DWORD, - TokenHandle: *mut HANDLE) -> BOOL; - pub fn GetUserProfileDirectoryW(hToken: HANDLE, - lpProfileDir: LPWSTR, - lpcchSize: *mut DWORD) -> BOOL; - pub fn GetFileInformationByHandle(hFile: HANDLE, - lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) - -> BOOL; - pub fn SetHandleInformation(hObject: HANDLE, - dwMask: DWORD, - dwFlags: DWORD) -> BOOL; - pub fn AddVectoredExceptionHandler(FirstHandler: ULONG, - VectoredHandler: PVECTORED_EXCEPTION_HANDLER) - -> LPVOID; - pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; + pub fn GetFileInformationByHandle( + hFile: HANDLE, + lpFileInformation: LPBY_HANDLE_FILE_INFORMATION, + ) -> BOOL; + pub fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL; + pub fn AddVectoredExceptionHandler( + FirstHandler: ULONG, + VectoredHandler: PVECTORED_EXCEPTION_HANDLER, + ) -> LPVOID; + pub fn CreateHardLinkW( + lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL; } } } @@ -747,55 +769,32 @@ if #[cfg(target_vendor = "uwp")] { pub Directory: BOOLEAN, } + #[link(name = "bcrypt")] extern "system" { - pub fn GetFileInformationByHandleEx(hFile: HANDLE, - fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: LPVOID, - dwBufferSize: DWORD) -> BOOL; - pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8, - cbBuffer: ULONG, dwFlags: ULONG) -> LONG; + pub fn BCryptGenRandom( + hAlgorithm: LPVOID, + pBuffer: *mut u8, + cbBuffer: ULONG, + dwFlags: ULONG, + ) -> LONG; + } + #[link(name = "kernel32")] + extern "system" { + pub fn GetFileInformationByHandleEx( + hFile: HANDLE, + fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; } } } // Shared between Desktop & UWP + +#[link(name = "kernel32")] extern "system" { - pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; - pub fn WSACleanup() -> c_int; - pub fn WSAGetLastError() -> c_int; - pub fn WSADuplicateSocketW( - s: SOCKET, - dwProcessId: DWORD, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - ) -> c_int; - pub fn WSASend( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesSent: LPDWORD, - dwFlags: DWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; - pub fn WSARecv( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesRecvd: LPDWORD, - lpFlags: LPDWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; pub fn GetCurrentProcessId() -> DWORD; - pub fn WSASocketW( - af: c_int, - kind: c_int, - protocol: c_int, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - g: GROUP, - dwFlags: DWORD, - ) -> SOCKET; - pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; @@ -882,28 +881,6 @@ extern "system" { pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - - pub fn closesocket(socket: SOCKET) -> c_int; - pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; - pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; - pub fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, - ) -> c_int; - pub fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, - ) -> c_int; - pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; - pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; pub fn DuplicateHandle( hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, @@ -950,32 +927,6 @@ extern "system" { pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; - pub fn getsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *mut c_char, - optlen: *mut c_int, - ) -> c_int; - pub fn setsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *const c_void, - optlen: c_int, - ) -> c_int; - pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; - pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; - pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; - pub fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, - ) -> c_int; - pub fn freeaddrinfo(res: *mut ADDRINFOA); pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE; @@ -1012,47 +963,23 @@ extern "system" { lpNumberOfBytesTransferred: LPDWORD, bWait: BOOL, ) -> BOOL; - pub fn select( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *const timeval, - ) -> c_int; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw pub fn CreateSymbolicLinkW( lpSymlinkFileName: LPCWSTR, lpTargetFileName: LPCWSTR, dwFlags: DWORD, ) -> BOOLEAN; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew pub fn GetFinalPathNameByHandleW( hFile: HANDLE, lpszFilePath: LPCWSTR, cchFilePath: DWORD, dwFlags: DWORD, ) -> DWORD; - - // >= Vista / Server 2003 - // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee - #[cfg(not(target_vendor = "uwp"))] - pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle pub fn SetFileInformationByHandle( hFile: HANDLE, FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, lpFileInformation: LPVOID, dwBufferSize: DWORD, ) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw pub fn SleepConditionVariableSRW( ConditionVariable: PCONDITION_VARIABLE, SRWLock: PSRWLOCK, @@ -1060,13 +987,9 @@ extern "system" { Flags: ULONG, ) -> BOOL; - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); @@ -1075,6 +998,99 @@ extern "system" { pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; } +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; + pub fn WSACleanup() -> c_int; + pub fn WSAGetLastError() -> c_int; + pub fn WSADuplicateSocketW( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + ) -> c_int; + pub fn WSASend( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSARecv( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASocketW( + af: c_int, + kind: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET; + pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; + pub fn closesocket(socket: SOCKET) -> c_int; + pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; + pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; + pub fn recvfrom( + socket: SOCKET, + buf: *mut c_void, + len: c_int, + flags: c_int, + addr: *mut SOCKADDR, + addrlen: *mut c_int, + ) -> c_int; + pub fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int; + pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; + pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; + pub fn getsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: *mut c_int, + ) -> c_int; + pub fn setsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: c_int, + ) -> c_int; + pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; + pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; + pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int; + pub fn freeaddrinfo(res: *mut ADDRINFOA); + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *const timeval, + ) -> c_int; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index cc60ca375ea..f23e874f249 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -281,17 +281,3 @@ pub fn abort_internal() -> ! { } crate::intrinsics::abort(); } - -cfg_if::cfg_if! { - if #[cfg(target_vendor = "uwp")] { - #[link(name = "ws2_32")] - // For BCryptGenRandom - #[link(name = "bcrypt")] - extern "C" {} - } else { - #[link(name = "advapi32")] - #[link(name = "ws2_32")] - #[link(name = "userenv")] - extern "C" {} - } -} diff --git a/library/std/src/sys/windows/rwlock.rs b/library/std/src/sys/windows/rwlock.rs index a769326352c..b7a5b1e7acc 100644 --- a/library/std/src/sys/windows/rwlock.rs +++ b/library/std/src/sys/windows/rwlock.rs @@ -5,6 +5,8 @@ pub struct RWLock { inner: UnsafeCell<c::SRWLOCK>, } +pub type MovableRWLock = RWLock; + unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 3705d641a1b..07ec20f4dc6 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -1,63 +1,112 @@ use crate::sys::rwlock as imp; +/// An OS-based reader-writer lock, meant for use in static variables. +/// +/// This rwlock does not implement poisoning. +/// +/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not +/// implement `Drop` to cleanup resources. +pub struct StaticRWLock(imp::RWLock); + +impl StaticRWLock { + /// Creates a new rwlock for use. + pub const fn new() -> Self { + Self(imp::RWLock::new()) + } + + /// Acquires shared access to the underlying lock, blocking the current + /// thread to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn read(&'static self) -> StaticRWLockReadGuard { + unsafe { self.0.read() }; + StaticRWLockReadGuard(&self.0) + } + + /// Acquires write access to the underlying lock, blocking the current thread + /// to do so. + /// + /// The lock is automatically unlocked when the returned guard is dropped. + #[inline] + pub fn write(&'static self) -> StaticRWLockWriteGuard { + unsafe { self.0.write() }; + StaticRWLockWriteGuard(&self.0) + } +} + +#[must_use] +pub struct StaticRWLockReadGuard(&'static imp::RWLock); + +impl Drop for StaticRWLockReadGuard { + #[inline] + fn drop(&mut self) { + unsafe { + self.0.read_unlock(); + } + } +} + +#[must_use] +pub struct StaticRWLockWriteGuard(&'static imp::RWLock); + +impl Drop for StaticRWLockWriteGuard { + #[inline] + fn drop(&mut self) { + unsafe { + self.0.write_unlock(); + } + } +} + /// An OS-based reader-writer lock. /// -/// This structure is entirely unsafe and serves as the lowest layer of a -/// cross-platform binding of system rwlocks. It is recommended to use the -/// safer types at the top level of this crate instead of this type. -pub struct RWLock(imp::RWLock); +/// This rwlock does *not* have a const constructor, cleans up its resources in +/// its `Drop` implementation and may safely be moved (when not borrowed). +/// +/// This rwlock does not implement poisoning. +/// +/// This is either a wrapper around `Box<imp::RWLock>` or `imp::RWLock`, +/// depending on the platform. It is boxed on platforms where `imp::RWLock` may +/// not be moved. +pub struct MovableRWLock(imp::MovableRWLock); -impl RWLock { +impl MovableRWLock { /// Creates a new reader-writer lock for use. - /// - /// Behavior is undefined if the reader-writer lock is moved after it is - /// first used with any of the functions below. - pub const fn new() -> RWLock { - RWLock(imp::RWLock::new()) + pub fn new() -> Self { + Self(imp::MovableRWLock::from(imp::RWLock::new())) } /// Acquires shared access to the underlying lock, blocking the current /// thread to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn read(&self) { - self.0.read() + pub fn read(&self) { + unsafe { self.0.read() } } /// Attempts to acquire shared access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn try_read(&self) -> bool { - self.0.try_read() + pub fn try_read(&self) -> bool { + unsafe { self.0.try_read() } } /// Acquires write access to the underlying lock, blocking the current thread /// to do so. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn write(&self) { - self.0.write() + pub fn write(&self) { + unsafe { self.0.write() } } /// Attempts to acquire exclusive access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. - /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. #[inline] - pub unsafe fn try_write(&self) -> bool { - self.0.try_write() + pub fn try_write(&self) -> bool { + unsafe { self.0.try_write() } } /// Unlocks previously acquired shared access to this lock. @@ -76,13 +125,10 @@ impl RWLock { pub unsafe fn write_unlock(&self) { self.0.write_unlock() } +} - /// Destroys OS-related resources with this RWLock. - /// - /// Behavior is undefined if there are any currently active users of this - /// lock. - #[inline] - pub unsafe fn destroy(&self) { - self.0.destroy() +impl Drop for MovableRWLock { + fn drop(&mut self) { + unsafe { self.0.destroy() }; } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 89addae0789..899cf6841ee 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -82,7 +82,7 @@ pub use core::time::Duration; /// 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] | @@ -158,7 +158,7 @@ pub struct Instant(time::Instant); /// 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] | diff --git a/library/stdarch b/library/stdarch -Subproject 37d6e1886369ea0176356286dc7fbd42ee5aa79 +Subproject 3001c75a1d2a81d2a76bef139c69387cb2ebb82 diff --git a/library/term/src/lib.rs b/library/term/src/lib.rs index 2116b433fce..943b276a220 100644 --- a/library/term/src/lib.rs +++ b/library/term/src/lib.rs @@ -30,11 +30,7 @@ //! [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))] diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index b7791b1b24d..84874a2d225 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -95,8 +95,9 @@ fn optgroups() -> getopts::Options { "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( @@ -336,10 +337,15 @@ fn get_format( } 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 )); diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 1721c3c14f9..9cfc7eaf4bc 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -10,7 +10,7 @@ use super::{ 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, @@ -277,6 +277,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu 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)?; diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs new file mode 100644 index 00000000000..ec66fc1219f --- /dev/null +++ b/library/test/src/formatters/junit.rs @@ -0,0 +1,174 @@ +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())) +} diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs index 1fb840520a6..2e03581b3af 100644 --- a/library/test/src/formatters/mod.rs +++ b/library/test/src/formatters/mod.rs @@ -8,10 +8,12 @@ use crate::{ }; 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; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 5e41d6d9692..e17fc08a9ae 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -169,7 +169,11 @@ impl<T: Write> PrettyFormatter<T> { fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> { let name = desc.padded_name(self.max_name_len, desc.name.padding()); - self.write_plain(&format!("test {} ... ", name))?; + if let Some(test_mode) = desc.test_mode() { + self.write_plain(&format!("test {} - {} ... ", name, test_mode))?; + } else { + self.write_plain(&format!("test {} ... ", name))?; + } Ok(()) } diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 6f46f7255a4..a2c223c494c 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -158,7 +158,11 @@ impl<T: Write> TerseFormatter<T> { fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> { let name = desc.padded_name(self.max_name_len, desc.name.padding()); - self.write_plain(&format!("test {} ... ", name))?; + if let Some(test_mode) = desc.test_mode() { + self.write_plain(&format!("test {} - {} ... ", name, test_mode))?; + } else { + self.write_plain(&format!("test {} ... ", name))?; + } Ok(()) } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index bda5ed888d7..3da4d434f48 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -19,7 +19,7 @@ #![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)] diff --git a/library/test/src/options.rs b/library/test/src/options.rs index 8e7bd8de924..baf36b5f1d8 100644 --- a/library/test/src/options.rs +++ b/library/test/src/options.rs @@ -39,6 +39,8 @@ pub enum OutputFormat { Terse, /// JSON output Json, + /// JUnit output + Junit, } /// Whether ignored test should be run or not diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 6a3f31b74ea..5a4a540b04e 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -61,6 +61,10 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), @@ -71,6 +75,10 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), @@ -89,6 +97,10 @@ pub fn do_not_run_ignored_tests() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -108,6 +120,10 @@ pub fn ignored_tests_result_in_ignored() { ignore: true, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -131,6 +147,10 @@ fn test_should_panic() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -154,6 +174,10 @@ fn test_should_panic_good_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -182,6 +206,10 @@ fn test_should_panic_bad_message() { ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -214,6 +242,10 @@ fn test_should_panic_non_string_message_type() { ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -238,6 +270,10 @@ fn test_should_panic_but_succeeds() { ignore: false, should_panic, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -270,6 +306,10 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(f)), @@ -303,6 +343,10 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type, }, testfn: DynTestFn(Box::new(f)), @@ -340,6 +384,10 @@ fn typed_test_desc(test_type: TestType) -> TestDesc { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type, } } @@ -451,6 +499,10 @@ pub fn exclude_should_panic_option() { ignore: false, should_panic: ShouldPanic::Yes, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), @@ -473,6 +525,10 @@ pub fn exact_filter_match() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(move || {})), @@ -565,6 +621,10 @@ pub fn sort_tests() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }, testfn: DynTestFn(Box::new(testfn)), @@ -642,6 +702,10 @@ pub fn test_bench_no_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }; @@ -662,6 +726,10 @@ pub fn test_bench_iter() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }; @@ -676,6 +744,10 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }; @@ -684,6 +756,10 @@ fn should_sort_failures_before_printing_them() { ignore: false, should_panic: ShouldPanic::No, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: TestType::Unknown, }; diff --git a/library/test/src/types.rs b/library/test/src/types.rs index c5d91f653b3..63907c71ea7 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -124,6 +124,10 @@ pub struct TestDesc { pub ignore: bool, pub should_panic: options::ShouldPanic, pub allow_fail: bool, + #[cfg(not(bootstrap))] + pub compile_fail: bool, + #[cfg(not(bootstrap))] + pub no_run: bool, pub test_type: TestType, } @@ -140,6 +144,36 @@ impl TestDesc { } } } + + /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test. + /// Descriptions include "should panic", "compile fail" and "compile". + #[cfg(not(bootstrap))] + pub fn test_mode(&self) -> Option<&'static str> { + if self.ignore { + return None; + } + match self.should_panic { + options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => { + return Some("should panic"); + } + options::ShouldPanic::No => {} + } + if self.allow_fail { + return Some("allow fail"); + } + if self.compile_fail { + return Some("compile fail"); + } + if self.no_run { + return Some("compile"); + } + None + } + + #[cfg(bootstrap)] + pub fn test_mode(&self) -> Option<&'static str> { + None + } } #[derive(Debug)] diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index f42ded62585..c76ba7667d4 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -21,8 +21,15 @@ compiler_builtins = "0.1.0" 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 = [] diff --git a/library/unwind/build.rs b/library/unwind/build.rs index d8bf152e4d6..0529d24a274 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -4,7 +4,8 @@ fn main() { 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; } @@ -19,6 +20,20 @@ fn main() { // 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"); @@ -57,101 +72,102 @@ mod llvm_libunwind { 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"); } } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index be5e56c71e3..eaeec72fbb5 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -37,9 +37,22 @@ cfg_if::cfg_if! { } #[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 @@ -68,5 +81,5 @@ extern "C" {} extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -#[link(name = "unwind", kind = "static-nobundle")] +#[link(name = "unwind", kind = "static")] extern "C" {} diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index a74df97a5c7..8445d811e0f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -40,7 +40,7 @@ cmake = "0.1.38" 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" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index d462dc4d116..ac8bbfe102d 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -124,6 +124,13 @@ fn main() { cmd.arg("-C").arg("target-feature=-crt-static"); } } + + if stage == "0" { + // Cargo doesn't pass RUSTFLAGS to proc_macros: + // https://github.com/rust-lang/cargo/issues/4423 + // Set `--cfg=bootstrap` explicitly instead. + cmd.arg("--cfg=bootstrap"); + } } if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { @@ -305,7 +312,7 @@ fn format_rusage_data(_child: Child) -> Option<String> { }; // Mac OS X reports the maxrss in bytes, not kb. let divisor = if env::consts::OS == "macos" { 1024 } else { 1 }; - let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor; + let maxrss = (rusage.ru_maxrss + (divisor - 1)) / divisor; let mut init_str = format!( "user: {USER_SEC}.{USER_USEC:03} \ diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index cba17c8e608..e4396d53016 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -41,7 +41,12 @@ fn main() { cmd.arg(arg); } if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() { - cmd.arg("-Clink-args=-fuse-ld=lld"); + cmd.arg("-Clink-arg=-fuse-ld=lld"); + if cfg!(windows) { + cmd.arg("-Clink-arg=-Wl,/threads:1"); + } else { + cmd.arg("-Clink-arg=-Wl,--threads=1"); + } } // Needed to be able to run all rustdoc tests. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 149a899cef7..7c7f162b82c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -648,18 +648,20 @@ class RustBuild(object): rev_parse = ["git", "rev-parse", "--show-toplevel"] top_level = subprocess.check_output(rev_parse, universal_newlines=True).strip() compiler = "{}/compiler/".format(top_level) + library = "{}/library/".format(top_level) # Look for a version to compare to based on the current commit. # Only commits merged by bors will have CI artifacts. merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"] commit = subprocess.check_output(merge_base, universal_newlines=True).strip() - # Warn if there were changes to the compiler since the ancestor commit. - status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler]) + # Warn if there were changes to the compiler or standard library since the ancestor commit. + status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library]) if status != 0: if download_rustc == "if-unchanged": return None - print("warning: `download-rustc` is enabled, but there are changes to compiler/") + print("warning: `download-rustc` is enabled, but there are changes to \ + compiler/ or library/") if self.verbose: print("using downloaded stage1 artifacts from CI (commit {})".format(commit)) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index f39e89a9d01..bc499fdba59 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -369,7 +369,8 @@ impl<'a> Builder<'a> { tool::Rustfmt, tool::Miri, tool::CargoMiri, - native::Lld + native::Lld, + native::CrtBeginEnd ), Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!( check::Std, @@ -573,6 +574,18 @@ impl<'a> Builder<'a> { 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); } @@ -708,7 +721,15 @@ impl<'a> Builder<'a> { 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. @@ -1121,6 +1142,7 @@ impl<'a> Builder<'a> { } if self.is_fuse_ld_lld(compiler.host) { cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); + cargo.env("RUSTDOC_FUSE_LD_LLD", "1"); } if let Some(target_linker) = self.linker(target) { @@ -1130,6 +1152,9 @@ impl<'a> Builder<'a> { if self.is_fuse_ld_lld(target) { rustflags.arg("-Clink-args=-fuse-ld=lld"); } + self.lld_flags(target).for_each(|flag| { + rustdocflags.arg(&flag); + }); if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 2676b3bf8e0..112a6ea9398 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -199,8 +199,9 @@ fn copy_self_contained_objects( 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)); @@ -268,7 +269,9 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car if builder.no_std(target) == Some(true) { let mut features = "compiler-builtins-mem".to_string(); - features.push_str(compiler_builtins_c_feature); + if !target.starts_with("bpf") { + features.push_str(compiler_builtins_c_feature); + } // for no-std targets we only compile a few no_std crates cargo @@ -325,6 +328,11 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car 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)] @@ -628,8 +636,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS cargo .env("CFG_RELEASE", builder.rust_release()) .env("CFG_RELEASE_CHANNEL", &builder.config.channel) - .env("CFG_VERSION", builder.rust_version()) - .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()); + .env("CFG_VERSION", builder.rust_version()); let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); @@ -1101,6 +1108,13 @@ impl Step for Assemble { let src_exe = exe("lld", target_compiler.host); let dst_exe = exe("rust-lld", target_compiler.host); builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); + // for `-Z gcc-ld=lld` + let gcc_ld_dir = libdir_bin.join("gcc-ld"); + t!(fs::create_dir(&gcc_ld_dir)); + builder.copy( + &lld_install.join("bin").join(&src_exe), + &gcc_ld_dir.join(exe("ld", target_compiler.host)), + ); } // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index aee3c8324bc..71ed0af4a7c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -402,6 +402,10 @@ impl Step for Rustc { if builder.config.lld_enabled { let exe = exe("rust-lld", compiler.host); builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe)); + // for `-Z gcc-ld=lld` + let gcc_lld_dir = dst_dir.join("gcc-ld"); + t!(fs::create_dir(&gcc_lld_dir)); + builder.copy(&src_dir.join(&exe), &gcc_lld_dir.join(&exe)); } // Copy over llvm-dwp if it's there diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f9972ac7b9d..d2fabf9967f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -434,6 +434,7 @@ impl Step for Std { cargo .arg("-p") .arg(package) + .arg("-Zskip-rustdoc-fingerprint") .arg("--") .arg("--markdown-css") .arg("rust.css") @@ -564,6 +565,7 @@ impl Step for Rustc { 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"); @@ -655,6 +657,7 @@ impl Step for Rustdoc { &[], ); + 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"); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2960dd3df6b..347236c655a 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -444,8 +444,13 @@ impl Build { build.verbose("finding compilers"); cc_detect::find(&mut build); - build.verbose("running sanity check"); - sanity::check(&mut build); + // When running `setup`, the profile is about to change, so any requirements we have now may + // be different on the next invocation. Don't check for them until the next time x.py is + // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. + if !matches!(build.config.cmd, Subcommand::Setup { .. }) { + build.verbose("running sanity check"); + sanity::check(&mut build); + } // If local-rust is the same major.minor as the current version, then force a // local-rebuild @@ -918,6 +923,21 @@ impl Build { self.config.use_lld && !target.contains("msvc") } + fn lld_flags(&self, target: TargetSelection) -> impl Iterator<Item = String> { + let mut options = [None, None]; + + if self.config.use_lld { + if self.is_fuse_ld_lld(target) { + options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string()); + } + + let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" }; + options[1] = Some(format!("-Clink-arg=-Wl,{}", threads)); + } + + std::array::IntoIter::new(options).flatten() + } + /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: TargetSelection) -> Option<bool> { if target.contains("pc-windows-msvc") { @@ -1366,7 +1386,7 @@ impl Build { 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); diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 47cf1172d36..fd39944e176 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -45,10 +45,6 @@ check-aux: 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: diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bde0a96f030..449fdb87b02 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -153,7 +153,7 @@ impl Step for Llvm { let llvm_targets = match &builder.config.llvm_targets { Some(s) => s, None => { - "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ + "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ Sparc;SystemZ;WebAssembly;X86" } }; @@ -181,7 +181,7 @@ impl Step for Llvm { .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"); @@ -858,3 +858,69 @@ impl HashStamp { 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 + } +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 98f753b25f0..fe4666effe6 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -449,6 +449,7 @@ impl Step for Miri { SourceType::Submodule, &[], ); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").arg("miri").arg("setup"); // Tell `cargo miri setup` where to find the sources. @@ -500,6 +501,7 @@ impl Step for Miri { SourceType::Submodule, &[], ); + cargo.add_rustc_lib_path(builder, compiler); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", miri_sysroot); @@ -508,8 +510,6 @@ impl Step for Miri { 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; @@ -774,6 +774,24 @@ impl Step for RustdocJSNotStd { } } +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, @@ -786,7 +804,17 @@ impl Step for RustdocGUI { 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<'_>) { @@ -795,58 +823,54 @@ impl Step for RustdocGUI { } 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); } } @@ -1107,19 +1131,6 @@ struct Compiletest { compare_mode: Option<&'static str>, } -impl Compiletest { - fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) { - if builder.config.use_lld { - if builder.is_fuse_ld_lld(target) { - flags.push("-Clink-arg=-fuse-ld=lld".to_string()); - } - - let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" }; - flags.push(format!("-Clink-arg=-Wl,{}", threads)); - } - } -} - impl Step for Compiletest { type Output = (); @@ -1256,7 +1267,6 @@ note: if you're sure you want to do this, please open an issue as to why. In the } } flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests)); - flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); if let Some(linker) = builder.linker(target) { @@ -1265,12 +1275,12 @@ note: if you're sure you want to do this, please open an issue as to why. In the let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); - Self::add_lld_flags(builder, compiler.host, &mut hostflags); + hostflags.extend(builder.lld_flags(compiler.host)); cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); - Self::add_lld_flags(builder, target, &mut targetflags); + targetflags.extend(builder.lld_flags(target)); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -1462,6 +1472,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the } } 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) { @@ -1492,6 +1503,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo); + cmd.arg("--channel").arg(&builder.config.channel); + builder.ci_env.force_coloring_in_ci(&mut cmd); builder.info(&format!( diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 98b5bfd3b98..9d75ad0918a 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -217,9 +217,8 @@ impl Step for ToolBuild { 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) } @@ -264,6 +263,7 @@ pub fn prepare_tool_cargo( 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() { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index b4421a82714..112979b0beb 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -45,6 +45,7 @@ pub fn libdir(target: TargetSelection) -> &'static str { } /// 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 { @@ -306,5 +307,6 @@ pub fn use_host_linker(target: TargetSelection) -> bool { || target.contains("wasm32") || target.contains("nvptx") || target.contains("fortanix") - || target.contains("fuchsia")) + || target.contains("fuchsia") + || target.contains("bpf")) } diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 1f8f9fc518a..cd0f01faa1b 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -144,7 +144,11 @@ ENV TARGETS=$TARGETS,armv7a-none-eabi # 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 \ diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index de3a99f34fc..b7f181adf2a 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -42,6 +42,9 @@ ENV \ 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 \ @@ -68,8 +71,10 @@ COPY host-x86_64/dist-various-2/shared.sh /tmp/ 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 @@ -99,6 +104,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown 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 diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh index ee76fafb1f9..4cbc2ccfe38 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh @@ -6,21 +6,11 @@ source shared.sh 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 diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index fd6dc563a0e..66afe84be4a 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -22,6 +22,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. RUN npm install es-check@5.2.3 -g +RUN npm install eslint@7.20.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -37,4 +38,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ 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 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index 00ad7b0a710..7f1a5820e22 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -17,27 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ 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 @@ -46,4 +26,4 @@ COPY scripts/cmake.sh /scripts/ 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 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index d4838c0d6f8..e2c064ee75d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -12,8 +12,48 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ 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 @@ -23,7 +63,19 @@ RUN /scripts/cmake.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.14 --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 diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c2ff62e7481..3a47076722c 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -235,6 +235,7 @@ docker \ --env TOOLSTATE_REPO_ACCESS_TOKEN \ --env TOOLSTATE_REPO \ --env TOOLSTATE_PUBLISH \ + --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \ --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \ --init \ --rm \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 343091cb779..e704071e401 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -407,6 +407,17 @@ jobs: - name: x86_64-gnu <<: *job-linux-xl + # This job ensures commits landing on nightly still pass the full + # test suite on the stable channel. There are some UI tests that + # depend on the channel being built (for example if they include the + # channel name on the output), and this builder prevents landing + # changes that would result in broken builds after a promotion. + - name: x86_64-gnu-stable + env: + IMAGE: x86_64-gnu + RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable + <<: *job-linux-xl + - name: x86_64-gnu-aux <<: *job-linux-xl diff --git a/src/ci/run.sh b/src/ci/run.sh index 35f80a935c6..c5e225c7cd1 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -65,7 +65,11 @@ fi # Always set the release channel for bootstrap; this is normally not important (i.e., only dist # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting # master, beta, or stable with a build to determine whether to run some checks (notably toolstate). -export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")" +if [[ -z "${RUST_CI_OVERRIDE_RELEASE_CHANNEL+x}" ]]; then + export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")" +else + export RUST_RELEASE_CHANNEL="${RUST_CI_OVERRIDE_RELEASE_CHANNEL}" +fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh index 631a7b247d5..fa738fe70c8 100755 --- a/src/ci/scripts/should-skip-this.sh +++ b/src/ci/scripts/should-skip-this.sh @@ -26,6 +26,12 @@ elif ! git diff --quiet "$BASE_COMMIT" -- src/tools/clippy src/tools/rustfmt; th # 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 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 1da3c411f17adb1ba5de1683bb6acee83362b54 +Subproject 302a115e8f71876dfc884aebb0ca5ccb02b8a96 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 569c3391f5c0cc43433bc77831d17f8ff4d7660 +Subproject 7349d173fa28a0bb834cf0264a05286620ef092 diff --git a/src/doc/reference b/src/doc/reference -Subproject 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a +Subproject 8f598e2af6c25b4a7ee88ef6a8196d9b8ea50ca diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 5f8c6da200ada77760a2fe1096938ef58151c9a +Subproject 805e016c5792ad2adabb66e348233067d5ea9f1 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447 +Subproject c8da5bfd1c7c71d90ef1646f5e0a9f6609d5c78 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b269aab9814..bc1873b6836 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -13,6 +13,7 @@ - [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) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 077c322bd77..05384117ac1 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -149,8 +149,7 @@ values: * `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated. * `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind - tables are required by the target or `-C panic=unwind`, an error will be - emitted. + tables are required by the target an error will be emitted. The default if not specified depends on the target. @@ -234,6 +233,8 @@ flavor. Valid options are: * `ptx-linker`: use [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia NVPTX GPGPU support. +* `bpf-linker`: use + [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support. * `wasm-ld`: use the [`wasm-ld`](https://lld.llvm.org/WebAssembly.html) executable, a port of LLVM `lld` for WebAssembly. * `ld64.lld`: use the LLVM `lld` executable with the [`-flavor darwin` diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f9a7599c497..3225e95941c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -144,7 +144,7 @@ target | std | notes `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) @@ -196,7 +196,7 @@ host tools. 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` | ? | | @@ -219,6 +219,8 @@ target | std | host | notes `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` +`bpfeb-unknown-none` | * | | BPF (big endian) +`bpfel-unknown-none` | * | | BPF (little endian) `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md new file mode 100644 index 00000000000..9aa5db26f91 --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md @@ -0,0 +1,56 @@ +# 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. diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index 8e3c6228189..cb7b85655b5 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -424,9 +424,7 @@ without including it in your main documentation. For example, you could write th `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; ``` diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 688be7aedea..f89495cca3a 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -229,15 +229,13 @@ Example: ```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. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 28b81a40265..e9b15666bb3 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -131,22 +131,6 @@ Book][unstable-masked] and [its tracking issue][issue-masked]. [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 diff --git a/src/doc/unstable-book/src/compiler-flags/force-warns.md b/src/doc/unstable-book/src/compiler-flags/force-warns.md new file mode 100644 index 00000000000..0a205be096c --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/force-warns.md @@ -0,0 +1,21 @@ +# `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. diff --git a/src/doc/unstable-book/src/language-features/external-doc.md b/src/doc/unstable-book/src/language-features/external-doc.md deleted file mode 100644 index effae5d2999..00000000000 --- a/src/doc/unstable-book/src/language-features/external-doc.md +++ /dev/null @@ -1,40 +0,0 @@ -# `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 diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md deleted file mode 100644 index 3ba4a3e6b1f..00000000000 --- a/src/doc/unstable-book/src/language-features/member-constraints.md +++ /dev/null @@ -1,29 +0,0 @@ -# `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. diff --git a/src/doc/unstable-book/src/language-features/more-qualified-paths.md b/src/doc/unstable-book/src/language-features/more-qualified-paths.md new file mode 100644 index 00000000000..857af577a6c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/more-qualified-paths.md @@ -0,0 +1,29 @@ +# `more_qualified_paths` + +The `more_qualified_paths` feature can be used in order to enable the +use of qualified paths in patterns. + +## Example + +```rust +#![feature(more_qualified_paths)] + +fn main() { + // destructure through a qualified path + let <Foo as A>::Assoc { br } = StructStruct { br: 2 }; +} + +struct StructStruct { + br: i8, +} + +struct Foo; + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = StructStruct; +} +``` diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 5503b3b4b32..03dbf4fb617 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -30,6 +30,7 @@ Inline assembly is currently supported on the following architectures: - Hexagon - MIPS32r2 and MIPS64r2 - wasm32 +- BPF ## Basic usage @@ -570,6 +571,8 @@ Here is the list of currently supported register classes: | PowerPC | `reg_nonzero` | | `r[1-31]` | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | | wasm32 | `local` | None\* | `r` | +| BPF | `reg` | `r[0-10]` | `r` | +| BPF | `wreg` | `w[0-10]` | `w` | > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > @@ -615,6 +618,8 @@ Each register class has constraints on which value types they can be used with. | PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` | | PowerPC | `freg` | None | `f32`, `f64` | | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` | +| BPF | `reg` | None | `i8` `i16` `i32` `i64` | +| BPF | `wreg` | `alu32` | `i8` `i16` `i32` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -674,6 +679,7 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r29` | `sp` | | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +| BPF | `r[0-10]` | `w[0-10]` | Some registers cannot be used for input or output operands: diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 2f7233685db..8647db5a45d 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -135,6 +135,8 @@ except NameError: unichr = chr +channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"] + class CustomHTMLParser(HTMLParser): """simplified HTML parser. @@ -270,6 +272,7 @@ def flatten(node): def normalize_xpath(path): + path = path.replace("{{channel}}", channel) if path.startswith('//'): return '.' + path # avoid warnings elif path.startswith('.//'): @@ -334,6 +337,7 @@ class CachedFiles(object): def check_string(data, pat, regexp): + pat = pat.replace("{{channel}}", channel) if not pat: return True # special case a presence testing elif regexp: diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 030892a432b..89280149a03 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,4 +149,57 @@ <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> diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 9c3c26f5978..17667770520 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -14,14 +14,6 @@ </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> @@ -30,15 +22,6 @@ </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> diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b816b9d7188..5ce75949457 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } pulldown-cmark = { version = "0.8", default-features = false } -minifier = "0.0.39" +minifier = "0.0.41" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 3bfc9fea62e..a3f63ea1046 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -561,7 +561,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } 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 { @@ -664,7 +664,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } } GenericParamDefKind::Lifetime => {} - GenericParamDefKind::Const { .. } => {} + GenericParamDefKind::Const { ref mut default, .. } => { + // We never want something like `impl<const N: usize = 10>` + default.take(); + } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6d05ac073cc..111827aacdf 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -527,7 +527,7 @@ fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::St } 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 { @@ -588,6 +588,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: 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), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index feeb03b1b67..d1c18821ea6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -418,9 +418,11 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { 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_, } } @@ -443,11 +445,15 @@ impl Clean<GenericParamDef> for ty::GenericParamDef { }, ) } - ty::GenericParamDefKind::Const { .. } => ( + ty::GenericParamDefKind::Const { has_default, .. } => ( self.name, GenericParamDefKind::Const { did: self.def_id, ty: cx.tcx.type_of(self.def_id).clean(cx), + default: match has_default { + true => Some(cx.tcx.const_param_default(self.def_id).to_string()), + false => None, + }, }, ), }; @@ -485,12 +491,15 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> { synthetic, }, ), - hir::GenericParamKind::Const { ref ty, default: _ } => ( + hir::GenericParamKind::Const { ref ty, default } => ( self.name.ident().name, GenericParamDefKind::Const { did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(), ty: ty.clean(cx), - // FIXME(const_generics_defaults): add `default` field here for docs + default: default.map(|ct| { + let def_id = cx.tcx.hir().local_def_id(ct.hir_id); + ty::Const::from_anon_const(cx.tcx, def_id).to_string() + }), }, ), }; @@ -1104,7 +1113,7 @@ impl Clean<Item> for ty::AssocItem { .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, @@ -1282,16 +1291,15 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { 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), } @@ -1306,6 +1314,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { 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), } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index edd3d77eeb7..6a7c3f8caa4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -499,7 +499,7 @@ impl Item { 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". @@ -526,7 +526,6 @@ impl Item { 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 } @@ -810,7 +809,7 @@ impl AttributesExt for [ast::Attribute] { // #[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; } @@ -895,9 +894,6 @@ crate enum DocFragmentKind { 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 @@ -931,18 +927,8 @@ impl<'a> FromIterator<&'a DocFragment> for String { 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 }) } @@ -989,45 +975,6 @@ impl Attributes { 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) { @@ -1051,18 +998,9 @@ impl Attributes { 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; } } @@ -1088,31 +1026,12 @@ impl Attributes { 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()) } }; @@ -1138,10 +1057,7 @@ impl Attributes { 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); @@ -1304,6 +1220,7 @@ crate enum GenericParamDefKind { Const { did: DefId, ty: Type, + default: Option<String>, }, } @@ -1519,6 +1436,7 @@ crate enum Type { QPath { name: Symbol, self_type: Box<Type>, + self_def_id: Option<DefId>, trait_: Box<Type>, }, @@ -1665,7 +1583,7 @@ impl 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_ { @@ -1767,37 +1685,6 @@ impl PrimitiveType { } } - 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") } @@ -1860,10 +1747,6 @@ impl PrimitiveType { }) } - crate fn to_url_str(&self) -> &'static str { - self.as_str() - } - crate fn as_sym(&self) -> Symbol { use PrimitiveType::*; match self { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 51a011cf197..706a56fbcbf 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,7 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder; 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; @@ -175,8 +175,9 @@ crate fn strip_type(ty: Type) -> Type { 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_)), }, @@ -450,35 +451,48 @@ crate fn get_auto_trait_and_blanket_impls( 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; @@ -542,3 +556,9 @@ crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool { && 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"); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index b75e98ae16c..1b5a00dde59 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,8 +6,10 @@ use std::path::PathBuf; 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; @@ -347,13 +349,6 @@ impl Options { 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); @@ -562,14 +557,7 @@ impl Options { } } - 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"); @@ -640,7 +628,8 @@ impl Options { 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, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3dd13a8f170..c3d9c4ea7f2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -217,8 +217,9 @@ crate fn create_config( // 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(), @@ -399,15 +400,18 @@ crate fn run_global_ctxt( 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(); }, ); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3a4d39e1d7f..88e2f6048e9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -880,6 +880,7 @@ impl Tester for Collector { let target = self.options.target.clone(); let target_str = target.to_string(); let unused_externs = self.unused_extern_reports.clone(); + let no_run = config.no_run || options.no_run; if !config.compile_fail { self.compiling_test_count.fetch_add(1, Ordering::SeqCst); } @@ -941,13 +942,16 @@ impl Tester for Collector { // compiler failures are test failures should_panic: testing::ShouldPanic::No, allow_fail: config.allow_fail, + #[cfg(not(bootstrap))] + compile_fail: config.compile_fail, + #[cfg(not(bootstrap))] + no_run, test_type: testing::TestType::DocTest, }, testfn: testing::DynTestFn(box move || { let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); }; - let no_run = config.no_run || options.no_run; let res = run_test( &test, &cratename, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fa57c9bda74..918a5cb5094 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,7 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX; 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; @@ -177,12 +177,22 @@ impl clean::GenericParamDef { Ok(()) } - clean::GenericParamDefKind::Const { ref ty, .. } => { + clean::GenericParamDefKind::Const { ref ty, ref default, .. } => { if f.alternate() { - write!(f, "const {}: {:#}", self.name, ty.print(cx)) + write!(f, "const {}: {:#}", self.name, ty.print(cx))?; } else { - write!(f, "const {}: {}", self.name, ty.print(cx)) + write!(f, "const {}: {}", self.name, ty.print(cx))?; } + + if let Some(default) = default { + if f.alternate() { + write!(f, " = {:#}", default)?; + } else { + write!(f, " = {}", default)?; + } + } + + Ok(()) } }) } @@ -574,7 +584,7 @@ fn primitive_link( f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">", "../".repeat(len), - prim.to_url_str() + prim.as_sym() )?; needs_termination = true; } @@ -603,7 +613,7 @@ fn primitive_link( f, "<a class=\"primitive\" href=\"{}/primitive.{}.html\">", loc.join("/"), - prim.to_url_str() + prim.as_sym() )?; needs_termination = true; } @@ -677,7 +687,7 @@ fn fmt_type<'cx>( 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!( @@ -836,10 +846,13 @@ fn fmt_type<'cx>( 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, }; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ec04c94dc11..d2d1757b900 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -87,7 +87,7 @@ crate fn render<T: Print, S: Print>( {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!\">\ @@ -105,8 +105,8 @@ crate fn render<T: Print, S: Print>( 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\">\ @@ -119,7 +119,7 @@ crate fn render<T: Print, S: Print>( {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>\ @@ -161,7 +161,7 @@ crate fn render<T: Print, S: Print>( } }, title = page.title, - description = page.description, + description = Escape(page.description), keywords = page.keywords, favicon = if layout.favicon.is_empty() { format!( @@ -235,6 +235,7 @@ crate fn redirect(url: &str) -> String { <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> diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 8676efd9fa8..1898f5feed2 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::sync::mpsc::{channel, Receiver}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; @@ -51,9 +51,6 @@ crate struct Context<'tcx> { pub(super) render_redirect_pages: bool, /// The map used to ensure all generated 'id=' attributes are unique. pub(super) id_map: RefCell<IdMap>, - /// Tracks section IDs for `Deref` targets so they match in both the main - /// body and the sidebar. - pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>, /// Shared mutable state. /// /// Issue for improving the situation: [#82381][] @@ -74,7 +71,7 @@ crate struct Context<'tcx> { // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Context<'_>, 152); +rustc_data_structures::static_assert_size!(Context<'_>, 112); /// Shared mutable state used in [`Context`] and elsewhere. crate struct SharedContext<'tcx> { @@ -200,8 +197,15 @@ impl<'tcx> Context<'tcx> { ) }; 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, @@ -479,7 +483,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { dst, render_redirect_pages: false, id_map: RefCell::new(id_map), - deref_id_map: RefCell::new(FxHashMap::default()), shared: Rc::new(scx), cache: Rc::new(cache), }; @@ -497,7 +500,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { dst: self.dst.clone(), render_redirect_pages: self.render_redirect_pages, id_map: RefCell::new(IdMap::new()), - deref_id_map: RefCell::new(FxHashMap::default()), shared: Rc::clone(&self.shared), cache: Rc::clone(&self.cache), } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 318e1b44f86..ebb4cfb7d48 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -33,7 +33,6 @@ mod print_item; mod write_shared; crate use context::*; -crate use write_shared::FILES_UNVERSIONED; use std::collections::VecDeque; use std::default::Default; @@ -323,7 +322,13 @@ impl AllTypes { if !e.is_empty() { let mut e: Vec<&ItemEntry> = e.iter().collect(); e.sort(); - write!(f, "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", title, title, class); + write!( + f, + "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", + title.replace(' ', "-"), // IDs cannot contain whitespaces. + title, + class + ); for s in e.iter() { write!(f, "<li>{}</li>", s.print()); @@ -347,7 +352,7 @@ impl AllTypes { </h1>", ); // Note: print_entries does not escape the title, because we know the current set of titles - // don't require escaping. + // doesn't require escaping. print_entries(f, &self.structs, "Structs", "structs"); print_entries(f, &self.enums, "Enums", "enums"); print_entries(f, &self.unions, "Unions", "unions"); @@ -1040,17 +1045,12 @@ fn render_assoc_items( RenderMode::Normal } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { - let id = - cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); - debug!("Adding {} to deref id map", type_.print(cx)); - cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone()); write!( w, - "<h2 id=\"{id}\" class=\"small-section-header\">\ + "<h2 id=\"deref-methods\" class=\"small-section-header\">\ Methods from {trait_}<Target = {type_}>\ - <a href=\"#{id}\" class=\"anchor\"></a>\ + <a href=\"#deref-methods\" class=\"anchor\"></a>\ </h2>", - id = id, trait_ = trait_.print(cx), type_ = type_.print(cx), ); @@ -1075,6 +1075,9 @@ fn render_assoc_items( ); } } + if let AssocItemRender::DerefFor { .. } = what { + return; + } if !traits.is_empty() { let deref_impl = traits .iter() @@ -1085,13 +1088,6 @@ fn render_assoc_items( .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } - - // If we were already one level into rendering deref methods, we don't want to render - // anything after recursing into any further deref methods above. - if let AssocItemRender::DerefFor { .. } = what { - return; - } - let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = traits.iter().partition(|t| t.inner_impl().synthetic); let (blanket_impl, concrete): (Vec<&&Impl>, _) = @@ -1281,7 +1277,6 @@ fn render_impl( // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], ) { - let tcx = cx.tcx(); let cache = cx.cache(); let traits = &cache.traits; let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); @@ -1370,7 +1365,11 @@ fn render_impl( }) }) .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, @@ -1389,13 +1388,17 @@ fn render_impl( ); 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, @@ -1407,12 +1410,16 @@ fn render_impl( ); 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, @@ -1432,12 +1439,12 @@ fn render_impl( ); 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, @@ -1449,7 +1456,7 @@ fn render_impl( ); 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), @@ -1541,83 +1548,34 @@ fn render_impl( ); } } - let toggled = !impl_items.is_empty() || !default_impl_items.is_empty(); - let open_details = |close_tags: &mut String| { + if render_mode == RenderMode::Normal { + let is_implementing_trait = i.inner_impl().trait_.is_some(); + let toggled = !impl_items.is_empty() || !default_impl_items.is_empty(); if toggled { close_tags.insert_str(0, "</details>"); - "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>" - } else { - "" - } - }; - if render_mode == RenderMode::Normal { - let id = cx.derive_id(match i.inner_impl().trait_ { - Some(ref t) => { - 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(), - }); - let aliases = if aliases.is_empty() { - String::new() - } else { - format!(" data-aliases=\"{}\"", aliases.join(",")) - }; - if let Some(use_absolute) = use_absolute { - write!( - w, - "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", - open_details(&mut close_tags), - id, - aliases - ); - write!(w, "{}", i.inner_impl().print(use_absolute, cx)); - if show_def_docs { - for it in &i.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { - w.write_str("<span class=\"where fmt-newline\"> "); - assoc_type( - w, - it, - &[], - Some(&tydef.type_), - AssocItemLink::Anchor(None), - "", - cx, - ); - w.write_str(";</span>"); - } - } + if is_implementing_trait { + write!(w, "<details class=\"rustdoc-toggle implementors-toggle\">"); + } else { + write!(w, "<details class=\"rustdoc-toggle implementors-toggle\" open>"); } - w.write_str("</code>"); - } else { - write!( - w, - "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", - open_details(&mut close_tags), - id, - aliases, - i.inner_impl().print(false, cx) - ); } - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - render_stability_since_raw( + if toggled { + write!(w, "<summary>") + } + render_impl_summary( w, - i.impl_item.stable_since(tcx).as_deref(), - i.impl_item.const_stable_since(tcx).as_deref(), + cx, + i, outer_version, outer_const_version, + show_def_docs, + use_absolute, + is_on_foreign_type, + aliases, ); - write_srclink(cx, &i.impl_item, w); - if !toggled { - w.write_str("</h3>"); - } else { - w.write_str("</h3></summary>"); + if toggled { + write!(w, "</summary>") } - if trait_.is_some() { if let Some(portability) = portability(&i.impl_item, Some(parent)) { write!(w, "<div class=\"item-info\">{}</div>", portability); @@ -1641,19 +1599,84 @@ fn render_impl( ); } } - 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>"); } w.write_str(&close_tags); } +fn render_impl_summary( + w: &mut Buffer, + cx: &Context<'_>, + i: &Impl, + outer_version: Option<&str>, + outer_const_version: Option<&str>, + show_def_docs: bool, + use_absolute: Option<bool>, + is_on_foreign_type: bool, + // This argument is used to reference same type with different paths to avoid duplication + // in documentation pages for trait with automatic implementations like "Send" and "Sync". + aliases: &[String], +) { + let tcx = cx.tcx(); + let id = cx.derive_id(match i.inner_impl().trait_ { + Some(ref t) => { + 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(), + }); + let aliases = if aliases.is_empty() { + String::new() + } else { + format!(" data-aliases=\"{}\"", aliases.join(",")) + }; + if let Some(use_absolute) = use_absolute { + write!( + w, + "<div id=\"{}\" class=\"impl has-srclink\"{}>\ + <code class=\"in-band\">", + id, aliases + ); + write!(w, "{}", i.inner_impl().print(use_absolute, cx)); + if show_def_docs { + for it in &i.inner_impl().items { + if let clean::TypedefItem(ref tydef, _) = *it.kind { + w.write_str("<span class=\"where fmt-newline\"> "); + assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx); + w.write_str(";</span>"); + } + } + } + w.write_str("</code>"); + } else { + write!( + w, + "<div id=\"{}\" class=\"impl has-srclink\"{}>\ + <code class=\"in-band\">{}</code>", + id, + aliases, + i.inner_impl().print(false, cx) + ); + } + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + render_stability_since_raw( + w, + i.impl_item.stable_since(tcx).as_deref(), + i.impl_item.const_stable_since(tcx).as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, &i.impl_item, w); + w.write_str("</div>"); +} + fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 }; @@ -1695,7 +1718,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { "<div class=\"block version\">\ <p>Version {}</p>\ </div>", - Escape(version) + Escape(version), ); } } @@ -1705,9 +1728,10 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { 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), @@ -1717,7 +1741,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { 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 @@ -1728,22 +1752,24 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { // 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}\">\ @@ -1752,17 +1778,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { 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>"); } @@ -1992,14 +2008,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c)) .collect::<Vec<_>>(); if !ret.is_empty() { - let deref_id_map = cx.deref_id_map.borrow(); - let id = deref_id_map - .get(&real_target.def_id_full(c).unwrap()) - .expect("Deref section without derived id"); write!( out, - "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}<Target={}></a>", - id, + "<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}<Target={}></a>", Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))), Escape(&format!("{:#}", real_target.print(cx))), ); @@ -2270,8 +2281,8 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean: } } -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"), @@ -2303,10 +2314,14 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { 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 @@ -2333,13 +2348,9 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { 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)); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index bac9c21f0f3..04464b622d7 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -75,13 +75,14 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, ); } } - 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, @@ -262,7 +263,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl 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\">\ @@ -578,14 +579,23 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra 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() { @@ -1502,7 +1512,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { 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.", ); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index bd781e7b741..a4188e6b203 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -18,7 +18,7 @@ use crate::docfs::PathError; 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, @@ -33,6 +33,8 @@ crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| { "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, @@ -225,7 +227,6 @@ pub(super) fn write_shared( )?; 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)?; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1ed94ec109c..1a15a444a70 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -561,41 +561,40 @@ function hideThemeButtonState() { } }()); - 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) { @@ -634,28 +633,32 @@ function hideThemeButtonState() { 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) { @@ -764,138 +767,6 @@ function hideThemeButtonState() { innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed); } - function collapseDocs(toggle, mode) { - if (!toggle || !toggle.parentNode) { - return; - } - - function adjustToggle(arg) { - return function(e) { - if (hasClass(e, "toggle-label")) { - if (arg) { - e.style.display = "inline-block"; - } else { - e.style.display = "none"; - } - } - if (hasClass(e, "inner")) { - e.innerHTML = labelForToggleButton(arg); - } - }; - } - - function implHider(addOrRemove, fullHide) { - return function(n) { - var shouldHide = - fullHide || - hasClass(n, "method") || - hasClass(n, "associatedconstant"); - if (shouldHide || hasClass(n, "type")) { - if (shouldHide) { - if (addOrRemove) { - addClass(n, "hidden-by-impl-hider"); - } else { - removeClass(n, "hidden-by-impl-hider"); - } - } - var ns = n.nextElementSibling; - while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) { - if (addOrRemove) { - addClass(ns, "hidden-by-impl-hider"); - } else { - removeClass(ns, "hidden-by-impl-hider"); - } - ns = ns.nextElementSibling; - } - } - }; - } - - var relatedDoc; - var action = mode; - if (!hasClass(toggle.parentNode, "impl")) { - relatedDoc = toggle.parentNode.nextElementSibling; - if (hasClass(relatedDoc, "item-info")) { - relatedDoc = relatedDoc.nextElementSibling; - } - if (hasClass(relatedDoc, "docblock")) { - if (mode === "toggle") { - if (hasClass(relatedDoc, "hidden-by-usual-hider")) { - action = "show"; - } else { - action = "hide"; - } - } - if (action === "hide") { - addClass(relatedDoc, "hidden-by-usual-hider"); - onEachLazy(toggle.childNodes, adjustToggle(true)); - addClass(toggle.parentNode, "collapsed"); - } else if (action === "show") { - removeClass(relatedDoc, "hidden-by-usual-hider"); - removeClass(toggle.parentNode, "collapsed"); - onEachLazy(toggle.childNodes, adjustToggle(false)); - } - } - } else { - // we are collapsing the impl block(s). - - var parentElem = toggle.parentNode; - relatedDoc = parentElem; - var docblock = relatedDoc.nextElementSibling; - - while (!hasClass(relatedDoc, "impl-items")) { - relatedDoc = relatedDoc.nextElementSibling; - } - - if (!relatedDoc && !hasClass(docblock, "docblock")) { - return; - } - - // Hide all functions, but not associated types/consts. - - if (mode === "toggle") { - if (hasClass(relatedDoc, "fns-now-collapsed") || - hasClass(docblock, "hidden-by-impl-hider")) { - action = "show"; - } else { - action = "hide"; - } - } - - var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main"; - if (action === "show") { - removeClass(relatedDoc, "fns-now-collapsed"); - // Stability/deprecation/portability information is never hidden. - if (!hasClass(docblock, "item-info")) { - removeClass(docblock, "hidden-by-usual-hider"); - } - onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule)); - onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule)); - } else if (action === "hide") { - addClass(relatedDoc, "fns-now-collapsed"); - // Stability/deprecation/portability information should be shown even when detailed - // info is hidden. - if (!hasClass(docblock, "item-info")) { - addClass(docblock, "hidden-by-usual-hider"); - } - onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule)); - onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule)); - } - } - } - - function collapseNonInherent(e) { - // inherent impl ids are like "impl" or impl-<number>'. - // they will never be hidden by default. - var n = e.parentElement; - if (n.id.match(/^impl(?:-\d+)?$/) === null) { - // Automatically minimize all non-inherent impls - if (hasClass(n, "impl")) { - collapseDocs(e, "hide"); - } - } - } - function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } @@ -908,26 +779,29 @@ function hideThemeButtonState() { var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true"; var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false"; + var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false"; var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false"; - var impl_list = document.getElementById("trait-implementations-list"); - if (impl_list !== null) { - onEachLazy(impl_list.getElementsByClassName("rustdoc-toggle"), function(e) { - collapseNonInherent(e); - }); + function openImplementors(id) { + var list = document.getElementById(id); + if (list !== null) { + onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) { + e.open = true; + }); + } } - var blanket_list = document.getElementById("blanket-implementations-list"); - if (blanket_list !== null) { - onEachLazy(blanket_list.getElementsByClassName("rustdoc-toggle"), function(e) { - collapseNonInherent(e); - }); + if (!hideImplementations) { + openImplementors("trait-implementations-list"); + openImplementors("blanket-implementations-list"); + } + + if (!hideImplementors) { + openImplementors("implementors-list"); } - onEachLazy(document.getElementsByTagName("details"), function (e) { - var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle"); - var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle"); - if (showLargeItem || showImplementor) { + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) { + if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) { e.open = true; } if (hideMethodDocs && hasClass(e, "method-toggle")) { @@ -936,18 +810,6 @@ function hideThemeButtonState() { }); - var currentType = document.getElementsByClassName("type-decl")[0]; - if (currentType) { - currentType = currentType.getElementsByClassName("rust")[0]; - if (currentType) { - onEachLazy(currentType.classList, function(item) { - if (item !== "main") { - return true; - } - }); - } - } - var pageId = getPageId(); if (pageId !== null) { expandSection(pageId); diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt new file mode 100644 index 00000000000..922d5fdc18d --- /dev/null +++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt @@ -0,0 +1,93 @@ +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. diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff new file mode 100644 index 00000000000..01d6b6b5466 --- /dev/null +++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff Binary files differdiff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 6d581108836..7535145caa5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -66,6 +66,14 @@ 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; @@ -90,7 +98,7 @@ html { /* 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; @@ -109,8 +117,7 @@ h2 { 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; @@ -127,29 +134,38 @@ h1.fqn { 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, .impl-items .method, +.impl-items .type, .impl-items .associatedconstant, +.impl-items .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; @@ -295,17 +311,18 @@ nav.sub { 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 { @@ -453,15 +470,7 @@ nav.sub { 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; } @@ -534,7 +543,7 @@ h4 > code, h3 > code, .invisible > code { } .content .multi-column li { width: 100%; display: inline-block; } -.content .method { +.content > .methods > .method { font-size: 1em; position: relative; } @@ -546,7 +555,7 @@ h4 > code, h3 > code, .invisible > code { 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; } @@ -555,9 +564,6 @@ h4 > code, h3 > code, .invisible > code { margin-left: 20px; margin-top: -34px; } -.content .docblock > .impl-items > h4 { - border-bottom: 0; -} .content .docblock >.impl-items .table-display { margin: 0; } @@ -679,7 +685,8 @@ a { text-decoration: underline; } -.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink { +.invisible > .srclink, +.method > code + .srclink { position: absolute; top: 0; right: 0; @@ -759,35 +766,42 @@ a { .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; } -tr.result 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; } -tr.result span.keyword::after { - content: ' (keyword)'; - font-style: italic; +.search-results .result-name > span { + display: inline-block; + margin: 0; + font-weight: normal; } body.blur > :not(#help) { @@ -909,7 +923,7 @@ 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; @@ -1120,6 +1134,13 @@ a.test-arrow:hover{ 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; @@ -1183,12 +1204,6 @@ pre.rust { margin-left: 5px; } -h4 > .notable-traits { - position: absolute; - left: -44px; - top: 2px; -} - #all-types { text-align: center; border: 1px solid; @@ -1302,14 +1317,6 @@ h4 > .notable-traits { border-top: 1px solid; } - - -h3.notable { - margin: 0; - margin-bottom: 13px; - font-size: 19px; -} - kbd { display: inline-block; padding: 3px 5px; @@ -1454,13 +1461,12 @@ details.rustdoc-toggle > summary.hideme::before { 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; } @@ -1602,10 +1608,6 @@ details.undocumented[open] > summary::before { padding: 0; } - .content h4 > .out-of-band { - position: inherit; - } - #search { margin-left: 0; } @@ -1625,7 +1627,7 @@ details.undocumented[open] > summary::before { z-index: 1; } - h4 > .notable-traits { + .notable-traits { position: absolute; left: -22px; top: 24px; @@ -1733,6 +1735,18 @@ details.undocumented[open] > summary::before { .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 { diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js index 01cfffc5429..35be246b5bf 100644 --- a/src/librustdoc/html/static/search.js +++ b/src/librustdoc/html/static/search.js @@ -885,12 +885,12 @@ window.initSearch = function(rawSearchIndex) { focusSearchResult(); } - // focus the first search result on the active tab, or the result that + // Focus the first search result on the active tab, or the result that // was focused last time this tab was active. function focusSearchResult() { var target = searchState.focusedByTab[searchState.currentTab] || - document.querySelectorAll(".search-results.active a").item(0) || - document.querySelectorAll("#titles > button").item(searchState.currentTab); + document.querySelectorAll(".search-results.active a").item(0) || + document.querySelectorAll("#titles > button").item(searchState.currentTab); if (target) { target.focus(); } @@ -968,39 +968,72 @@ window.initSearch = function(rawSearchIndex) { 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.insertAdjacentHTML("beforeend", item.desc); + + 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/>" + @@ -1012,7 +1045,7 @@ window.initSearch = function(rawSearchIndex) { "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]; } @@ -1072,10 +1105,18 @@ window.initSearch = function(rawSearchIndex) { 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); var elems = document.getElementById("titles").childNodes; elems[0].onclick = function() { printTab(0); }; @@ -1365,7 +1406,6 @@ window.initSearch = function(rawSearchIndex) { if (e.which === 38) { // up var previous = document.activeElement.previousElementSibling; if (previous) { - console.log("previousElementSibling", previous); previous.focus(); } else { searchState.focus(); diff --git a/src/librustdoc/html/static/sidebar-items.js b/src/librustdoc/html/static/sidebar-items.js deleted file mode 100644 index 81172ba0d92..00000000000 --- a/src/librustdoc/html/static/sidebar-items.js +++ /dev/null @@ -1 +0,0 @@ -initSidebarItems({}); diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index e59909ffdf0..d220d8708a1 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -10,8 +10,7 @@ body { 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 { @@ -20,10 +19,10 @@ 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; } @@ -407,6 +406,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #5c6773; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #5c6773; +} + #titles > button.selected { background-color: #141920 !important; border-bottom: 1px solid #ffb44c !important; @@ -565,10 +568,10 @@ kbd { 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; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index a2bcb43f44e..6385a763f2e 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -3,15 +3,13 @@ body { 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; } @@ -356,6 +354,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #777; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #d2d2d2; +} + #titles > button:not(.selected) { background-color: #252525; border-top-color: #252525; @@ -444,10 +446,10 @@ kbd { 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; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 2ad3551d900..c19d5bfc317 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -5,15 +5,13 @@ body { 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; } @@ -348,6 +346,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #999; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #DDDDDD; +} + #titles > button:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; @@ -435,10 +437,10 @@ kbd { 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; } diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 4e3d5ff0a4a..ca7e5ef8150 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -126,11 +126,19 @@ crate mod source_code_pro { 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"); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 5ac43c73646..7086dd8c4d2 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -317,7 +317,9 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), default: default.map(|x| x.into_tcx(tcx)), }, - Const { did: _, ty } => GenericParamDefKind::Const(ty.into_tcx(tcx)), + Const { did: _, ty, default } => { + GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default } + } } } } @@ -379,7 +381,7 @@ impl FromWithTcx<clean::Type> for Type { .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))), @@ -396,7 +398,7 @@ impl FromWithTcx<clean::Type> for Type { 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)), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index f8bd9710813..0d84bf250c9 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -234,7 +234,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), - format_version: 5, + format_version: 6, }; let mut p = self.out_path.clone(); p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5ede3780e87..ee7a716655b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -8,7 +8,6 @@ #![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(test)] #![feature(crate_visibility_modifier)] #![feature(never_type)] @@ -82,6 +81,8 @@ use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGro 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: @@ -511,6 +512,14 @@ fn opts() -> Vec<RustcOptGroup> { "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") }), @@ -582,9 +591,6 @@ fn opts() -> Vec<RustcOptGroup> { "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( "", @@ -607,7 +613,10 @@ fn usage(argv0: &str) { } 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()`. diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 81c90f4eaa7..247a020f2a2 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -91,10 +91,10 @@ impl Res { } } - 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(), } } @@ -388,7 +388,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { 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))) }) }) @@ -481,7 +481,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { 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())), } @@ -1148,7 +1148,7 @@ impl LinkCollector<'_, '_> { 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]; @@ -1999,8 +1999,11 @@ fn disambiguator_error( ) { 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); }); } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 4e621e100e3..6d7c45f6eea 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -3,8 +3,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::DefId; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::DefIdTree; use rustc_span::symbol::sym; @@ -53,6 +52,39 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { } } + let mut cleaner = BadImplStripper { prims, items: crate_items }; + + // scan through included items ahead of time to splice in Deref targets to the "valid" sets + for it in &new_items { + if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { + if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { + let target = items + .iter() + .find_map(|item| match *item.kind { + TypedefItem(ref t, true) => Some(&t.type_), + _ => None, + }) + .expect("Deref impl without Target type"); + + if let Some(prim) = target.primitive_type() { + cleaner.prims.insert(prim); + } else if let Some(did) = target.def_id() { + cleaner.items.insert(did.into()); + } + } + } + } + + new_items.retain(|it| { + if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { + cleaner.keep_impl(for_) + || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) + || blanket_impl.is_some() + } else { + true + } + }); + // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations` // doesn't work with it anyway, so pull them from the HIR map instead let mut extra_attrs = Vec::new(); @@ -84,53 +116,6 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { } } - let mut cleaner = BadImplStripper { prims, items: crate_items }; - - let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default(); - // Gather all type to `Deref` target edges. - for it in &new_items { - if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { - if trait_.def_id() == cx.tcx.lang_items().deref_trait() { - let target = items.iter().find_map(|item| match *item.kind { - TypedefItem(ref t, true) => Some(&t.type_), - _ => None, - }); - if let (Some(for_did), Some(target)) = (for_.def_id(), target) { - type_did_to_deref_target.insert(for_did, target); - } - } - } - } - // Follow all `Deref` targets of included items and recursively add them as valid - fn add_deref_target( - map: &FxHashMap<DefId, &Type>, - cleaner: &mut BadImplStripper, - type_did: &DefId, - ) { - if let Some(target) = map.get(type_did) { - debug!("add_deref_target: type {:?}, target {:?}", type_did, target); - if let Some(target_prim) = target.primitive_type() { - cleaner.prims.insert(target_prim); - } else if let Some(target_did) = target.def_id() { - // `impl Deref<Target = S> for S` - if target_did == *type_did { - // Avoid infinite cycles - return; - } - cleaner.items.insert(target_did.into()); - add_deref_target(map, cleaner, &target_did.into()); - } - } - } - for type_did in type_did_to_deref_target.keys() { - // Since only the `DefId` portion of the `Type` instances is known to be same for both the - // `Deref` target type and the impl for type positions, this map of types is keyed by - // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly. - if cleaner.keep_impl_with_def_id(FakeDefId::Real(*type_did)) { - add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did); - } - } - let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind { items } else { @@ -138,19 +123,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { }; items.extend(synth_impls); - for it in new_items.drain(..) { - if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { - if !(cleaner.keep_impl(for_) - || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) - || blanket_impl.is_some()) - { - continue; - } - } - - items.push(it); - } - + items.extend(new_items); krate } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 191d8d5a2ea..b563c4f4799 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -9,6 +9,7 @@ use rustc_hir::Node; 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}; @@ -76,7 +77,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &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 diff --git a/src/llvm-project b/src/llvm-project -Subproject 5f67a5715771b7d29e4713e8d68338602d216dc +Subproject 39c5555872cc5d379cc3535a31dc0cdac969466 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 72a4d9a1830..6d9a5cb515a 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -324,7 +324,7 @@ pub struct GenericParamDef { pub enum GenericParamDefKind { Lifetime, Type { bounds: Vec<GenericBound>, default: Option<Type> }, - Const(Type), + Const { ty: Type, default: Option<String> }, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] diff --git a/src/stage0.txt b/src/stage0.txt index 6ad0f6db42b..1027057f385 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # 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 diff --git a/src/test/assembly/asm/bpf-types.rs b/src/test/assembly/asm/bpf-types.rs new file mode 100644 index 00000000000..cc3863d03cd --- /dev/null +++ b/src/test/assembly/asm/bpf-types.rs @@ -0,0 +1,154 @@ +// min-llvm-version: 10.0.1 +// assembly-output: emit-asm +// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 +// needs-llvm-components: bpf + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const u64; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); +} + +// CHECK-LABEL: sym_fn +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64 i64 reg); + +// CHECK-LABEL: wreg_i8: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i8 i8 wreg); + +// CHECK-LABEL: wreg_i16: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i16 i16 wreg); + +// CHECK-LABEL: wreg_i32: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i32 i32 wreg); + +// CHECK-LABEL: r0_i8: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i8 i8 "r0"); + +// CHECK-LABEL: r0_i16: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i16 i16 "r0"); + +// CHECK-LABEL: r0_i32: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i32 i32 "r0"); + +// CHECK-LABEL: r0_i64: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i64 i64 "r0"); + +// CHECK-LABEL: w0_i8: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i8 i8 "w0"); + +// CHECK-LABEL: w0_i16: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i16 i16 "w0"); + +// CHECK-LABEL: w0_i32: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i32 i32 "w0"); diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs index ce2b3b1cfa4..2cd74a01c84 100644 --- a/src/test/assembly/static-relocation-model.rs +++ b/src/test/assembly/static-relocation-model.rs @@ -1,9 +1,10 @@ // 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] @@ -75,3 +76,9 @@ pub fn mango() -> u8 { 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 diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index f2641404aae..e410180bfff 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -17,33 +17,33 @@ async fn async_fn_test() { // 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 diff --git a/src/test/codegen/bpf-alu32.rs b/src/test/codegen/bpf-alu32.rs new file mode 100644 index 00000000000..c68bffd03e2 --- /dev/null +++ b/src/test/codegen/bpf-alu32.rs @@ -0,0 +1,11 @@ +// only-bpf +#![crate_type = "lib"] +#![feature(bpf_target_feature)] +#![no_std] + +#[no_mangle] +#[target_feature(enable = "alu32")] +// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 { +pub unsafe fn foo(arg: u8) -> u8 { + arg +} diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 44be71f3b9b..7edb07d224c 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -21,33 +21,33 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // 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 diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs new file mode 100644 index 00000000000..550cc66f389 --- /dev/null +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -0,0 +1,97 @@ +// 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() { () } diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 1a99f841250..68e73b5f38d 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -1,6 +1,7 @@ // 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 @@ -111,11 +112,11 @@ // 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; diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index f698f8835a2..ea1ea1943e9 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; 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(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { 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); @@ -46,7 +46,7 @@ pub mod fn_calls_free_fn { 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 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { 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 } @@ -66,7 +66,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs index 02453740079..084ed232a55 100644 --- a/src/test/incremental/callee_caller_cross_crate/b.rs +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -6,12 +6,12 @@ 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); } diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index 8d98cfac8a4..3308ea56222 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -70,7 +70,7 @@ pub mod point { 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) } @@ -86,7 +86,7 @@ pub mod fn_with_type_in_sig { 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) } @@ -102,7 +102,7 @@ pub mod call_fn_with_type_in_sig { 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() } @@ -115,7 +115,7 @@ pub mod fn_with_type_in_body { 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() } @@ -125,7 +125,7 @@ pub mod call_fn_with_type_in_body { 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 } } @@ -135,7 +135,7 @@ pub mod fn_make_struct { 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 } @@ -145,7 +145,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index ba4bf4e7b7d..1791c089cfa 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { 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(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { 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); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { 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 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { 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 } @@ -93,7 +93,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index 5072ef609e2..1c27ec3a3f7 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -23,7 +23,7 @@ extern crate point; 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(); @@ -34,7 +34,7 @@ pub mod fn_calls_methods_in_same_impl { 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); @@ -45,7 +45,7 @@ pub mod fn_calls_methods_in_another_impl { 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 } } @@ -55,7 +55,7 @@ pub mod fn_make_struct { 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 } @@ -65,7 +65,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 11ba96a8c8d..cf43e4757cb 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { 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(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { 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); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { 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 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { 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 } @@ -93,7 +93,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index 2aeecfc89d5..9fe8b5df93a 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; 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(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { 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); @@ -46,7 +46,7 @@ pub mod fn_calls_methods_in_another_impl { 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 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { 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 } @@ -66,7 +66,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index a192dff19e9..1b87b18fcd4 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -42,7 +42,7 @@ pub mod point { 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(); @@ -53,7 +53,7 @@ pub mod fn_calls_changed_method { 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(); @@ -64,7 +64,7 @@ pub mod fn_calls_another_method { 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 } } @@ -74,7 +74,7 @@ pub mod fn_make_struct { 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 } @@ -84,7 +84,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index b0476168555..0a672956768 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -52,7 +52,7 @@ pub mod point { 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); @@ -63,7 +63,7 @@ pub mod fn_calls_changed_method { 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(); @@ -74,7 +74,7 @@ pub mod fn_calls_another_method { 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 } } @@ -84,7 +84,7 @@ pub mod fn_make_struct { 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 } @@ -94,7 +94,7 @@ pub mod fn_read_field { 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; } diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs index 6e06e67b668..ca476b4d2db 100644 --- a/src/test/incremental/crate_hash_reorder.rs +++ b/src/test/incremental/crate_hash_reorder.rs @@ -7,9 +7,9 @@ // 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, diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 02c9a0c5798..11d999ab328 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -25,15 +25,24 @@ mod x { 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 } diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index d4511cee75b..d4201400f0f 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -55,12 +55,8 @@ mod change_callee_indirectly_function { #[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) } diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index c73c03ca14e..76bff3cad38 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -370,7 +370,7 @@ enum EnumChangeNameOfTypeParameter<S> { } #[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), @@ -386,7 +386,7 @@ enum EnumAddTypeParameter<S> { } #[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), @@ -402,7 +402,7 @@ enum EnumChangeNameOfLifetimeParameter<'a> { } #[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), @@ -418,7 +418,7 @@ enum EnumAddLifetimeParameter<'a> { } #[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), @@ -435,7 +435,7 @@ enum EnumAddLifetimeParameterBound<'a, 'b> { } #[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), @@ -450,7 +450,7 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[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), @@ -466,7 +466,7 @@ enum EnumAddTraitBound<S> { } #[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), @@ -482,7 +482,7 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { } #[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), @@ -499,7 +499,7 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[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), @@ -515,7 +515,7 @@ enum EnumAddTraitBoundWhere<S> { } #[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), diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 93e70d3792c..1160bc376c4 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -21,7 +21,7 @@ extern "C" { } #[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; @@ -34,7 +34,7 @@ extern "C" { } #[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; @@ -47,7 +47,7 @@ extern "C" { } #[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; @@ -60,7 +60,7 @@ extern "C" { } #[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; @@ -73,7 +73,7 @@ extern "C" { } #[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; @@ -86,7 +86,7 @@ extern "C" { } #[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; @@ -99,7 +99,7 @@ extern "C" { } #[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, ...); @@ -112,7 +112,7 @@ extern "C" { } #[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); @@ -125,7 +125,7 @@ extern "C" { } #[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); @@ -138,7 +138,7 @@ extern "C" { } #[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); @@ -153,7 +153,7 @@ extern "C" { } #[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" { @@ -170,7 +170,7 @@ mod indirectly_change_parameter_type { #[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); @@ -184,7 +184,7 @@ mod indirectly_change_return_type { #[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; diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index 7a8cbc3566e..49ee7a9cac0 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -20,10 +20,8 @@ fn change_simple_index(slice: &[u32]) -> u32 { } #[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] } @@ -37,10 +35,8 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] { } #[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] } @@ -54,10 +50,8 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] { } #[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] } @@ -71,10 +65,8 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { } #[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] } @@ -88,10 +80,8 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { } #[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] } @@ -105,10 +95,8 @@ fn change_mutability(slice: &mut [u32]) -> u32 { } #[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] } @@ -122,10 +110,8 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { } #[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] } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 70ce81bd473..284a95f1a68 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -103,7 +103,10 @@ impl Foo { #[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) { } } diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 1339a1e5bf2..0ce5aeaaf50 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -24,16 +24,8 @@ 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; @@ -41,16 +33,8 @@ 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; @@ -61,16 +45,8 @@ 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( @@ -84,16 +60,8 @@ 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 @@ -106,16 +74,8 @@ struct TupleStructAddField( 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); @@ -125,16 +85,8 @@ 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 { @@ -148,16 +100,8 @@ 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 } @@ -167,16 +111,8 @@ 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: () } @@ -188,16 +124,8 @@ struct RecordStructAddField { 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 } @@ -209,16 +137,8 @@ struct RecordStructFieldVisibility { 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); @@ -228,16 +148,8 @@ 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 @@ -247,16 +159,8 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>( 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) @@ -269,16 +173,8 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>( 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. @@ -293,16 +189,8 @@ struct AddTypeParameter<T1, T2>( 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 ); @@ -312,16 +200,8 @@ struct AddTypeParameterBound<T: Send>( 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; @@ -332,16 +212,8 @@ struct AddTypeParameterBoundWhereClause<T>( // 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; @@ -351,16 +223,8 @@ 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; @@ -373,16 +237,8 @@ mod tuple_struct_change_field_type_indirectly { #[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 ); @@ -396,16 +252,8 @@ mod record_struct_change_field_type_indirectly { #[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 } @@ -424,16 +272,8 @@ mod change_trait_bound_indirectly { #[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); } @@ -444,15 +284,7 @@ mod change_trait_bound_indirectly_in_where_clause { #[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; } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 4dab032e47f..a604ca5ca82 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -25,8 +25,8 @@ 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 { } @@ -36,8 +36,8 @@ 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 { } @@ -48,8 +48,8 @@ trait TraitAddMethod { } #[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(); } @@ -63,8 +63,8 @@ trait TraitChangeMethodName { } #[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(); } @@ -78,11 +78,11 @@ trait TraitAddReturnType { } #[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; } @@ -95,11 +95,11 @@ trait TraitChangeReturnType { } #[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; } @@ -112,11 +112,11 @@ trait TraitAddParameterToMethod { } #[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); } @@ -130,18 +130,16 @@ trait TraitChangeMethodParameterName { } #[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) {} } @@ -154,11 +152,11 @@ trait TraitChangeMethodParameterType { } #[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); } @@ -171,11 +169,11 @@ trait TraitChangeMethodParameterTypeRef { } #[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); } @@ -188,11 +186,11 @@ trait TraitChangeMethodParametersOrder { } #[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); } @@ -205,11 +203,11 @@ trait TraitAddMethodAutoImplementation { } #[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() { } } @@ -223,8 +221,8 @@ trait TraitChangeOrderOfMethods { } #[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(); @@ -239,11 +237,11 @@ trait TraitChangeModeSelfRefToMut { } #[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); } @@ -255,13 +253,11 @@ trait TraitChangeModeSelfOwnToMut: 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 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) {} } @@ -273,11 +269,11 @@ trait TraitChangeModeSelfOwnToRef { } #[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); } @@ -290,11 +286,11 @@ trait TraitAddUnsafeModifier { } #[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(); } @@ -307,11 +303,11 @@ trait TraitAddExternModifier { } #[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(); } @@ -324,11 +320,11 @@ trait TraitChangeExternCToRustIntrinsic { } #[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(); } @@ -341,11 +337,11 @@ trait TraitAddTypeParameterToMethod { } #[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>(); } @@ -358,11 +354,11 @@ trait TraitAddLifetimeParameterToMethod { } #[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>(); } @@ -379,11 +375,11 @@ trait TraitAddTraitBoundToMethodTypeParameter { } #[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>(); } @@ -396,11 +392,11 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { } #[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>(); } @@ -413,11 +409,14 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { } #[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); } @@ -430,11 +429,11 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { } #[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>(); } @@ -447,11 +446,11 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { } #[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>(); } @@ -464,11 +463,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { } #[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); } @@ -478,14 +480,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[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; @@ -506,11 +508,11 @@ trait TraitAddTraitBoundToAssociatedType { // 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(); @@ -527,11 +529,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'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 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(); @@ -548,11 +550,11 @@ trait TraitAddDefaultToAssociatedType { } #[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(); @@ -567,8 +569,8 @@ trait TraitAddAssociatedConstant { } #[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; @@ -586,15 +588,15 @@ trait TraitAddInitializerToAssociatedConstant { } #[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(); } @@ -609,15 +611,15 @@ trait TraitChangeTypeOfAssociatedConstant { } #[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(); } @@ -628,8 +630,8 @@ trait TraitChangeTypeOfAssociatedConstant { 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 { } @@ -639,8 +641,8 @@ 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 { } @@ -650,8 +652,8 @@ 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 { } @@ -661,16 +663,16 @@ 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 { } @@ -680,16 +682,16 @@ 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 { } @@ -699,16 +701,16 @@ 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 { } @@ -718,8 +720,8 @@ 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> { } @@ -729,8 +731,8 @@ 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> { } @@ -740,8 +742,8 @@ 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> { } @@ -751,8 +753,8 @@ 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> { } @@ -762,8 +764,8 @@ 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> { } @@ -773,8 +775,8 @@ 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> { } @@ -784,8 +786,8 @@ 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> { } @@ -795,8 +797,8 @@ 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> { } @@ -806,8 +808,8 @@ 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> { } @@ -817,8 +819,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer 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> { } @@ -828,8 +830,8 @@ 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> { } @@ -839,8 +841,8 @@ 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> { } @@ -855,8 +857,8 @@ struct ReferenceType1 {} 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 { } @@ -866,8 +868,8 @@ 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 { } @@ -877,8 +879,8 @@ 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 { } @@ -888,8 +890,8 @@ 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 { } @@ -899,8 +901,8 @@ 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 { } @@ -911,8 +913,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> 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 { } @@ -922,8 +924,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 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 { } @@ -933,8 +935,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe 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 { } @@ -945,11 +947,11 @@ mod change_return_type_of_method_indirectly_use { #[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; } } @@ -963,11 +965,11 @@ mod change_method_parameter_type_indirectly_by_use { #[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); } } @@ -981,11 +983,11 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[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); } } @@ -1000,11 +1002,11 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[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; } } @@ -1018,8 +1020,8 @@ mod change_method_type_parameter_bound_indirectly { #[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); } @@ -1035,8 +1037,8 @@ mod change_method_type_parameter_bound_indirectly_where { #[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); } diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index e9118da5a61..c9a3de1f6ae 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -30,18 +30,18 @@ impl ChangeMethodNameTrait for Foo { } #[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() { } } @@ -59,13 +59,11 @@ impl ChangeMethodBodyTrait for Foo { } #[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() { () } @@ -86,13 +84,11 @@ impl ChangeMethodBodyTraitInlined for Foo { } #[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!() @@ -117,11 +113,14 @@ pub trait ChangeMethodSelfnessTrait { } #[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) { () } @@ -145,11 +144,14 @@ pub trait RemoveMethodSelfnessTrait { } #[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() {} } @@ -171,11 +173,11 @@ pub trait ChangeMethodSelfmutnessTrait { } #[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) {} } @@ -197,8 +199,8 @@ pub trait ChangeItemKindTrait { } #[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 = (); } @@ -223,8 +225,8 @@ pub trait RemoveItemTrait { } #[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 = (); } @@ -248,8 +250,8 @@ pub trait AddItemTrait { } #[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() { } @@ -268,17 +270,17 @@ impl ChangeHasValueTrait for Foo { } #[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() { } } @@ -295,11 +297,11 @@ impl AddDefaultTrait for Foo { } #[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() { } } @@ -321,11 +323,11 @@ pub trait AddArgumentTrait { } #[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) { } } @@ -347,11 +349,11 @@ pub trait ChangeArgumentTypeTrait { } #[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) { } } @@ -370,11 +372,14 @@ impl AddTypeParameterToImpl<u32> for Bar<u32> { } #[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 } } @@ -391,11 +396,11 @@ impl ChangeSelfTypeOfImpl for u32 { } #[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 } } @@ -412,11 +417,11 @@ impl<T> AddLifetimeBoundToImplParameter for 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", 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 } } @@ -433,11 +438,11 @@ impl<T> AddTraitBoundToImplParameter for 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", 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 } } @@ -454,11 +459,11 @@ impl AddNoMangleToMethod for Foo { } #[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) { } } @@ -475,11 +480,11 @@ impl MakeMethodInline for Foo { } #[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 } } diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs index 4c60d7bd9d5..d5ec6e92bc0 100644 --- a/src/test/incremental/hello_world.rs +++ b/src/test/incremental/hello_world.rs @@ -21,7 +21,7 @@ mod x { mod y { use x; - #[rustc_clean(label="typeck", cfg="rpass2")] + #[rustc_clean(cfg="rpass2")] pub fn yyyy() { x::xxxx(); } @@ -30,7 +30,7 @@ mod y { mod z { use y; - #[rustc_clean(label="typeck", cfg="rpass2")] + #[rustc_clean(cfg="rpass2")] pub fn z() { y::yyyy(); } diff --git a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs index 91a9f63d39b..b31f60e972b 100644 --- a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs +++ b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs @@ -13,7 +13,7 @@ macro_rules! first_macro { } } -#[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, diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs index 6d7d446cb7c..5566506c039 100644 --- a/src/test/incremental/ich_method_call_trait_scope.rs +++ b/src/test/incremental/ich_method_call_trait_scope.rs @@ -26,16 +26,12 @@ mod mod3 { #[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 } diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs index 8df54467e5e..379c09575ed 100644 --- a/src/test/incremental/ich_nested_items.rs +++ b/src/test/incremental/ich_nested_items.rs @@ -8,14 +8,12 @@ #![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)] diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs index 1fb0f8aa84d..e6ab6bcebae 100644 --- a/src/test/incremental/ich_resolve_results.rs +++ b/src/test/incremental/ich_resolve_results.rs @@ -29,18 +29,14 @@ mod mod3 { #[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>(); } diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs new file mode 100644 index 00000000000..57cde5f7c6e --- /dev/null +++ b/src/test/incremental/link_order/auxiliary/my_lib.rs @@ -0,0 +1,3 @@ +// no-prefer-dynamic +//[cfail1] compile-flags: -lbar -lfoo --crate-type lib +//[cfail2] compile-flags: -lfoo -lbar --crate-type lib diff --git a/src/test/incremental/link_order/main.rs b/src/test/incremental/link_order/main.rs new file mode 100644 index 00000000000..d211c295bc4 --- /dev/null +++ b/src/test/incremental/link_order/main.rs @@ -0,0 +1,12 @@ +// 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() {} diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs index 73846712b59..639cfc918cb 100644 --- a/src/test/incremental/rlib_cross_crate/b.rs +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -12,15 +12,15 @@ 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'; } diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs index f18d2fdaf0a..e5f04e5dc58 100644 --- a/src/test/incremental/source_loc_macros.rs +++ b/src/test/incremental/source_loc_macros.rs @@ -7,26 +7,22 @@ #![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)] { @@ -38,8 +34,7 @@ fn line_different() { } } -#[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)] { diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs index 2927ddec4e5..70e2ea06b7e 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub struct SomeType { pub x: u32, pub y: i64, diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs index aa635077db8..1167cdb0a82 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub struct SomeOtherType { pub a: i32, pub b: u64, diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs index aff2be830ff..8506636e22b 100644 --- a/src/test/incremental/spans_significant_w_debuginfo.rs +++ b/src/test/incremental/spans_significant_w_debuginfo.rs @@ -12,6 +12,5 @@ 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() {} diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs index 37728af9516..a29b61ab153 100644 --- a/src/test/incremental/spans_significant_w_panic.rs +++ b/src/test/incremental/spans_significant_w_panic.rs @@ -13,7 +13,7 @@ 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; } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 2fc72529431..866f51d759e 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -18,8 +18,7 @@ pub mod x { } #[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"); } @@ -28,8 +27,7 @@ pub mod x { 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(); } @@ -38,8 +36,7 @@ pub mod y { 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(); } diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs index 4c29f196f67..720854f1605 100644 --- a/src/test/incremental/struct_add_field.rs +++ b/src/test/incremental/struct_add_field.rs @@ -21,17 +21,17 @@ pub struct 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' }; } diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index ee88fbdf592..7498d0305e0 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -24,7 +24,7 @@ pub struct Y { 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` @@ -32,13 +32,13 @@ pub fn use_X() -> u32 { //[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' }; } diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs index b60b4b311ee..37d2fba9901 100644 --- a/src/test/incremental/struct_change_field_type.rs +++ b/src/test/incremental/struct_change_field_type.rs @@ -24,19 +24,19 @@ pub struct Y { 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' }; } diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs index 0221d510eab..c78207bcb1a 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs @@ -8,18 +8,18 @@ extern crate a; 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' }; } diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs index 3ab90e966fb..de30c818cfe 100644 --- a/src/test/incremental/struct_change_nothing.rs +++ b/src/test/incremental/struct_change_nothing.rs @@ -24,19 +24,19 @@ pub struct Y { 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' }; } diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs index f6017b1b1c3..b97a87e0962 100644 --- a/src/test/incremental/struct_remove_field.rs +++ b/src/test/incremental/struct_remove_field.rs @@ -25,17 +25,17 @@ pub struct Y { 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' }; } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs index 05c926fdded..f6c2526841c 100644 --- a/src/test/incremental/type_alias_cross_crate/b.rs +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -6,15 +6,15 @@ 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'; } diff --git a/src/test/incremental/unchecked_dirty_clean.rs b/src/test/incremental/unchecked_dirty_clean.rs index 3bc8818aa6f..3c8692a302d 100644 --- a/src/test/incremental/unchecked_dirty_clean.rs +++ b/src/test/incremental/unchecked_dirty_clean.rs @@ -4,31 +4,31 @@ #![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, } diff --git a/src/test/mir-opt/bool_compare.opt1.InstCombine.diff b/src/test/mir-opt/bool_compare.opt1.InstCombine.diff new file mode 100644 index 00000000000..a14f64467a6 --- /dev/null +++ b/src/test/mir-opt/bool_compare.opt1.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt1` before InstCombine ++ // MIR for `opt1` after InstCombine + + fn opt1(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:2:9: 2:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:2:21: 2:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:9 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:3:8: 3:9 +- _2 = Ne(move _3, const true); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:3:16: 3:17 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34 + } + + bb1: { + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:3:20: 3:21 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34 + } + + bb2: { + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:3:31: 3:32 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:3:33: 3:34 + return; // scope 0 at $DIR/bool_compare.rs:4:2: 4:2 + } + } + diff --git a/src/test/mir-opt/bool_compare.opt2.InstCombine.diff b/src/test/mir-opt/bool_compare.opt2.InstCombine.diff new file mode 100644 index 00000000000..4e9c255ad62 --- /dev/null +++ b/src/test/mir-opt/bool_compare.opt2.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt2` before InstCombine ++ // MIR for `opt2` after InstCombine + + fn opt2(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:7:9: 7:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:7:21: 7:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:8:16: 8:17 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 +- _2 = Ne(const true, move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34 + } + + bb1: { + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:8:20: 8:21 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34 + } + + bb2: { + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:8:31: 8:32 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:8:33: 8:34 + return; // scope 0 at $DIR/bool_compare.rs:9:2: 9:2 + } + } + diff --git a/src/test/mir-opt/bool_compare.opt3.InstCombine.diff b/src/test/mir-opt/bool_compare.opt3.InstCombine.diff new file mode 100644 index 00000000000..2048c97a9e1 --- /dev/null +++ b/src/test/mir-opt/bool_compare.opt3.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt3` before InstCombine ++ // MIR for `opt3` after InstCombine + + fn opt3(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:12:9: 12:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:12:21: 12:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:9 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:13:8: 13:9 +- _2 = Eq(move _3, const false); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:13:17: 13:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35 + } + + bb1: { + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:13:21: 13:22 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35 + } + + bb2: { + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:13:32: 13:33 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:13:34: 13:35 + return; // scope 0 at $DIR/bool_compare.rs:14:2: 14:2 + } + } + diff --git a/src/test/mir-opt/bool_compare.opt4.InstCombine.diff b/src/test/mir-opt/bool_compare.opt4.InstCombine.diff new file mode 100644 index 00000000000..efcaa2766a9 --- /dev/null +++ b/src/test/mir-opt/bool_compare.opt4.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt4` before InstCombine ++ // MIR for `opt4` after InstCombine + + fn opt4(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/bool_compare.rs:17:9: 17:10 + let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:17:21: 17:24 + let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:18:17: 18:18 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 + _3 = _1; // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 +- _2 = Eq(const false, move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 ++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18 + StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18 + switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35 + } + + bb1: { + _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:18:21: 18:22 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35 + } + + bb2: { + _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:18:32: 18:33 + goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:18:34: 18:35 + return; // scope 0 at $DIR/bool_compare.rs:19:2: 19:2 + } + } + diff --git a/src/test/mir-opt/bool_compare.rs b/src/test/mir-opt/bool_compare.rs new file mode 100644 index 00000000000..3ff046325dc --- /dev/null +++ b/src/test/mir-opt/bool_compare.rs @@ -0,0 +1,26 @@ +// EMIT_MIR bool_compare.opt1.InstCombine.diff +fn opt1(x: bool) -> u32 { + if x != true { 0 } else { 1 } +} + +// EMIT_MIR bool_compare.opt2.InstCombine.diff +fn opt2(x: bool) -> u32 { + if true != x { 0 } else { 1 } +} + +// EMIT_MIR bool_compare.opt3.InstCombine.diff +fn opt3(x: bool) -> u32 { + if x == false { 0 } else { 1 } +} + +// EMIT_MIR bool_compare.opt4.InstCombine.diff +fn opt4(x: bool) -> u32 { + if false == x { 0 } else { 1 } +} + +fn main() { + opt1(false); + opt2(false); + opt3(false); + opt4(false); +} diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index 6da0460286b..d19229aabad 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -14,7 +14,7 @@ }, } */ -fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () { +fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6]) -> () { let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index 42b95b5c68c..642d9b3fb35 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}` before StateTransform -fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () +fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6], _2: ()) -> () yields () { let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 @@ -85,13 +85,13 @@ yields () bb8 (cleanup): { StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16 StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17 - goto -> bb10; // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1 + goto -> bb10; // scope 2 at no-location } bb9 (cleanup): { StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16 StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17 - goto -> bb10; // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1 + goto -> bb10; // scope 2 at no-location } bb10 (cleanup): { diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 990aa1ec087..539988cad24 100644 --- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -10,7 +10,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 @@ -27,7 +27,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 } bb0: { - _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 } @@ -43,7 +43,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 - discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 + discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 return; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18 } diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index fba88c83eb4..9035b46f4c6 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -13,13 +13,13 @@ } + scope 2 (inlined g) { // at $DIR/inline-generator.rs:9:28: 9:31 + } -+ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32 ++ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32 + debug pointer => _3; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32 -+ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32 ++ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32 + scope 4 { -+ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32 ++ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32 + debug pointer => _5; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32 -+ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32 ++ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32 + } + } + } @@ -58,7 +58,7 @@ + _5 = move _3; // scope 4 at $DIR/inline-generator.rs:9:14: 9:32 + StorageLive(_6); // scope 5 at $DIR/inline-generator.rs:9:14: 9:32 + _6 = move _5; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32 -+ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32 ++ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32 + StorageDead(_6); // scope 5 at $DIR/inline-generator.rs:9:14: 9:32 + StorageDead(_5); // scope 4 at $DIR/inline-generator.rs:9:14: 9:32 StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:9:31: 9:32 @@ -71,7 +71,7 @@ + StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 + StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46 -+ _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 ++ _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 } @@ -115,7 +115,7 @@ + StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 -+ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 ++ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39 + } + @@ -125,7 +125,7 @@ + StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 -+ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 ++ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46 + goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41 + } + diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir index 99c7ac8d5b7..db88f77bb63 100644 --- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir +++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir @@ -43,7 +43,7 @@ fn main() -> () { _6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18 FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14 StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6 - goto -> bb3; // scope 0 at $DIR/loop_test.rs:1:1: 1:1 + goto -> bb3; // scope 0 at no-location } bb5 (cleanup): { diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 3395cbfbdfb..feb25035ee0 100644 --- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -94,8 +94,8 @@ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60 StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 -- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1 -+ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1 +- goto -> bb23; // scope 0 at no-location ++ goto -> bb20; // scope 0 at no-location } - bb10: { @@ -150,8 +150,8 @@ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60 StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73 StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78 -- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1 -+ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1 +- goto -> bb23; // scope 0 at no-location ++ goto -> bb20; // scope 0 at no-location } - bb15: { diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index dd8a9251042..80024124dc5 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -32,6 +32,10 @@ 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 @@ -61,19 +65,15 @@ - 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 @@ -85,7 +85,7 @@ 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 @@ -111,5 +111,12 @@ - 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 + } } diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir index b91aae054de..bf9c2d138a0 100644 --- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -40,7 +40,7 @@ fn while_loop(_1: bool) -> () { bb4: { StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10 - goto -> bb6; // scope 0 at $DIR/while-storage.rs:1:1: 1:1 + goto -> bb6; // scope 0 at no-location } bb5: { diff --git a/src/test/pretty/anonymous-types.rs b/src/test/pretty/anonymous-types.rs new file mode 100644 index 00000000000..5ff452e8e43 --- /dev/null +++ b/src/test/pretty/anonymous-types.rs @@ -0,0 +1,24 @@ +// 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() { } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt index 322f5681b3f..dc06a485a8f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt @@ -12,6 +12,7 @@ 12| 1| if b { 13| 1| println!("non_async_func println in block"); 14| 1| } + ^0 15| 1|} 16| | 17| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt index 656a2659775..2d8a98a5d0c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt @@ -5,6 +5,7 @@ 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,6 +25,7 @@ 24| 1| if true { 25| 1| countdown = 10; 26| 1| } + ^0 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; @@ -42,6 +44,7 @@ 41| 1| if true { 42| 1| countdown = 10; 43| 1| } + ^0 44| | 45| 1| if countdown > 7 { 46| 1| countdown -= 4; @@ -54,13 +57,14 @@ 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 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt index 1b6bb9ff889..7ae0e978808 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -9,7 +9,7 @@ 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| |//! @@ -84,7 +84,7 @@ 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| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt index fab5be41901..fe6a9e93cbf 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt @@ -19,11 +19,11 @@ 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: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt new file mode 100644 index 00000000000..0fb3808ff2e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt @@ -0,0 +1,32 @@ + 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|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 7b38ffb87cb..8569513e842 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -11,16 +11,16 @@ 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| | 15| |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display { @@ -52,15 +52,15 @@ 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: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 81d5c7d9034..5d572db7cc6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -9,23 +9,23 @@ 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| } @@ -36,21 +36,21 @@ 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(()) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt index 5adeef7d085..2d4c57f451a 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -1,6 +1,6 @@ 1| 1|fn main() { 2| 1| if false { - 3| | loop {} + 3| 0| loop {} 4| 1| } 5| 1|} diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index 8a2a0b53e58..057599d1b47 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -53,8 +53,8 @@ fn main() { } 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 { diff --git a/src/test/run-make-fulldeps/coverage/generator.rs b/src/test/run-make-fulldeps/coverage/generator.rs new file mode 100644 index 00000000000..4319991021e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/generator.rs @@ -0,0 +1,30 @@ +#![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"), + } +} diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs index cbeda35d3b8..18b38868496 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make-fulldeps/coverage/generics.rs @@ -30,11 +30,11 @@ fn main() -> Result<(),u8> { 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 }; diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs index 4d9bbad3367..7116ce47f4b 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs @@ -12,7 +12,7 @@ impl std::fmt::Debug for DebugTest { while true { } } - write!(f, "error")?; + write!(f, "cool")?; } else { } @@ -21,7 +21,7 @@ impl std::fmt::Debug for DebugTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } else { } } @@ -38,7 +38,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } for i in 0..10 { if false { @@ -46,7 +46,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } } Ok(()) diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index a9e99d3c10e..443e2df357f 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![deny(warnings)] extern crate rustc_codegen_ssa; extern crate rustc_errors; @@ -15,44 +16,28 @@ use rustc_codegen_ssa::back::linker::LinkerInfo; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::MetadataRef; use rustc_errors::ErrorReported; -use rustc_middle::dep_graph::DepGraph; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; -use rustc_middle::ty::query::Providers; +use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_target::spec::Target; use std::any::Any; -use std::path::Path; struct TheBackend; impl CodegenBackend for TheBackend { - fn metadata_loader(&self) -> Box<MetadataLoaderDyn> { - Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader) - } - - fn provide(&self, providers: &mut Providers) {} - fn provide_extern(&self, providers: &mut Providers) {} - fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, _need_metadata_module: bool, ) -> Box<dyn Any> { - use rustc_hir::def_id::LOCAL_CRATE; - Box::new(CodegenResults { - crate_name: tcx.crate_name(LOCAL_CRATE), modules: vec![], allocator_module: None, metadata_module: None, metadata, - windows_subsystem: None, linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()), crate_info: CrateInfo::new(tcx), }) @@ -77,7 +62,7 @@ impl CodegenBackend for TheBackend { ) -> Result<(), ErrorReported> { use rustc_session::{config::CrateType, output::out_filename}; use std::io::Write; - let crate_name = codegen_results.crate_name; + let crate_name = codegen_results.crate_info.local_crate_name; for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::Rlib { sess.fatal(&format!("Crate type is {:?}", crate_type)); diff --git a/src/test/run-make-fulldeps/include_bytes_deps/main.rs b/src/test/run-make-fulldeps/include_bytes_deps/main.rs index 00ad0eb8d50..2fd55699d44 100644 --- a/src/test/run-make-fulldeps/include_bytes_deps/main.rs +++ b/src/test/run-make-fulldeps/include_bytes_deps/main.rs @@ -1,6 +1,4 @@ -#![feature(external_doc)] - -#[doc(include="input.md")] +#[doc = include_str!("input.md")] pub struct SomeStruct; pub fn main() { diff --git a/src/test/run-make-fulldeps/issue-47551/Makefile b/src/test/run-make-fulldeps/issue-47551/Makefile new file mode 100644 index 00000000000..f4495e6b671 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-47551/Makefile @@ -0,0 +1,9 @@ +# 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' diff --git a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs new file mode 100644 index 00000000000..2f740dc4fac --- /dev/null +++ b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs @@ -0,0 +1,23 @@ +// 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]); +} diff --git a/src/test/run-make-fulldeps/link-dedup/Makefile b/src/test/run-make-fulldeps/link-dedup/Makefile new file mode 100644 index 00000000000..4e7ce0f02d4 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/Makefile @@ -0,0 +1,12 @@ +# 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"' diff --git a/src/test/run-make-fulldeps/link-dedup/depa.rs b/src/test/run-make-fulldeps/link-dedup/depa.rs new file mode 100644 index 00000000000..e48ffd6413c --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depa.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +#[link(name = "testa")] +extern "C" {} + +#[link(name = "testa")] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/depb.rs b/src/test/run-make-fulldeps/link-dedup/depb.rs new file mode 100644 index 00000000000..b1be21fe005 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depb.rs @@ -0,0 +1,8 @@ +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "testb", cfg(foo))] +extern "C" {} + +#[link(name = "testb", cfg(bar))] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/depc.rs b/src/test/run-make-fulldeps/link-dedup/depc.rs new file mode 100644 index 00000000000..8dcb3dee5a2 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depc.rs @@ -0,0 +1,4 @@ +#![crate_type = "rlib"] + +#[link(name = "testa")] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/empty.rs b/src/test/run-make-fulldeps/link-dedup/empty.rs new file mode 100644 index 00000000000..e00ae18f4af --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/empty.rs @@ -0,0 +1,5 @@ +extern crate depa; +extern crate depb; +extern crate depc; + +fn main() {} diff --git a/src/test/run-make-fulldeps/print-unversioned-files/Makefile b/src/test/run-make-fulldeps/print-unversioned-files/Makefile deleted file mode 100644 index e368f61cddf..00000000000 --- a/src/test/run-make-fulldeps/print-unversioned-files/Makefile +++ /dev/null @@ -1,4 +0,0 @@ --include ../tools.mk - -all: - $(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt diff --git a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt deleted file mode 100644 index 4b20cd5d745..00000000000 --- a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt +++ /dev/null @@ -1,16 +0,0 @@ -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 diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile new file mode 100644 index 00000000000..6d0bc4186f2 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile @@ -0,0 +1,9 @@ +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 diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs new file mode 100644 index 00000000000..da27b7f3463 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs @@ -0,0 +1,2 @@ +#![feature(no_core)] +#![no_core] diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs new file mode 100644 index 00000000000..12aa0822084 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs @@ -0,0 +1,3 @@ +#![feature(no_core)] +#![no_core] +extern crate dummy_core; diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json new file mode 100644 index 00000000000..58e924a9895 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json @@ -0,0 +1,39 @@ +{ + "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" +} diff --git a/src/test/run-make-fulldeps/save-analysis/foo.rs b/src/test/run-make-fulldeps/save-analysis/foo.rs index 483eeed0b39..dd70675032f 100644 --- a/src/test/run-make-fulldeps/save-analysis/foo.rs +++ b/src/test/run-make-fulldeps/save-analysis/foo.rs @@ -2,7 +2,6 @@ #![feature(box_syntax)] #![feature(rustc_private)] #![feature(associated_type_defaults)] -#![feature(external_doc)] extern crate rustc_graphviz; // A simple rust project @@ -454,9 +453,9 @@ impl Iterator for SilenceGenerator { } } +#[doc = include_str!("extra-docs.md")] +struct StructWithDocs; + trait Foo { type Bar = FrameBuffer; } - -#[doc(include = "extra-docs.md")] -struct StructWithDocs; diff --git a/src/test/run-make/emit-named-files/Makefile b/src/test/run-make/emit-named-files/Makefile new file mode 100644 index 00000000000..03eb83b97e3 --- /dev/null +++ b/src/test/run-make/emit-named-files/Makefile @@ -0,0 +1,33 @@ +-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) diff --git a/src/test/run-make/emit-named-files/foo.rs b/src/test/run-make/emit-named-files/foo.rs new file mode 100644 index 00000000000..c1bfaa6cab5 --- /dev/null +++ b/src/test/run-make/emit-named-files/foo.rs @@ -0,0 +1 @@ +#![crate_type = "rlib"] diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile new file mode 100644 index 00000000000..0461bb926e7 --- /dev/null +++ b/src/test/run-make/incremental-session-fail/Makefile @@ -0,0 +1,14 @@ +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) diff --git a/src/test/run-make/incremental-session-fail/foo.rs b/src/test/run-make/incremental-session-fail/foo.rs new file mode 100644 index 00000000000..d11c69f812a --- /dev/null +++ b/src/test/run-make/incremental-session-fail/foo.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/run-make/issue-71519/Makefile b/src/test/run-make/issue-71519/Makefile new file mode 100644 index 00000000000..636665ec1d0 --- /dev/null +++ b/src/test/run-make/issue-71519/Makefile @@ -0,0 +1,6 @@ +-include ../../run-make-fulldeps/tools.mk + +# needs-rust-lld +all: + RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt + $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/src/test/run-make/issue-71519/main.rs b/src/test/run-make/issue-71519/main.rs new file mode 100644 index 00000000000..f8d09e89753 --- /dev/null +++ b/src/test/run-make/issue-71519/main.rs @@ -0,0 +1,4 @@ +// test linking using cc with rust-lld injected into search path as ld +// see rust-lang/rust#71519 for more info + +fn main() {} diff --git a/src/test/run-make/raw-dylib/Makefile b/src/test/run-make/raw-dylib/Makefile new file mode 100644 index 00000000000..7ce46fd9331 --- /dev/null +++ b/src/test/run-make/raw-dylib/Makefile @@ -0,0 +1,21 @@ +# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc + +# only-windows +# only-msvc + +-include ../../run-make-fulldeps/tools.mk + +all: + $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) + $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) + $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll + $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" + "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/output.txt output.txt +else + $(DIFF) output.txt "$(TMPDIR)"/output.txt +endif diff --git a/src/test/run-make/raw-dylib/driver.rs b/src/test/run-make/raw-dylib/driver.rs new file mode 100644 index 00000000000..4059ede11fc --- /dev/null +++ b/src/test/run-make/raw-dylib/driver.rs @@ -0,0 +1,5 @@ +extern crate raw_dylib_test; + +fn main() { + raw_dylib_test::library_function(); +} diff --git a/src/test/run-make/raw-dylib/extern_1.c b/src/test/run-make/raw-dylib/extern_1.c new file mode 100644 index 00000000000..72737c086eb --- /dev/null +++ b/src/test/run-make/raw-dylib/extern_1.c @@ -0,0 +1,16 @@ +#include <stdio.h> + +__declspec(dllexport) void extern_fn_1() { + printf("extern_fn_1\n"); + fflush(stdout); +} + +__declspec(dllexport) void extern_fn_2() { + printf("extern_fn_2; didn't get the rename\n"); + fflush(stdout); +} + +__declspec(dllexport) void extern_fn_with_long_name() { + printf("extern_fn_with_long_name; got the rename\n"); + fflush(stdout); +} diff --git a/src/test/run-make/raw-dylib/extern_2.c b/src/test/run-make/raw-dylib/extern_2.c new file mode 100644 index 00000000000..ae87fc3f821 --- /dev/null +++ b/src/test/run-make/raw-dylib/extern_2.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +__declspec(dllexport) void extern_fn_3() { + printf("extern_fn_3\n"); + fflush(stdout); +} diff --git a/src/test/run-make/raw-dylib/lib.rs b/src/test/run-make/raw-dylib/lib.rs new file mode 100644 index 00000000000..d8e6301f38e --- /dev/null +++ b/src/test/run-make/raw-dylib/lib.rs @@ -0,0 +1,22 @@ +#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)] + +#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")] +extern { + fn extern_fn_1(); +} + +#[link(name = "extern_2", kind = "raw-dylib")] +extern { + fn extern_fn_3(); +} + +pub fn library_function() { + #[link(name = "extern_1", kind = "raw-dylib")] + extern { fn extern_fn_2(); } + + unsafe { + extern_fn_1(); + extern_fn_2(); + extern_fn_3(); + } +} diff --git a/src/test/run-make/raw-dylib/output.txt b/src/test/run-make/raw-dylib/output.txt new file mode 100644 index 00000000000..7800cba1872 --- /dev/null +++ b/src/test/run-make/raw-dylib/output.txt @@ -0,0 +1,3 @@ +extern_fn_1 +extern_fn_2; didn't get the rename +extern_fn_3 diff --git a/src/test/run-make/unstable-flag-required/Makefile b/src/test/run-make/unstable-flag-required/Makefile index b8769d5f690..aa20d6aa4bf 100644 --- a/src/test/run-make/unstable-flag-required/Makefile +++ b/src/test/run-make/unstable-flag-required/Makefile @@ -2,3 +2,4 @@ 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 diff --git a/src/test/run-make/unstable-flag-required/force-warns.stderr b/src/test/run-make/unstable-flag-required/force-warns.stderr new file mode 100644 index 00000000000..e0936196a11 --- /dev/null +++ b/src/test/run-make/unstable-flag-required/force-warns.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints` + diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml new file mode 100644 index 00000000000..d8ad6c2e3f5 --- /dev/null +++ b/src/test/rustdoc-gui/font-weight.goml @@ -0,0 +1,7 @@ +goto: file://|DOC_PATH|/lib2/struct.Foo.html +// This test checks that the font weight is correctly applied. +assert: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"}) +assert: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"}) +assert: ("#method\.a_method > code", {"font-weight": "600"}) +assert: ("#associatedtype\.X > code", {"font-weight": "600"}) +assert: ("#associatedconstant\.Y > code", {"font-weight": "600"}) diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml new file mode 100644 index 00000000000..25a01512159 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-colors.goml @@ -0,0 +1,14 @@ +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)"}) diff --git a/src/test/rustdoc-gui/search-result-description.goml b/src/test/rustdoc-gui/search-result-description.goml new file mode 100644 index 00000000000..a50d03cf489 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-description.goml @@ -0,0 +1,5 @@ +// This test is to ensure that the codeblocks are correctly rendered in the search results. +goto: file://|DOC_PATH|/test_docs/index.html?search=some_more_function +// Waiting for the search results to appear... +wait-for: "#titles" +assert: (".search-results .desc code", "format!") diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml new file mode 100644 index 00000000000..96d15c624f1 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -0,0 +1,12 @@ +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"}) diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml new file mode 100644 index 00000000000..e7612d66371 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-keyword.goml @@ -0,0 +1,10 @@ +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "CookieMonster") +// Waiting for the search results to appear... +wait-for: "#titles" +// Note: The two next assert commands could be merged as one but readability would be +// less good. +// +// Checking that the CSS is displaying " (keyword)" in italic. +assert: (".result-name span.keyword > i", "(keyword)") +assert: (".result-name span.keyword", "CookieMonster (keyword)") diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml new file mode 100644 index 00000000000..e0e6d19cace --- /dev/null +++ b/src/test/rustdoc-gui/sidebar.goml @@ -0,0 +1,60 @@ +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)", "Type Definitions") +assert: (".sidebar-elems > .items > ul > li:nth-child(7)", "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)", "Structs") +assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits") +assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions") +assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions") +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") diff --git a/src/test/rustdoc-gui/src/lib.rs b/src/test/rustdoc-gui/src/lib.rs index eeba3e3f907..5141b6d1920 100644 --- a/src/test/rustdoc-gui/src/lib.rs +++ b/src/test/rustdoc-gui/src/lib.rs @@ -2,6 +2,7 @@ //! documentation generated so we can test each different features. #![crate_name = "test_docs"] +#![feature(doc_keyword)] use std::fmt; @@ -35,6 +36,7 @@ impl Foo { } /// Just a normal enum. +#[doc(alias = "ThisIsAnAlias")] pub enum WhoLetTheDogOut { /// Woof! Woof, @@ -91,3 +93,9 @@ pub fn check_list_code_block() {} pub enum AnEnum { WithVariants { and: usize, sub: usize, variants: usize }, } + +#[doc(keyword = "CookieMonster")] +pub mod keyword {} + +/// Just some type alias. +pub type SomeType = u32; diff --git a/src/test/rustdoc-gui/src/lib2.rs b/src/test/rustdoc-gui/src/lib2.rs new file mode 100644 index 00000000000..6fa1b36b29b --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2.rs @@ -0,0 +1,31 @@ +pub mod module { + pub mod sub_module { + pub mod sub_sub_module { + pub fn foo() {} + } + pub fn bar() {} + } + pub fn whatever() {} +} + +pub fn foobar() {} + +pub type Alias = u32; + +pub struct Foo { + pub x: Alias, +} + +impl Foo { + pub fn a_method(&self) {} +} + +pub trait Trait { + type X; + const Y: u32; +} + +impl Trait for Foo { + type X = u32; + const Y: u32 = 0; +} diff --git a/src/test/rustdoc-gui/type-weight.rs b/src/test/rustdoc-gui/type-weight.rs new file mode 100644 index 00000000000..8b6518e7f31 --- /dev/null +++ b/src/test/rustdoc-gui/type-weight.rs @@ -0,0 +1,2 @@ +goto: file://|DOC_PATH|/test_docs/type.SomeType.html +assert-all: (".top-block .docblock p", {"font-weight": "400"}) diff --git a/src/test/rustdoc-ui/check.rs b/src/test/rustdoc-ui/check.rs index 65a56e03d9d..2b44ba24b44 100644 --- a/src/test/rustdoc-ui/check.rs +++ b/src/test/rustdoc-ui/check.rs @@ -1,5 +1,6 @@ // 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 diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr index 2e1fc1eca4d..8c9e70e57fe 100644 --- a/src/test/rustdoc-ui/check.stderr +++ b/src/test/rustdoc-ui/check.stderr @@ -1,5 +1,5 @@ warning: missing documentation for the crate - --> $DIR/check.rs:4:1 + --> $DIR/check.rs:5:1 | LL | / #![warn(missing_docs)] LL | | @@ -10,13 +10,13 @@ LL | | pub fn foo() {} | |_______________^ | 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() {} | ^^^^^^^^^^^^ @@ -24,16 +24,16 @@ 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 | | @@ -44,14 +44,14 @@ LL | | pub fn foo() {} | |_______________^ | 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() {} | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/deref-recursive-cycle.rs b/src/test/rustdoc-ui/deref-recursive-cycle.rs deleted file mode 100644 index 4cb518cbbbd..00000000000 --- a/src/test/rustdoc-ui/deref-recursive-cycle.rs +++ /dev/null @@ -1,17 +0,0 @@ -// check-pass -// #26207: Ensure `Deref` cycles are properly handled without errors. - -#[derive(Copy, Clone)] -struct S; - -impl std::ops::Deref for S { - type Target = S; - - fn deref(&self) -> &S { - self - } -} - -fn main() { - let s: S = *******S; -} diff --git a/src/test/rustdoc-ui/doc-include-suggestion.rs b/src/test/rustdoc-ui/doc-include-suggestion.rs new file mode 100644 index 00000000000..0c010073551 --- /dev/null +++ b/src/test/rustdoc-ui/doc-include-suggestion.rs @@ -0,0 +1,10 @@ +// 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; diff --git a/src/test/rustdoc-ui/doc-include-suggestion.stderr b/src/test/rustdoc-ui/doc-include-suggestion.stderr new file mode 100644 index 00000000000..870b7efa2ac --- /dev/null +++ b/src/test/rustdoc-ui/doc-include-suggestion.stderr @@ -0,0 +1,12 @@ +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 + diff --git a/src/test/rustdoc-ui/doc-spotlight.fixed b/src/test/rustdoc-ui/doc-spotlight.fixed index 94b69a99879..4b58778eacd 100644 --- a/src/test/rustdoc-ui/doc-spotlight.fixed +++ b/src/test/rustdoc-ui/doc-spotlight.fixed @@ -1,9 +1,8 @@ -// 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 {} diff --git a/src/test/rustdoc-ui/doc-spotlight.rs b/src/test/rustdoc-ui/doc-spotlight.rs index cc5f159a809..16e38724580 100644 --- a/src/test/rustdoc-ui/doc-spotlight.rs +++ b/src/test/rustdoc-ui/doc-spotlight.rs @@ -1,9 +1,8 @@ -// 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 {} diff --git a/src/test/rustdoc-ui/doc-spotlight.stderr b/src/test/rustdoc-ui/doc-spotlight.stderr index e5fa6293f3d..8e7831139a8 100644 --- a/src/test/rustdoc-ui/doc-spotlight.stderr +++ b/src/test/rustdoc-ui/doc-spotlight.stderr @@ -1,14 +1,19 @@ -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 diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout index b8bb5ccb403..af3a90a7410 100644 --- a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout +++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) ... FAILED +test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED failures: diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout index 7367a7d6519..bacbb47b5f9 100644 --- a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) ... FAILED +test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED failures: diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs index 417618c7458..9465e8e7ab9 100644 --- a/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs +++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.rs @@ -1,3 +1,4 @@ +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" #![deny(warnings)] //! Email me at <hello@localhost>. diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr index f287f87408c..1b07828fc6e 100644 --- a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr +++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr @@ -1,16 +1,16 @@ 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 diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs index 925fc515a3e..0aa1e5a415a 100644 --- a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs @@ -1,3 +1,4 @@ +// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" #![deny(warnings)] //! Linking to [foo@banana] and [`bar@banana!()`]. diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr index 94d6d461651..d280e6497e0 100644 --- a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -1,56 +1,56 @@ 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 diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout index 1dd19f46827..d2b1cd1d550 100644 --- a/src/test/rustdoc-ui/issue-80992.stdout +++ b/src/test/rustdoc-ui/issue-80992.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/issue-80992.rs - test (line 7) ... ok +test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs index 3939ec6827a..a186410acf4 100644 --- a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs @@ -1,4 +1,5 @@ // 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 diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr index 55ead1a55cf..1a1f8085a1b 100644 --- a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr @@ -1,12 +1,12 @@ 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 diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout index d92f5da8335..02f28aaf60d 100644 --- a/src/test/rustdoc-ui/no-run-flag.stdout +++ b/src/test/rustdoc-ui/no-run-flag.stdout @@ -1,12 +1,12 @@ running 7 tests -test $DIR/no-run-flag.rs - f (line 11) ... ok +test $DIR/no-run-flag.rs - f (line 11) - compile ... ok test $DIR/no-run-flag.rs - f (line 14) ... ignored -test $DIR/no-run-flag.rs - f (line 17) ... ok -test $DIR/no-run-flag.rs - f (line 23) ... ok -test $DIR/no-run-flag.rs - f (line 28) ... ok -test $DIR/no-run-flag.rs - f (line 32) ... ok -test $DIR/no-run-flag.rs - f (line 8) ... ok +test $DIR/no-run-flag.rs - f (line 17) - compile ... ok +test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok +test $DIR/no-run-flag.rs - f (line 28) - compile ... ok +test $DIR/no-run-flag.rs - f (line 32) - compile ... ok +test $DIR/no-run-flag.rs - f (line 8) - compile ... ok test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/test/rustdoc-ui/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs index 78431c0e80b..0d432c1e699 100644 --- a/src/test/rustdoc-ui/run-directory.rs +++ b/src/test/rustdoc-ui/run-directory.rs @@ -2,8 +2,8 @@ // revisions: correct incorrect // check-pass -// [correct]compile-flags:--test --test-run-directory={{src-base}} -// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage +// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options +// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" diff --git a/src/test/rustdoc-ui/test-type.rs b/src/test/rustdoc-ui/test-type.rs new file mode 100644 index 00000000000..882da5c2503 --- /dev/null +++ b/src/test/rustdoc-ui/test-type.rs @@ -0,0 +1,26 @@ +// compile-flags: --test --test-args=--test-threads=1 +// check-pass +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// let a = true; +/// ``` +/// ```should_panic +/// panic!() +/// ``` +/// ```ignore (incomplete-code) +/// fn foo() { +/// ``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +/// fails to compile +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` + +pub fn f() {} diff --git a/src/test/rustdoc-ui/test-type.stdout b/src/test/rustdoc-ui/test-type.stdout new file mode 100644 index 00000000000..a66fd240d34 --- /dev/null +++ b/src/test/rustdoc-ui/test-type.stdout @@ -0,0 +1,10 @@ + +running 5 tests +test $DIR/test-type.rs - f (line 12) ... ignored +test $DIR/test-type.rs - f (line 15) - compile ... ok +test $DIR/test-type.rs - f (line 21) - compile fail ... ok +test $DIR/test-type.rs - f (line 6) ... ok +test $DIR/test-type.rs - f (line 9) ... ok + +test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc-ui/wasm-safe.rs b/src/test/rustdoc-ui/wasm-safe.rs new file mode 100644 index 00000000000..ba971342b46 --- /dev/null +++ b/src/test/rustdoc-ui/wasm-safe.rs @@ -0,0 +1,5 @@ +// check-pass + +#[cfg(any(target_arch = "wasm32", doc))] +#[target_feature(enable = "simd128")] +pub fn foo() {} diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index 7bfa922185b..a3dd166e651 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -88,14 +88,12 @@ impl Qux for Bar { /// 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." } diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index 4b66b5271c5..9f95d9a994b 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } 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) {} } diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs index 56e0770ab5c..01ea09a9461 100644 --- a/src/test/rustdoc/auto_aliases.rs +++ b/src/test/rustdoc/auto_aliases.rs @@ -1,6 +1,6 @@ #![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 {} diff --git a/src/test/rustdoc/auxiliary/external-cross-doc.md b/src/test/rustdoc/auxiliary/external-cross-doc.md index 8b4e6edc699..d3c85326559 100644 --- a/src/test/rustdoc/auxiliary/external-cross-doc.md +++ b/src/test/rustdoc/auxiliary/external-cross-doc.md @@ -1,4 +1,4 @@ # 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. diff --git a/src/test/rustdoc/auxiliary/external-cross.rs b/src/test/rustdoc/auxiliary/external-cross.rs index 473d4ec99f0..5de63cdabc6 100644 --- a/src/test/rustdoc/auxiliary/external-cross.rs +++ b/src/test/rustdoc/auxiliary/external-cross.rs @@ -1,5 +1,3 @@ -#![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; diff --git a/src/test/rustdoc/auxiliary/external-doc.md b/src/test/rustdoc/auxiliary/external-doc.md index 38478c1635a..babde0a05ad 100644 --- a/src/test/rustdoc/auxiliary/external-doc.md +++ b/src/test/rustdoc/auxiliary/external-doc.md @@ -1,3 +1,3 @@ # 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. diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs index f247ee637b9..6f0c15cb5ac 100644 --- a/src/test/rustdoc/blanket-reexport-item.rs +++ b/src/test/rustdoc/blanket-reexport-item.rs @@ -1,6 +1,6 @@ #![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 {} diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index fb5c8517f6c..2761f92ef57 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -38,12 +38,12 @@ pub const unsafe fn bar_not_gated() -> u32 { 42 } 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")] diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs index 9ea7343e075..28eba849ace 100644 --- a/src/test/rustdoc/const-fn.rs +++ b/src/test/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ pub const fn bar() -> usize { } // @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 { diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs index 77432ba1539..8f412aa8c40 100644 --- a/src/test/rustdoc/const-generics/add-impl.rs +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> { 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; diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs new file mode 100644 index 00000000000..efe35bf7aa4 --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] +#![feature(const_generics_defaults)] + +// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \ +// 'pub struct Foo<const M: usize = 10_usize, const N: usize = M, T = i32>(_);' +pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T); diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs index 60d96770f7e..626a9e2b210 100644 --- a/src/test/rustdoc/const-generics/const-generic-slice.rs +++ b/src/test/rustdoc/const-generics/const-generic-slice.rs @@ -6,7 +6,7 @@ pub trait Array { } // @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; } diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs index 21bf216c304..7c4c70432c7 100644 --- a/src/test/rustdoc/const-generics/const-generics-docs.rs +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>; // @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; @@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> { } } -// @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>' diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs index 04fb3395333..e4e504dd83b 100644 --- a/src/test/rustdoc/const-generics/const-impl.rs +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -9,20 +9,20 @@ pub enum Order { } // @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() } @@ -31,7 +31,7 @@ impl <T> VSet<T, {Order::Unsorted}> { 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() {} } diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs deleted file mode 100644 index 459a30060c6..00000000000 --- a/src/test/rustdoc/deref-recursive-pathbuf.rs +++ /dev/null @@ -1,24 +0,0 @@ -// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing -// levels and across multiple crates. - -// @has 'foo/struct.Foo.html' -// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>' -// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)' -// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>' -// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)' -// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path' -// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists' - -#![crate_name = "foo"] - -use std::ops::Deref; -use std::path::PathBuf; - -pub struct Foo(PathBuf); - -impl Deref for Foo { - type Target = PathBuf; - fn deref(&self) -> &PathBuf { &self.0 } -} diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs deleted file mode 100644 index b96b5397ad7..00000000000 --- a/src/test/rustdoc/deref-recursive.rs +++ /dev/null @@ -1,40 +0,0 @@ -// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing -// levels if needed. - -// @has 'foo/struct.Foo.html' -// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>' -// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)' -// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>' -// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)' -// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar' -// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz' - -#![crate_name = "foo"] - -use std::ops::Deref; - -pub struct Foo(Bar); -pub struct Bar(Baz); -pub struct Baz; - -impl Deref for Foo { - type Target = Bar; - fn deref(&self) -> &Bar { &self.0 } -} - -impl Deref for Bar { - type Target = Baz; - fn deref(&self) -> &Baz { &self.0 } -} - -impl Bar { - /// This appears under `Foo` methods - pub fn bar(&self) {} -} - -impl Baz { - /// This should also appear in `Foo` methods when recursing - pub fn baz(&self) {} -} diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs index 47009559e6f..3fc48b46d74 100644 --- a/src/test/rustdoc/deref-typedef.rs +++ b/src/test/rustdoc/deref-typedef.rs @@ -1,12 +1,12 @@ #![crate_name = "foo"] // @has 'foo/struct.Bar.html' -// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>' +// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>' // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)' // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)' // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)' // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)' -// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>' +// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>' // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a' // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b' // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c' diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs index 4d5c9f83e1e..4f15418650c 100644 --- a/src/test/rustdoc/doc-assoc-item.rs +++ b/src/test/rustdoc/doc-assoc-item.rs @@ -8,7 +8,7 @@ pub trait Bar { 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 { diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index 1e644bb9739..15c3444606c 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -1,8 +1,8 @@ // @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 diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs index 86dec32e625..2eed1cc9d74 100644 --- a/src/test/rustdoc/empty-impls.rs +++ b/src/test/rustdoc/empty-impls.rs @@ -1,19 +1,19 @@ #![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) {} } diff --git a/src/test/rustdoc/ensure-src-link.rs b/src/test/rustdoc/ensure-src-link.rs index b7e7b11d27a..4b6270b26da 100644 --- a/src/test/rustdoc/ensure-src-link.rs +++ b/src/test/rustdoc/ensure-src-link.rs @@ -2,5 +2,5 @@ // 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; diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs index 0dadca551a9..fc29cb252e2 100644 --- a/src/test/rustdoc/external-doc.rs +++ b/src/test/rustdoc/external-doc.rs @@ -1,12 +1,3 @@ -#![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' diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs index 03a4d197499..96ced021041 100644 --- a/src/test/rustdoc/generic-impl.rs +++ b/src/test/rustdoc/generic-impl.rs @@ -2,10 +2,10 @@ 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' diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 90110babea7..e4039eecb71 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -5,7 +5,7 @@ pub auto trait AnAutoTrait {} 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," diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs index 8fc01c3f04c..231805a52b9 100644 --- a/src/test/rustdoc/inline_cross/assoc-items.rs +++ b/src/test/rustdoc/inline_cross/assoc-items.rs @@ -16,18 +16,15 @@ extern crate assoc_items; // @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 diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs index cc0596c70ce..9b67022fd4b 100644 --- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs +++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs @@ -8,6 +8,5 @@ extern crate impl_inline_without_trait; // @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; diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs index f47056223fe..390f0b845e0 100644 --- a/src/test/rustdoc/inline_cross/issue-31948-1.rs +++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs @@ -5,8 +5,8 @@ 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; diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs index 282f0679e98..013e777440f 100644 --- a/src/test/rustdoc/inline_cross/issue-31948-2.rs +++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs @@ -5,9 +5,9 @@ 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; diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs index d5725175e3f..82dcc2d2cc3 100644 --- a/src/test/rustdoc/inline_cross/issue-31948.rs +++ b/src/test/rustdoc/inline_cross/issue-31948.rs @@ -5,9 +5,9 @@ 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; diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs index 2757418bc64..d9fed2d6951 100644 --- a/src/test/rustdoc/intra-doc/associated-items.rs +++ b/src/test/rustdoc/intra-doc/associated-items.rs @@ -3,9 +3,9 @@ /// [`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] diff --git a/src/test/rustdoc/intra-doc/builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs index 74216a587e1..bbdbe246bbc 100644 --- a/src/test/rustdoc/intra-doc/builtin-macros.rs +++ b/src/test/rustdoc/intra-doc/builtin-macros.rs @@ -1,3 +1,3 @@ // @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] diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs new file mode 100644 index 00000000000..00114348924 --- /dev/null +++ b/src/test/rustdoc/intra-doc/field.rs @@ -0,0 +1,4 @@ +// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' +// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//! [start][std::ops::Range::start] +//! [not_found][std::io::ErrorKind::NotFound] diff --git a/src/test/rustdoc/intra-doc/generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs index 1de6410f10c..fbc9fc6a9bc 100644 --- a/src/test/rustdoc/intra-doc/generic-params.rs +++ b/src/test/rustdoc/intra-doc/generic-params.rs @@ -5,40 +5,40 @@ //! 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) diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs index ee71537d155..be4b44b3142 100644 --- a/src/test/rustdoc/intra-doc/non-path-primitives.rs +++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs @@ -2,45 +2,45 @@ #![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] //! [!] diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs index 4099ececfaf..c73140420ff 100644 --- a/src/test/rustdoc/intra-doc/prim-assoc.rs +++ b/src/test/rustdoc/intra-doc/prim-assoc.rs @@ -1,4 +1,4 @@ #![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" diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs index 695a7fbfb53..9347d7bb428 100644 --- a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs @@ -9,8 +9,8 @@ #![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`]. diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs index f0b939a468c..124faa9a636 100644 --- a/src/test/rustdoc/intra-doc/prim-methods-local.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs @@ -5,8 +5,8 @@ // @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`]. diff --git a/src/test/rustdoc/intra-doc/prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs index 6de15e76d15..076117359d2 100644 --- a/src/test/rustdoc/intra-doc/prim-methods.rs +++ b/src/test/rustdoc/intra-doc/prim-methods.rs @@ -2,7 +2,7 @@ // @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`]. diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs index 478b40b0b51..fcd86a99f1d 100644 --- a/src/test/rustdoc/intra-doc/prim-precedence.rs +++ b/src/test/rustdoc/intra-doc/prim-precedence.rs @@ -2,12 +2,12 @@ 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] diff --git a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs index acdd07566c9..9b3b6983240 100644 --- a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs +++ b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs @@ -1,4 +1,4 @@ #![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()] diff --git a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs index cf83ead4db7..f8a824bd08f 100644 --- a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs +++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs @@ -3,29 +3,29 @@ // @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() {} diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs index 579fa68cee8..b4f2d6b0617 100644 --- a/src/test/rustdoc/intra-doc/pub-use.rs +++ b/src/test/rustdoc/intra-doc/pub-use.rs @@ -12,7 +12,7 @@ extern crate inner; // 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; @@ -23,5 +23,5 @@ extern crate self as _; // 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; diff --git a/src/test/rustdoc/intra-doc/trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs index 7602aced564..0be368d051e 100644 --- a/src/test/rustdoc/intra-doc/trait-item.rs +++ b/src/test/rustdoc/intra-doc/trait-item.rs @@ -3,7 +3,7 @@ /// 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 { diff --git a/src/test/rustdoc/intra-doc/true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs index db637ece369..44aac688413 100644 --- a/src/test/rustdoc/intra-doc/true-false.rs +++ b/src/test/rustdoc/intra-doc/true-false.rs @@ -3,7 +3,7 @@ // @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`]. diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-link-prim-self.rs index 1189d266c53..4744c84b622 100644 --- a/src/test/rustdoc/intra-link-prim-self.rs +++ b/src/test/rustdoc/intra-link-prim-self.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![deny(broken_intra_doc_links)] #![feature(lang_items)] #![feature(no_core)] @@ -8,8 +7,8 @@ /// [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() {} @@ -18,7 +17,7 @@ impl usize { 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; } diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs index 5de26abace6..43ce13fd9b1 100644 --- a/src/test/rustdoc/issue-21474.rs +++ b/src/test/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { 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; diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs index 2b25da77d7e..23d9e73b567 100644 --- a/src/test/rustdoc/issue-29503.rs +++ b/src/test/rustdoc/issue-29503.rs @@ -5,7 +5,7 @@ pub trait MyTrait { 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) diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs index 21356b513ee..1777744c0fc 100644 --- a/src/test/rustdoc/issue-33302.rs +++ b/src/test/rustdoc/issue-33302.rs @@ -23,7 +23,7 @@ macro_rules! make { } // @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 { @@ -31,7 +31,7 @@ macro_rules! make { } // @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 { @@ -39,7 +39,7 @@ macro_rules! make { } // @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 { diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs index 8a5f0413826..86479e6fb2e 100644 --- a/src/test/rustdoc/issue-45584.rs +++ b/src/test/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @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 {} diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs index 0820512e521..69774aa351f 100644 --- a/src/test/rustdoc/issue-50159.rs +++ b/src/test/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> { // @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, } diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs index d018c948162..e01dae6c7f1 100644 --- a/src/test/rustdoc/issue-51236.rs +++ b/src/test/rustdoc/issue-51236.rs @@ -7,8 +7,8 @@ pub mod traits { } // @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>, } diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs index ddc14e68675..0b1f2f2c93f 100644 --- a/src/test/rustdoc/issue-53812.rs +++ b/src/test/rustdoc/issue-53812.rs @@ -12,9 +12,10 @@ macro_rules! array_impls { } } -// @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 } diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs index 47da94a4ccf..5a94d36ed70 100644 --- a/src/test/rustdoc/issue-54705.rs +++ b/src/test/rustdoc/issue-54705.rs @@ -3,11 +3,11 @@ pub trait ScopeHandle<'scope> {} // @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>, { diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs index d1877f39ba7..b664733487b 100644 --- a/src/test/rustdoc/issue-55321.rs +++ b/src/test/rustdoc/issue-55321.rs @@ -1,16 +1,18 @@ #![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>); diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs index b932a3d3474..977596e0b90 100644 --- a/src/test/rustdoc/issue-56822.rs +++ b/src/test/rustdoc/issue-56822.rs @@ -17,8 +17,8 @@ impl<'a, T> MyTrait for Inner<'a, 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 } diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs index 79b8b70c545..e0417f1a4f4 100644 --- a/src/test/rustdoc/issue-60726.rs +++ b/src/test/rustdoc/issue-60726.rs @@ -26,10 +26,10 @@ where {} // @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>>, } diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs index d468f35e280..a90e0fea092 100644 --- a/src/test/rustdoc/issue-76501.rs +++ b/src/test/rustdoc/issue-76501.rs @@ -8,7 +8,8 @@ pub const fn bloop() -> i32 { 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 diff --git a/src/test/rustdoc/issue-78673.rs b/src/test/rustdoc/issue-78673.rs index d09141c3204..2e4bec2544c 100644 --- a/src/test/rustdoc/issue-78673.rs +++ b/src/test/rustdoc/issue-78673.rs @@ -7,8 +7,8 @@ pub trait AnAmazingTrait {} 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 {} @@ -16,8 +16,8 @@ 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> {} diff --git a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs new file mode 100644 index 00000000000..618ac20ac48 --- /dev/null +++ b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs @@ -0,0 +1,16 @@ +use std::convert::AsRef; +pub struct Local; + +// @has issue_82465_asref_for_and_of_local/struct.Local.html '//code' 'impl AsRef<str> for Local' +impl AsRef<str> for Local { + fn as_ref(&self) -> &str { + todo!() + } +} + +// @has - '//code' 'impl AsRef<Local> for str' +impl AsRef<Local> for str { + fn as_ref(&self) -> &Local { + todo!() + } +} diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs new file mode 100644 index 00000000000..45664dfc382 --- /dev/null +++ b/src/test/rustdoc/issue-85454.rs @@ -0,0 +1,17 @@ +// @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), +} diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs index 25e8b7912e7..652517c5c90 100644 --- a/src/test/rustdoc/keyword.rs +++ b/src/test/rustdoc/keyword.rs @@ -4,7 +4,8 @@ // @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!' diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs index 776a191ceef..b2ee077bc6b 100644 --- a/src/test/rustdoc/manual_impl.rs +++ b/src/test/rustdoc/manual_impl.rs @@ -24,13 +24,10 @@ pub trait T { // @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. @@ -45,10 +42,7 @@ impl T for S1 { // @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. @@ -65,10 +59,9 @@ impl T for S2 { } // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T' -// @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. diff --git a/src/test/rustdoc/mut-params.rs b/src/test/rustdoc/mut-params.rs index 1ef7e304fa2..f3ea6995839 100644 --- a/src/test/rustdoc/mut-params.rs +++ b/src/test/rustdoc/mut-params.rs @@ -5,7 +5,7 @@ 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) {} diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs index d76aac6906c..ee65a7d5f39 100644 --- a/src/test/rustdoc/negative-impl.rs +++ b/src/test/rustdoc/negative-impl.rs @@ -5,8 +5,10 @@ pub struct Alpha; // @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> {} diff --git a/src/test/rustdoc/primitive-generic-impl.rs b/src/test/rustdoc/primitive-generic-impl.rs index 5794322ba1d..2951f5128e0 100644 --- a/src/test/rustdoc/primitive-generic-impl.rs +++ b/src/test/rustdoc/primitive-generic-impl.rs @@ -2,4 +2,4 @@ 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' diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs index dd455e45bfc..125e0c84973 100644 --- a/src/test/rustdoc/primitive-link.rs +++ b/src/test/rustdoc/primitive-link.rs @@ -1,12 +1,12 @@ #![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], diff --git a/src/test/rustdoc/primitive-reexport.rs b/src/test/rustdoc/primitive-reexport.rs index de18360d407..10a8a47db52 100644 --- a/src/test/rustdoc/primitive-reexport.rs +++ b/src/test/rustdoc/primitive-reexport.rs @@ -5,24 +5,24 @@ // @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; diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs index 8e88b2b5901..fa7de0aff6a 100644 --- a/src/test/rustdoc/pub-method.rs +++ b/src/test/rustdoc/pub-method.rs @@ -10,8 +10,8 @@ pub fn bar() -> usize { } // @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 { diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs index 6219a2c3b90..d256fbe8de0 100644 --- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs +++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs @@ -6,9 +6,9 @@ // @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 {} diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs index 26d12817afc..6730c71e90f 100644 --- a/src/test/rustdoc/sized_trait.rs +++ b/src/test/rustdoc/sized_trait.rs @@ -1,17 +1,17 @@ #![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], } diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs index ed42c435945..864cb0c400b 100644 --- a/src/test/rustdoc/spotlight-from-dependency.rs +++ b/src/test/rustdoc/spotlight-from-dependency.rs @@ -3,7 +3,7 @@ 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, } diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs index a1d183df0f1..6f609e080d3 100644 --- a/src/test/rustdoc/src-links-auto-impls.rs +++ b/src/test/rustdoc/src-links-auto-impls.rs @@ -1,12 +1,12 @@ #![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], } diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index 0dd3a3f7a86..943596a0c85 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @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, } diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index d951a20e2de..0213142266f 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -20,8 +20,8 @@ mod foo { } // @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}; diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs index 05c88f10822..c2e9b6f4046 100644 --- a/src/test/rustdoc/synthetic_auto/lifetimes.rs +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -9,11 +9,11 @@ where {} // @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>, } diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index 88ddd57349a..91fe6c351c5 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @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, } diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs index 53801542c95..16b36b56b68 100644 --- a/src/test/rustdoc/synthetic_auto/negative.rs +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -3,11 +3,11 @@ pub struct Inner<T: Copy> { } // @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>, } diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs index d4d93a87ffc..a6cf5890dca 100644 --- a/src/test/rustdoc/synthetic_auto/nested.rs +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @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>, diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index 3a23dc2cf95..5c744e3eb3c 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,8 +9,8 @@ where } // @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>, } diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs index 060491e3cf1..baf9924b1ae 100644 --- a/src/test/rustdoc/synthetic_auto/project.rs +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -23,11 +23,12 @@ where } // @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>, } diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index ecdbdf41b20..e96187e2c96 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> { // @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; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs index a10e694c1b2..fc732a08ed4 100644 --- a/src/test/rustdoc/synthetic_auto/static-region.rs +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -3,8 +3,8 @@ pub trait OwnedTrait<'a> { } // @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, } diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/toggle-item-contents.rs index 8986f72636a..6e3c0b4c681 100644 --- a/src/test/rustdoc/item-hide-threshold.rs +++ b/src/test/rustdoc/toggle-item-contents.rs @@ -1,13 +1,13 @@ #![allow(unused)] -// @has 'item_hide_threshold/struct.PubStruct.html' +// @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 'item_hide_threshold/struct.BigPubStruct.html' +// @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 { @@ -26,7 +26,7 @@ pub struct BigPubStruct { pub m: usize, } -// @has 'item_hide_threshold/union.BigUnion.html' +// @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 { @@ -45,7 +45,7 @@ pub union BigUnion { pub m: usize, } -// @has 'item_hide_threshold/union.Union.html' +// @has 'toggle_item_contents/union.Union.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 pub union Union { pub a: usize, @@ -53,7 +53,7 @@ pub union Union { pub c: usize, } -// @has 'item_hide_threshold/struct.PrivStruct.html' +// @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 { @@ -61,7 +61,7 @@ pub struct PrivStruct { b: usize, } -// @has 'item_hide_threshold/enum.Enum.html' +// @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 { @@ -72,14 +72,14 @@ pub enum Enum { } } -// @has 'item_hide_threshold/enum.LargeEnum.html' +// @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 'item_hide_threshold/trait.Trait.html' +// @has 'toggle_item_contents/trait.Trait.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 pub trait Trait { type A; @@ -88,7 +88,7 @@ pub trait Trait { fn bar(); } -// @has 'item_hide_threshold/trait.GinormousTrait.html' +// @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 { @@ -111,7 +111,7 @@ pub trait GinormousTrait { fn bar(); } -// @has 'item_hide_threshold/trait.HugeTrait.html' +// @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 { @@ -133,7 +133,7 @@ pub trait HugeTrait { fn bar(); } -// @has 'item_hide_threshold/trait.BigTrait.html' +// @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 { diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs new file mode 100644 index 00000000000..f7f6086a4cb --- /dev/null +++ b/src/test/rustdoc/toggle-method.rs @@ -0,0 +1,18 @@ +#![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() {} +} diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs index a160809cbf9..0bc5eba75a1 100644 --- a/src/test/rustdoc/toggle-trait-fn.rs +++ b/src/test/rustdoc/toggle-trait-fn.rs @@ -1,7 +1,23 @@ #![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() {} } diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs index 2bb24a82193..d0dfb8759e6 100644 --- a/src/test/rustdoc/trait-attributes.rs +++ b/src/test/rustdoc/trait-attributes.rs @@ -2,7 +2,7 @@ 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(); } @@ -11,11 +11,11 @@ pub trait 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() {} } diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs index c6a9313e821..5b7c04c0d44 100644 --- a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs +++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs @@ -8,58 +8,58 @@ pub trait MyTrait { 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; diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs index 7f834d3d5a5..21a7fdda769 100644 --- a/src/test/rustdoc/typedef.rs +++ b/src/test/rustdoc/typedef.rs @@ -9,8 +9,8 @@ impl 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' diff --git a/src/test/rustdoc/unindent.rs b/src/test/rustdoc/unindent.rs index d10e1ec89c5..372af5f4672 100644 --- a/src/test/rustdoc/unindent.rs +++ b/src/test/rustdoc/unindent.rs @@ -1,5 +1,3 @@ -#![feature(external_doc)] - #![crate_name = "foo"] // @has foo/struct.Example.html @@ -51,7 +49,7 @@ pub struct I; // @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 @@ -60,5 +58,5 @@ pub struct J; /// /// 4 whitespaces! /// -#[doc(include = "unindent.md")] +#[doc = include_str!("unindent.md")] pub struct K; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 992cddfe72a..f204a27d7d3 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -11,7 +11,7 @@ pub fn charlie<C>() where C: MyTrait {} 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() {} @@ -19,7 +19,7 @@ impl<D> Delta<D> where D: MyTrait { 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" @@ -27,7 +27,7 @@ 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" diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs index f58446d5592..25f6490aa35 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -1,3 +1,4 @@ +// compile-flags: -Z unstable-options // NOTE: This test doesn't actually require `fulldeps` // so we could instead use it as an `ui` test. // diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr index b846b30f4ed..15a06e721dd 100644 --- a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -1,17 +1,17 @@ error: passing `TyCtxt<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:17:15 + --> $DIR/pass_ty_by_ref_self.rs:18:15 | LL | fn by_ref(&self) {} | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` | note: the lint level is defined here - --> $DIR/pass_ty_by_ref_self.rs:7:9 + --> $DIR/pass_ty_by_ref_self.rs:8:9 | LL | #![deny(rustc::ty_pass_by_reference)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing `Ty<'tcx>` by reference - --> $DIR/pass_ty_by_ref_self.rs:30:21 + --> $DIR/pass_ty_by_ref_self.rs:31:21 | LL | fn by_ref(self: &Ty<'tcx>) {} | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index ac2d29c9caf..091c834eccf 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -19,45 +19,35 @@ #![feature(rustc_private)] +extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_data_structures; -extern crate rustc_ast; extern crate rustc_parse; extern crate rustc_session; extern crate rustc_span; +use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor}; +use rustc_ast::ptr::P; +use rustc_ast::*; use rustc_ast_pretty::pprust; use rustc_data_structures::thin_vec::ThinVec; use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{Spanned, DUMMY_SP, FileName}; use rustc_span::source_map::FilePathMapping; +use rustc_span::source_map::{FileName, Spanned, DUMMY_SP}; use rustc_span::symbol::Ident; -use rustc_ast::*; -use rustc_ast::mut_visit::{self, MutVisitor, visit_clobber}; -use rustc_ast::ptr::P; fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> { let src_as_string = src.to_string(); - let mut p = new_parser_from_source_str( - ps, - FileName::Custom(src_as_string.clone()), - src_as_string, - ); + let mut p = + new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string); p.parse_expr().map_err(|mut e| e.cancel()).ok() } - // Helper functions for building exprs fn expr(kind: ExprKind) -> P<Expr> { - P(Expr { - id: DUMMY_NODE_ID, - kind, - span: DUMMY_SP, - attrs: ThinVec::new(), - tokens: None - }) + P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: ThinVec::new(), tokens: None }) } fn make_x() -> P<Expr> { @@ -83,11 +73,13 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { 1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), 2 => { let seg = PathSegment::from_ident(Ident::from_str("x")); - iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( - seg.clone(), vec![e, make_x()], DUMMY_SP))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( - seg.clone(), vec![make_x(), e], DUMMY_SP))); - }, + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP)) + }); + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP)) + }); + } 3..=8 => { let op = Spanned { span: DUMMY_SP, @@ -99,14 +91,14 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { 7 => BinOpKind::Or, 8 => BinOpKind::Lt, _ => unreachable!(), - } + }, }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); - }, + } 9 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e))); - }, + } 10 => { let block = P(Block { stmts: Vec::new(), @@ -116,67 +108,66 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); - }, + } 11 => { - let decl = P(FnDecl { - inputs: vec![], - output: FnRetTy::Default(DUMMY_SP), + let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) }); + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::Closure( + CaptureBy::Value, + Async::No, + Movability::Movable, + decl.clone(), + e, + DUMMY_SP, + )) }); - iter_exprs(depth - 1, &mut |e| g( - ExprKind::Closure(CaptureBy::Value, - Async::No, - Movability::Movable, - decl.clone(), - e, - DUMMY_SP))); - }, + } 12 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP))); - }, + } 13 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f")))); - }, + } 14 => { - iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( - Some(e), Some(make_x()), RangeLimits::HalfOpen))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( - Some(make_x()), Some(e), RangeLimits::HalfOpen))); - }, + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::Range(Some(e), Some(make_x()), RangeLimits::HalfOpen)) + }); + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::Range(Some(make_x()), Some(e), RangeLimits::HalfOpen)) + }); + } 15 => { - iter_exprs( - depth - 1, - &mut |e| g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e)), - ); - }, + iter_exprs(depth - 1, &mut |e| { + g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e)) + }); + } 16 => { g(ExprKind::Ret(None)); iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e)))); - }, + } 17 => { let path = Path::from_ident(Ident::from_str("S")); g(ExprKind::Struct(P(StructExpr { - path, fields: vec![], rest: StructRest::Base(make_x()) + qself: None, + path, + fields: vec![], + rest: StructRest::Base(make_x()), }))); - }, + } 18 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); - }, + } 19 => { - let pat = P(Pat { - id: DUMMY_NODE_ID, - kind: PatKind::Wild, - span: DUMMY_SP, - tokens: None, - }); + let pat = + P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None }); iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e))) - }, + } _ => panic!("bad counter value in iter_exprs"), } } } - // Folders for manipulating the placement of `Paren` nodes. See below for why this is needed. /// `MutVisitor` that removes all `ExprKind::Paren` nodes. @@ -192,7 +183,6 @@ impl MutVisitor for RemoveParens { } } - /// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`. struct AddParens; @@ -205,7 +195,7 @@ impl MutVisitor for AddParens { kind: ExprKind::Paren(e), span: DUMMY_SP, attrs: ThinVec::new(), - tokens: None + tokens: None, }) }); } @@ -238,9 +228,12 @@ fn run() { RemoveParens.visit_expr(&mut parsed); AddParens.visit_expr(&mut parsed); let text2 = pprust::expr_to_string(&parsed); - assert!(text1 == text2, - "exprs are not equal:\n e = {:?}\n parsed = {:?}", - text1, text2); + assert!( + text1 == text2, + "exprs are not equal:\n e = {:?}\n parsed = {:?}", + text1, + text2 + ); } }); } diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs index 7967b32a4a4..140aaad3b38 100644 --- a/src/test/ui-fulldeps/session-derive-errors.rs +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -1,6 +1,12 @@ // check-fail // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] +// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, +// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler +// the test is just ignored on stable and beta: +// ignore-beta +// ignore-stable + #![feature(rustc_private)] #![crate_type = "lib"] diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr index c6c3765b80d..2f1debe25b7 100644 --- a/src/test/ui-fulldeps/session-derive-errors.stderr +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -1,5 +1,5 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs - --> $DIR/session-derive-errors.rs:28:1 + --> $DIR/session-derive-errors.rs:34:1 | LL | / #[error = "E0123"] LL | | @@ -10,31 +10,31 @@ LL | | } | |_^ error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute - --> $DIR/session-derive-errors.rs:37:1 + --> $DIR/session-derive-errors.rs:43:1 | LL | #[label = "This is in the wrong place"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute - --> $DIR/session-derive-errors.rs:44:5 + --> $DIR/session-derive-errors.rs:50:5 | LL | #[suggestion = "this is the wrong kind of attribute"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `error` specified multiple times - --> $DIR/session-derive-errors.rs:52:11 + --> $DIR/session-derive-errors.rs:58:11 | LL | #[error = "E0456"] | ^^^^^^^ error: `lint` specified when `error` was already specified - --> $DIR/session-derive-errors.rs:58:10 + --> $DIR/session-derive-errors.rs:64:10 | LL | #[lint = "some_useful_lint"] | ^^^^^^^^^^^^^^^^^^ error: `code` not specified - --> $DIR/session-derive-errors.rs:67:1 + --> $DIR/session-derive-errors.rs:73:1 | LL | struct ErrorCodeNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,19 +42,19 @@ LL | struct ErrorCodeNotProvided {} = help: use the [code = "..."] attribute to set this diagnostic's error code error: the `#[message = "..."]` attribute can only be applied to fields of type Span - --> $DIR/session-derive-errors.rs:95:5 + --> $DIR/session-derive-errors.rs:101:5 | LL | #[message = "this message is applied to a String field"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/session-derive-errors.rs:102:1 + --> $DIR/session-derive-errors.rs:108:1 | LL | #[message = "This error has a field, and references {name}"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/session-derive-errors.rs:110:1 + --> $DIR/session-derive-errors.rs:116:1 | LL | #[error = "E0123"] | - because of this opening brace @@ -65,7 +65,7 @@ LL | #[message = "This is missing a closing brace: {name"] = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/session-derive-errors.rs:119:1 + --> $DIR/session-derive-errors.rs:125:1 | LL | #[message = "This is missing an opening brace: name}"] | ^ unmatched `}` in format string @@ -74,25 +74,25 @@ LL | #[message = "This is missing an opening brace: name}"] = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: The `#[label = ...]` attribute can only be applied to fields of type Span - --> $DIR/session-derive-errors.rs:138:5 + --> $DIR/session-derive-errors.rs:144:5 | LL | #[label = "See here"] | ^^^^^^^^^^^^^^^^^^^^^ error: `nonsense` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:163:18 + --> $DIR/session-derive-errors.rs:169:18 | LL | #[suggestion(nonsense = "This is nonsense")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `msg` is not a valid key for `#[suggestion(...)]` - --> $DIR/session-derive-errors.rs:171:18 + --> $DIR/session-derive-errors.rs:177:18 | LL | #[suggestion(msg = "This is a suggestion")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing suggestion message - --> $DIR/session-derive-errors.rs:179:7 + --> $DIR/session-derive-errors.rs:185:7 | LL | #[suggestion(code = "This is suggested code")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | #[suggestion(code = "This is suggested code")] = help: provide a suggestion message using #[suggestion(message = "...")] error: wrong field type for suggestion - --> $DIR/session-derive-errors.rs:194:5 + --> $DIR/session-derive-errors.rs:200:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -110,7 +110,7 @@ LL | | suggestion: Applicability, = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) error: type of field annotated with `#[suggestion(...)]` contains more than one Span - --> $DIR/session-derive-errors.rs:209:5 + --> $DIR/session-derive-errors.rs:215:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -118,7 +118,7 @@ LL | | suggestion: (Span, Span, Applicability), | |___________________________________________^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/session-derive-errors.rs:217:5 + --> $DIR/session-derive-errors.rs:223:5 | LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] LL | | @@ -126,7 +126,7 @@ LL | | suggestion: (Applicability, Applicability, Span), | |____________________________________________________^ error: invalid annotation list `#[label(...)]` - --> $DIR/session-derive-errors.rs:225:7 + --> $DIR/session-derive-errors.rs:231:7 | LL | #[label("wrong kind of annotation for label")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/annotate-snippet/missing-type.rs b/src/test/ui/annotate-snippet/missing-type.rs index d0814a9537d..b0d8b5fbaf2 100644 --- a/src/test/ui/annotate-snippet/missing-type.rs +++ b/src/test/ui/annotate-snippet/missing-type.rs @@ -1,4 +1,4 @@ -// compile-flags: --error-format human-annotate-rs +// compile-flags: --error-format human-annotate-rs -Z unstable-options pub fn main() { let x: Iter; //~ ERROR cannot find type `Iter` in this scope diff --git a/src/test/ui/annotate-snippet/multispan.rs b/src/test/ui/annotate-snippet/multispan.rs index 325252d7716..69d7e1a9d11 100644 --- a/src/test/ui/annotate-snippet/multispan.rs +++ b/src/test/ui/annotate-snippet/multispan.rs @@ -1,5 +1,5 @@ // aux-build:multispan.rs -// compile-flags: --error-format human-annotate-rs +// compile-flags: --error-format human-annotate-rs -Z unstable-options #![feature(proc_macro_hygiene)] diff --git a/src/test/ui/associated-types/associated-type-destructuring-assignment.rs b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs new file mode 100644 index 00000000000..fea7c7a383f --- /dev/null +++ b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(destructuring_assignment)] +#![feature(more_qualified_paths)] + +enum E { V() } + +fn main() { + <E>::V() = E::V(); // OK, destructuring assignment + <E>::V {} = E::V(); // OK, destructuring assignment +} diff --git a/src/test/ui/associated-types/associated-type-macro.rs b/src/test/ui/associated-types/associated-type-macro.rs new file mode 100644 index 00000000000..22b5bca4010 --- /dev/null +++ b/src/test/ui/associated-types/associated-type-macro.rs @@ -0,0 +1,4 @@ +fn main() { + #[cfg(FALSE)] + <() as module>::mac!(); //~ ERROR macros cannot use qualified paths +} diff --git a/src/test/ui/associated-types/associated-type-macro.stderr b/src/test/ui/associated-types/associated-type-macro.stderr new file mode 100644 index 00000000000..6a4cf99c474 --- /dev/null +++ b/src/test/ui/associated-types/associated-type-macro.stderr @@ -0,0 +1,8 @@ +error: macros cannot use qualified paths + --> $DIR/associated-type-macro.rs:3:5 + | +LL | <() as module>::mac!(); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/associated-types/associated-type-struct-construction.rs b/src/test/ui/associated-types/associated-type-struct-construction.rs new file mode 100644 index 00000000000..f8f8048fb71 --- /dev/null +++ b/src/test/ui/associated-types/associated-type-struct-construction.rs @@ -0,0 +1,24 @@ +// Make sure that users can construct structs through associated types +// in both expressions and patterns + +#![feature(more_qualified_paths)] + +// check-pass +fn main() { + let <Foo as A>::Assoc { br } = <Foo as A>::Assoc { br: 2 }; + assert!(br == 2); +} + +struct StructStruct { + br: i8, +} + +struct Foo; + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = StructStruct; +} diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs b/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs new file mode 100644 index 00000000000..d5809ecd55d --- /dev/null +++ b/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs @@ -0,0 +1,24 @@ +// Users cannot yet construct structs through associated types +// in both expressions and patterns + +#![feature(more_qualified_paths)] + +fn main() { + let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2); + //~^ ERROR expected method or associated constant, found associated type + //~| ERROR expected method or associated constant, found associated type + assert!(n == 2); +} + +struct TupleStruct(i8); + +struct Foo; + + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = TupleStruct; +} diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr b/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr new file mode 100644 index 00000000000..bca7deeb512 --- /dev/null +++ b/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr @@ -0,0 +1,19 @@ +error[E0575]: expected method or associated constant, found associated type `A::Assoc` + --> $DIR/associated-type-tuple-struct-construction.rs:7:32 + | +LL | let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2); + | ^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0575]: expected method or associated constant, found associated type `A::Assoc` + --> $DIR/associated-type-tuple-struct-construction.rs:7:9 + | +LL | let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2); + | ^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0575`. diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 0207752afe0..3d22025bf28 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -1,7 +1,8 @@ // run-pass -// revisions: default nomiropt +// revisions: default nomiropt thirunsafeck //[nomiropt]compile-flags: -Z mir-opt-level=0 +//[thirunsafeck]compile-flags: -Zthir-unsafeck #![allow(unused)] diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs index 2ed343b4a07..fc37822cb7b 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs @@ -16,6 +16,6 @@ async fn g() { } 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 } diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr index d22413beecb..21ba45d7f1e 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr @@ -14,22 +14,6 @@ LL | f(); | = 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`. diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index e97d088cf3e..62a1f451a1c 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -41,14 +41,14 @@ LL | require_send(send_fut); | = 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 `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>` = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future` = note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready<i32>}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>` = note: required because it appears within the type `impl Future` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/issues/issue-67893.stderr b/src/test/ui/async-await/issues/issue-67893.stderr index aee2ae0e2e4..ea5c90a81d4 100644 --- a/src/test/ui/async-await/issues/issue-67893.stderr +++ b/src/test/ui/async-await/issues/issue-67893.stderr @@ -14,8 +14,8 @@ LL | pub async fn run() { | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}` - = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>` + = note: required because it appears within the type `[static generator@run::{closure#0}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>` = note: required because it appears within the type `impl Future` = note: required because it appears within the type `impl Future` diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs index b901b61aa18..f1002947fb9 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs @@ -1,10 +1,9 @@ // 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 { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs deleted file mode 100644 index 05960c0c7f6..00000000000 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs +++ /dev/null @@ -1,20 +0,0 @@ -// 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); -} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr deleted file mode 100644 index f65bbeaa31a..00000000000 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr +++ /dev/null @@ -1,43 +0,0 @@ -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`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr index 53b0dd691b8..eed90772d29 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr @@ -1,5 +1,5 @@ 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> { | ________________________________--__--__________________________________________^ diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs index babc90a5e96..7e084217c26 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs @@ -3,8 +3,6 @@ // 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 { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 5041b39a9e9..8e28605721c 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -1,5 +1,5 @@ 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> { | ------ ^^^^^^^^^^^^^^ diff --git a/src/test/ui/borrowck/issue-85765.rs b/src/test/ui/borrowck/issue-85765.rs new file mode 100644 index 00000000000..b82e0298158 --- /dev/null +++ b/src/test/ui/borrowck/issue-85765.rs @@ -0,0 +1,8 @@ +fn main() { + let mut test = Vec::new(); + let rofl: &Vec<Vec<i32>> = &mut test; + //~^ HELP consider changing this to be a mutable reference + rofl.push(Vec::new()); + //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference + //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable +} diff --git a/src/test/ui/borrowck/issue-85765.stderr b/src/test/ui/borrowck/issue-85765.stderr new file mode 100644 index 00000000000..863c2e8eccc --- /dev/null +++ b/src/test/ui/borrowck/issue-85765.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference + --> $DIR/issue-85765.rs:5:5 + | +LL | let rofl: &Vec<Vec<i32>> = &mut test; + | ---- help: consider changing this to be a mutable reference: `&mut Vec<Vec<i32>>` +LL | +LL | rofl.push(Vec::new()); + | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index dd67514d02a..cf73403bbae 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -64,6 +64,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + | + = note: requirement occurs because of a mutable reference to VaListImpl<'_> + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 @@ -74,6 +78,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` + | + = note: requirement occurs because of a mutable reference to VaListImpl<'_> + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error[E0597]: `ap1` does not live long enough --> $DIR/variadic-ffi-4.rs:28:11 diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr index 8282bc3db05..dcc9a243f0f 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr +++ b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block - --> $DIR/cast-ptr-to-int-const.rs:16:9 + --> $DIR/cast-ptr-to-int-const.rs:10:9 | LL | &Y as *const u32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int @@ -7,7 +7,7 @@ LL | &Y as *const u32 as usize = 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 + --> $DIR/cast-ptr-to-int-const.rs:17:5 | LL | &0 as *const i32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs index aed099a53ea..01ea627679d 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.rs +++ b/src/test/ui/cast/cast-ptr-to-int-const.rs @@ -1,25 +1,19 @@ -// gate-test-const_raw_ptr_to_usize_cast -// revisions: with_feature without_feature +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck -#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))] +#![feature(const_raw_ptr_to_usize_cast)] fn main() { - const X: usize = unsafe { - main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable - }; const Y: u32 = 0; - const Z: usize = unsafe { - &Y as *const u32 as usize //[without_feature]~ ERROR is unstable - }; // Cast in `const` without `unsafe` block const SAFE: usize = { - &Y as *const u32 as usize //[without_feature]~ ERROR is unstable - //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe + &Y as *const u32 as usize + //~^ ERROR cast of pointer to int is unsafe and requires unsafe }; } // Cast in `const fn` without `unsafe` block const fn test() -> usize { - &0 as *const i32 as usize //[without_feature]~ ERROR is unstable - //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe + &0 as *const i32 as usize + //~^ ERROR cast of pointer to int is unsafe and requires unsafe } diff --git a/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr new file mode 100644 index 00000000000..dcc9a243f0f --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr @@ -0,0 +1,19 @@ +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:10: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:17: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`. diff --git a/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs new file mode 100644 index 00000000000..03e99eb7527 --- /dev/null +++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs @@ -0,0 +1,13 @@ +fn main() { + const X: usize = unsafe { + main as usize //~ ERROR casting pointers to integers in constants is unstable + }; + const Y: u32 = 0; + const Z: usize = unsafe { + &Y as *const u32 as usize //~ ERROR is unstable + }; +} + +const fn test() -> usize { + &0 as *const i32 as usize //~ ERROR is unstable +} diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr index c87fa1a14a4..4a0b424e181 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr +++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr @@ -1,5 +1,5 @@ error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:8:9 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:3:9 | LL | main as usize | ^^^^^^^^^^^^^ @@ -8,16 +8,7 @@ LL | main as usize = 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 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:7:9 | LL | &Y as *const u32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +17,7 @@ LL | &Y as *const u32 as usize = 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 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:12:5 | LL | &0 as *const i32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,6 +25,6 @@ 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 +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/cast/issue-84213.stderr b/src/test/ui/cast/issue-84213.stderr index 1b71d4db511..90cfa263c52 100644 --- a/src/test/ui/cast/issue-84213.stderr +++ b/src/test/ui/cast/issue-84213.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Something` as `*const Something` 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; | ^ @@ -15,7 +15,7 @@ error[E0605]: non-primitive cast: `Something` as `*mut 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; | ^^^^ diff --git a/src/test/ui/command/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs index 819ed0b2dde..61914e22930 100644 --- a/src/test/ui/command/command-pre-exec.rs +++ b/src/test/ui/command/command-pre-exec.rs @@ -1,4 +1,6 @@ // run-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![allow(stable_features)] // ignore-windows - this is a unix-specific test diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr index d6b399acb73..fe6b12968c1 100644 --- a/src/test/ui/confuse-field-and-method/issue-18343.stderr +++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr @@ -1,4 +1,4 @@ -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 { diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index 051940bbe96..0480958e99c 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -1,4 +1,4 @@ -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 { @@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p 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 { @@ -23,7 +23,7 @@ LL | o_closure.not_closure(); | | | 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 { @@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access 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 { @@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p 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 { @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | 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 { diff --git a/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs index 6ba1b2813a1..457e5ae6049 100644 --- a/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs +++ b/src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs @@ -9,31 +9,31 @@ use std::{ }; pub fn yes_iterator() -> impl Iterator<Item = i32> { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_exact_size_iterator() -> impl ExactSizeIterator { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_fused_iterator() -> impl FusedIterator { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_trusted_len() -> impl TrustedLen { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_clone() -> impl Clone { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } pub fn yes_debug() -> impl Debug { - IntoIter::new([0i32; 32]) + IntoIterator::into_iter([0i32; 32]) } diff --git a/src/test/ui/const-generics/array-impls/into-iter-impls-length-33.rs b/src/test/ui/const-generics/array-impls/into-iter-impls-length-33.rs index deafde2912b..4f343f3f97e 100644 --- a/src/test/ui/const-generics/array-impls/into-iter-impls-length-33.rs +++ b/src/test/ui/const-generics/array-impls/into-iter-impls-length-33.rs @@ -9,31 +9,31 @@ use std::{ }; pub fn yes_iterator() -> impl Iterator<Item = i32> { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_exact_size_iterator() -> impl ExactSizeIterator { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_fused_iterator() -> impl FusedIterator { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_trusted_len() -> impl TrustedLen { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_clone() -> impl Clone { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } pub fn yes_debug() -> impl Debug { - IntoIter::new([0i32; 33]) + IntoIterator::into_iter([0i32; 33]) } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs new file mode 100644 index 00000000000..744a1c4de48 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_evaluatable_checked, const_generics)] +#![allow(incomplete_features)] + +struct Foo<const N: u8>([u8; N as usize]) +where + [(); N as usize]:; + +struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:; + +// unifying with subtrees +struct Evaluatable<const N: u16>; +fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: { + let _ = Foo::<N>([1; N as usize]); +} + + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs new file mode 100644 index 00000000000..543774649ed --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs @@ -0,0 +1,20 @@ +#![feature(const_evaluatable_checked, const_generics)] +#![allow(incomplete_features)] + +struct Evaluatable<const N: u128> {} + +struct Foo<const N: u8>([u8; N as usize]) +//~^ Error: unconstrained generic constant +//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:` +where + Evaluatable<{N as u128}>:; + +struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:; +//~^ Error: unconstrained generic constant +//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:` + +struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:; +//~^ Error: unconstrained generic constant +//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:` + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr new file mode 100644 index 00000000000..5ca04d25e55 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr @@ -0,0 +1,26 @@ +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-2.rs:6:25 + | +LL | struct Foo<const N: u8>([u8; N as usize]) + | ^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); N as usize]:` + +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-2.rs:12:26 + | +LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); {N as u128}]:` + +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-2.rs:16:25 + | +LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs new file mode 100644 index 00000000000..2ca06bd1cb7 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs @@ -0,0 +1,47 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +trait Trait {} +pub struct EvaluatableU128<const N: u128>; + +struct HasCastInTraitImpl<const N: usize, const M: u128>; +impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + +pub fn use_trait_impl<const N: usize>() +where + [(); { N + 1}]:, + EvaluatableU128<{N as u128}>:, { + fn assert_impl<T: Trait>() {} + + // errors are bad but seems to be pre-existing issue #86198 + assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + //~^ Error: mismatched types + //~^^ Error: unconstrained generic constant + assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + //~^ Error: mismatched types + //~^^ Error: unconstrained generic constant + assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>(); + //~^ Error: mismatched types + assert_impl::<HasCastInTraitImpl<14, 13>>(); + //~^ Error: mismatched types +} +pub fn use_trait_impl_2<const N: usize>() +where + [(); { N + 1}]:, + EvaluatableU128<{N as _}>:, { + fn assert_impl<T: Trait>() {} + + // errors are bad but seems to be pre-existing issue #86198 + assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + //~^ Error: mismatched types + //~^^ Error: unconstrained generic constant + assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + //~^ Error: mismatched types + //~^^ Error: unconstrained generic constant + assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>(); + //~^ Error: mismatched types + assert_impl::<HasCastInTraitImpl<14, 13>>(); + //~^ Error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr new file mode 100644 index 00000000000..c5237fc6f2b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr @@ -0,0 +1,139 @@ +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-3.rs:17:5 + | +LL | fn assert_impl<T: Trait>() {} + | ----- required by this bound in `use_trait_impl::assert_impl` +... +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:` +note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>` + --> $DIR/abstract-const-as-cast-3.rs:8:22 + | +LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:17:5 + | +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` + | + = note: expected type `{ N as u128 }` + found type `{ O as u128 }` + +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-3.rs:20:5 + | +LL | fn assert_impl<T: Trait>() {} + | ----- required by this bound in `use_trait_impl::assert_impl` +... +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:` +note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>` + --> $DIR/abstract-const-as-cast-3.rs:8:22 + | +LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:20:5 + | +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` + | + = note: expected type `{ N as _ }` + found type `{ O as u128 }` + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:23:5 + | +LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128` + | + = note: expected type `12_u128` + found type `13_u128` + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:25:5 + | +LL | assert_impl::<HasCastInTraitImpl<14, 13>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128` + | + = note: expected type `13_u128` + found type `14_u128` + +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-3.rs:35:5 + | +LL | fn assert_impl<T: Trait>() {} + | ----- required by this bound in `use_trait_impl_2::assert_impl` +... +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:` +note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>` + --> $DIR/abstract-const-as-cast-3.rs:8:22 + | +LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:35:5 + | +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }` + | + = note: expected type `{ N as u128 }` + found type `{ O as u128 }` + +error: unconstrained generic constant + --> $DIR/abstract-const-as-cast-3.rs:38:5 + | +LL | fn assert_impl<T: Trait>() {} + | ----- required by this bound in `use_trait_impl_2::assert_impl` +... +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:` +note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>` + --> $DIR/abstract-const-as-cast-3.rs:8:22 + | +LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:38:5 + | +LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }` + | + = note: expected type `{ N as _ }` + found type `{ O as u128 }` + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:41:5 + | +LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128` + | + = note: expected type `12_u128` + found type `13_u128` + +error[E0308]: mismatched types + --> $DIR/abstract-const-as-cast-3.rs:43:5 + | +LL | assert_impl::<HasCastInTraitImpl<14, 13>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128` + | + = note: expected type `13_u128` + found type `14_u128` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs new file mode 100644 index 00000000000..0bb4fcff4d0 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs @@ -0,0 +1,29 @@ +// check-pass +#![feature(const_evaluatable_checked, const_generics)] +#![allow(incomplete_features)] + +trait Trait {} +pub struct EvaluatableU128<const N: u128>; + +struct HasCastInTraitImpl<const N: usize, const M: u128>; +impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + +pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>(); + assert_impl::<HasCastInTraitImpl<N, { N as _ }>>(); + assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>(); + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} +pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>(); + assert_impl::<HasCastInTraitImpl<N, { N as _ }>>(); + assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>(); + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} + + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs index 05049d9c2a6..26c4295cd9b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs @@ -9,6 +9,7 @@ struct Foo<T>(PhantomData<T>); fn test<T>() -> [u8; size_of::<T>()] { [0; size_of::<Foo<T>>()] //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types } fn main() { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr index 7c11a47b2f0..2aeb9b961ff 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr @@ -1,3 +1,12 @@ +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 | @@ -6,5 +15,6 @@ LL | [0; size_of::<Foo<T>>()] | = 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`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs new file mode 100644 index 00000000000..0f36ce383a8 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs @@ -0,0 +1,22 @@ +// 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() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs index 3da4688702c..8167d785d7a 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -2,7 +2,7 @@ #![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!() } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr index 25af18eb162..31ccf979694 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -1,4 +1,4 @@ -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] { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr index acf0a52ce5b..1f2313a6028 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -1,10 +1,10 @@ -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]; diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr index fe5463f8acc..1aa66f9a8ba 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -8,7 +8,7 @@ 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` diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index c9535d04244..f08d2495b4d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -3,12 +3,13 @@ #![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!() } diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs new file mode 100644 index 00000000000..09fc105320e --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.rs @@ -0,0 +1,15 @@ +#![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() {} diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr new file mode 100644 index 00000000000..a6c4a7ae4ef --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.stderr @@ -0,0 +1,27 @@ +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`. diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr index 985e7b655ec..29d835e36c6 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr @@ -2,13 +2,13 @@ error: lifetime parameters must be declared prior to const parameters --> $DIR/intermixed-lifetime.rs:7:28 | LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T); - | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>` + | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>` error: lifetime parameters must be declared prior to type parameters --> $DIR/intermixed-lifetime.rs:10:37 | LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T); - | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>` + | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/defaults/mismatch.full.stderr b/src/test/ui/const-generics/defaults/mismatch.full.stderr index be4f364d8ee..4aa8401ab22 100644 --- a/src/test/ui/const-generics/defaults/mismatch.full.stderr +++ b/src/test/ui/const-generics/defaults/mismatch.full.stderr @@ -5,9 +5,12 @@ LL | let e: Example::<13> = (); | ------------- ^^ expected struct `Example`, found `()` | | | expected due to this + | + = note: expected struct `Example` + found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:14:34 + --> $DIR/mismatch.rs:15:34 | LL | let e: Example2::<u32, 13> = (); | ------------------- ^^ expected struct `Example2`, found `()` @@ -18,7 +21,7 @@ LL | let e: Example2::<u32, 13> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:16:34 + --> $DIR/mismatch.rs:18:34 | LL | let e: Example3::<13, u32> = (); | ------------------- ^^ expected struct `Example3`, found `()` @@ -29,7 +32,7 @@ LL | let e: Example3::<13, u32> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:18:28 + --> $DIR/mismatch.rs:21:28 | LL | let e: Example3::<7> = (); | ------------- ^^ expected struct `Example3`, found `()` @@ -40,12 +43,15 @@ LL | let e: Example3::<7> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:22:28 + --> $DIR/mismatch.rs:24:28 | LL | let e: Example4::<7> = (); | ------------- ^^ expected struct `Example4`, found `()` | | | expected due to this + | + = note: expected struct `Example4<7_usize>` + found unit type `()` error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/defaults/mismatch.min.stderr b/src/test/ui/const-generics/defaults/mismatch.min.stderr index be4f364d8ee..4aa8401ab22 100644 --- a/src/test/ui/const-generics/defaults/mismatch.min.stderr +++ b/src/test/ui/const-generics/defaults/mismatch.min.stderr @@ -5,9 +5,12 @@ LL | let e: Example::<13> = (); | ------------- ^^ expected struct `Example`, found `()` | | | expected due to this + | + = note: expected struct `Example` + found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:14:34 + --> $DIR/mismatch.rs:15:34 | LL | let e: Example2::<u32, 13> = (); | ------------------- ^^ expected struct `Example2`, found `()` @@ -18,7 +21,7 @@ LL | let e: Example2::<u32, 13> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:16:34 + --> $DIR/mismatch.rs:18:34 | LL | let e: Example3::<13, u32> = (); | ------------------- ^^ expected struct `Example3`, found `()` @@ -29,7 +32,7 @@ LL | let e: Example3::<13, u32> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:18:28 + --> $DIR/mismatch.rs:21:28 | LL | let e: Example3::<7> = (); | ------------- ^^ expected struct `Example3`, found `()` @@ -40,12 +43,15 @@ LL | let e: Example3::<7> = (); found unit type `()` error[E0308]: mismatched types - --> $DIR/mismatch.rs:22:28 + --> $DIR/mismatch.rs:24:28 | LL | let e: Example4::<7> = (); | ------------- ^^ expected struct `Example4`, found `()` | | | expected due to this + | + = note: expected struct `Example4<7_usize>` + found unit type `()` error: aborting due to 5 previous errors diff --git a/src/test/ui/const-generics/defaults/mismatch.rs b/src/test/ui/const-generics/defaults/mismatch.rs index 68a640c0a08..9d9a8793aaa 100644 --- a/src/test/ui/const-generics/defaults/mismatch.rs +++ b/src/test/ui/const-generics/defaults/mismatch.rs @@ -11,14 +11,17 @@ pub struct Example4<const N: usize=13, const M: usize=4>; fn main() { let e: Example::<13> = (); //~^ Error: mismatched types + //~| expected struct `Example` let e: Example2::<u32, 13> = (); //~^ Error: mismatched types + //~| expected struct `Example2` let e: Example3::<13, u32> = (); //~^ Error: mismatched types + //~| expected struct `Example3` let e: Example3::<7> = (); //~^ Error: mismatched types - // FIXME(const_generics_defaults): There should be a note for the error below, but it is - // missing. + //~| expected struct `Example3<7_usize>` let e: Example4::<7> = (); //~^ Error: mismatched types + //~| expected struct `Example4<7_usize>` } diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs new file mode 100644 index 00000000000..933eacb312d --- /dev/null +++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs @@ -0,0 +1,5 @@ +#![feature(const_generics_defaults)] +struct Foo<const M: usize = 10, 'a>(&'a u32); +//~^ Error lifetime parameters must be declared prior to const parameters + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr new file mode 100644 index 00000000000..f50653fe9a1 --- /dev/null +++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr @@ -0,0 +1,8 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/param-order-err-pretty-prints-default.rs:2:33 + | +LL | struct Foo<const M: usize = 10, 'a>(&'a u32); + | ----------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const M: usize = 10>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.full.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325e..efbcdc3d2b7 100644 --- a/src/test/ui/const-generics/issues/issue-62504.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,3 +1,12 @@ +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 | @@ -6,5 +15,6 @@ LL | ArrayHolder([0; Self::SIZE]) | = 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`. diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 0b95754cab4..1b70cd1c376 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -17,7 +17,7 @@ impl<const X: usize> ArrayHolder<X> { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //~^ ERROR constant expression depends on a generic parameter - //[min]~| ERROR mismatched types + //~| ERROR mismatched types } } diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs deleted file mode 100644 index 560795a51f5..00000000000 --- a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs +++ /dev/null @@ -1,10 +0,0 @@ -struct Const<const P: &'static ()>; -//~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter - -fn main() { - const A: &'static () = unsafe { - std::mem::transmute(10 as *const ()) - }; - - let _ = Const::<{A}>; -} diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr b/src/test/ui/const-generics/transmute-const-param-static-reference.min.stderr index d612e0c35a1..f735be9c24e 100644 --- a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr +++ b/src/test/ui/const-generics/transmute-const-param-static-reference.min.stderr @@ -1,5 +1,5 @@ error: `&'static ()` is forbidden as the type of a const generic parameter - --> $DIR/transmute-const-param-static-reference.rs:1:23 + --> $DIR/transmute-const-param-static-reference.rs:7:23 | LL | struct Const<const P: &'static ()>; | ^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/transmute-const-param-static-reference.rs b/src/test/ui/const-generics/transmute-const-param-static-reference.rs new file mode 100644 index 00000000000..3147d61ec9b --- /dev/null +++ b/src/test/ui/const-generics/transmute-const-param-static-reference.rs @@ -0,0 +1,16 @@ +// revisions: full min +//[full] check-pass + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] + +struct Const<const P: &'static ()>; +//[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter + +fn main() { + const A: &'static () = unsafe { + std::mem::transmute(10 as *const ()) + }; + + let _ = Const::<{A}>; +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs deleted file mode 100644 index 183aa9e5122..00000000000 --- a/src/test/ui/const-ptr/out_of_bounds_read.rs +++ /dev/null @@ -1,16 +0,0 @@ -// error-pattern: any use of this value will cause an error - -#![feature(const_ptr_read)] -#![feature(const_ptr_offset)] - -fn main() { - use std::ptr; - - const DATA: [u32; 1] = [42]; - - const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; - - const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; -} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr deleted file mode 100644 index 6c4092e3e5c..00000000000 --- a/src/test/ui/const-ptr/out_of_bounds_read.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: any use of this value will cause an error - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | -LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 - | - ::: $DIR/out_of_bounds_read.rs:13:5 - | -LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ------------------------------------------------------ - | - = 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> - -error: any use of this value will cause an error - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | -LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL - | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 - | - ::: $DIR/out_of_bounds_read.rs:14:5 - | -LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | -------------------------------------------------------- - | - = 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: any use of this value will cause an error - --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | -LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 - | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - | inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 - | - ::: $DIR/out_of_bounds_read.rs:15:5 - | -LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | -------------------------------------------------------------------- - | - = 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: aborting due to 3 previous errors - diff --git a/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs new file mode 100644 index 00000000000..bdeaa0cd360 --- /dev/null +++ b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs @@ -0,0 +1,20 @@ +// 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); +} diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index 8ae8376ae4a..b33b1475a22 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -6,40 +6,30 @@ const MSG: &str = "hello"; 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 diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index 5637de8b313..3c890f78af7 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,4 +1,4 @@ -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"); @@ -6,118 +6,98 @@ 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`. diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs index 0eb1e3eb94e..6b03e847def 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -8,15 +8,12 @@ use core::panic::PanicInfo; 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() {} diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr index 9971559e33b..2a3ad3ca180 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -1,4 +1,4 @@ -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"); @@ -6,34 +6,28 @@ 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`. diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 92d990f1498..23b847b8f3a 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc_intrinsic_uninit.rs:9:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 6d63233997d..ff21a31c9c2 100644 --- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc_intrinsic_uninit.rs:9:1 | LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index 0c520165496..d34ac773da2 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -10,7 +10,7 @@ LL | const BAR: usize = [5, 6, 7][T::BOO]; = 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 diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index cf82d1eef3e..dd8d6bf839a 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -10,7 +10,7 @@ LL | const MAX: u8 = A::MAX + B::MAX; = 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 diff --git a/src/test/ui/consts/const-eval/issue-85155.rs b/src/test/ui/consts/const-eval/issue-85155.rs new file mode 100644 index 00000000000..c3216d53d05 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85155.rs @@ -0,0 +1,21 @@ +// 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 +} diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr new file mode 100644 index 00000000000..c36d7c17215 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85155.stderr @@ -0,0 +1,15 @@ +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`. diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs index f76440298b3..dd18a98035b 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -9,8 +9,7 @@ struct PrintName; 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() { diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr index d1f067df848..e186240f53a 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -1,4 +1,4 @@ -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!(); @@ -6,21 +6,14 @@ 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`. diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs index c5139c575b1..71b489d828c 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -1,15 +1,11 @@ -// 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 } diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr index 2217bf1e05a..2254c3dcfdf 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-never-type.stderr @@ -1,26 +1,13 @@ -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`. diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr index 2274366fa21..4abc6a479a3 100644 --- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001 at .<enum-tag>, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:42:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000 at .<enum-tag>, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -46,7 +46,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -90,7 +90,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:77:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -101,7 +101,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:79:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -112,7 +112,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:87:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -123,7 +123,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:92:1 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -134,7 +134,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:94:1 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr index 29d97962f32..1716f5b05b7 100644 --- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000001 at .<enum-tag>, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:27:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:42:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000000 at .<enum-tag>, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -46,7 +46,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -90,7 +90,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:77:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -101,7 +101,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:79:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { @@ -112,7 +112,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:87:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -123,7 +123,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:92:1 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -134,7 +134,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:94:1 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr new file mode 100644 index 00000000000..941f08bfd8d --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -0,0 +1,52 @@ +error: any use of this value will cause an error + --> $DIR/ub-incorrect-vtable.rs:19:14 + | +LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait = +LL | | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__- + | | + | invalid vtable: alignment `1000` is not a power of 2 + | + = 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> + +error: any use of this value will cause an error + --> $DIR/ub-incorrect-vtable.rs:25:14 + | +LL | / const INVALID_VTABLE_SIZE: &dyn Trait = +LL | | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__- + | | + | invalid vtable: size is bigger than largest supported object + | + = 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]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:36:1 + | +LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = +LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; + | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:41:1 + | +LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = +LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; + | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + } + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr new file mode 100644 index 00000000000..ceed6f8268d --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -0,0 +1,52 @@ +error: any use of this value will cause an error + --> $DIR/ub-incorrect-vtable.rs:19:14 + | +LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait = +LL | | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__- + | | + | invalid vtable: alignment `1000` is not a power of 2 + | + = 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> + +error: any use of this value will cause an error + --> $DIR/ub-incorrect-vtable.rs:25:14 + | +LL | / const INVALID_VTABLE_SIZE: &dyn Trait = +LL | | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__- + | | + | invalid vtable: size is bigger than largest supported object + | + = 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]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:36:1 + | +LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = +LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; + | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:41:1 + | +LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = +LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; + | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + } + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs new file mode 100644 index 00000000000..7c514e804e0 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -0,0 +1,46 @@ +// This test contains code with incorrect vtables in a const context: +// - from issue 86132: a trait object with invalid alignment caused an ICE in const eval, and now +// triggers an error +// - a similar test that triggers a previously-untested const UB error: emitted close to the above +// error, it checks the correctness of the size +// +// As is, this code will only hard error when the constants are used, and the errors are emitted via +// the `#[allow]`-able `const_err` lint. However, if the transparent wrapper technique to prevent +// reborrows is used -- from `ub-wide-ptr.rs` -- these two errors reach validation and would trigger +// ICEs as tracked by #86193. So we also use the transparent wrapper to verify proper validation +// errors are emitted instead of ICEs. + +// stderr-per-bitwidth +// normalize-stderr-test "alloc\d+" -> "allocN" + +trait Trait {} + +const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; +//~^ ERROR any use of this value will cause an error +//~| WARNING this was previously accepted by the compiler +//~| invalid vtable: alignment `1000` is not a power of 2 + +const INVALID_VTABLE_SIZE: &dyn Trait = + unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; +//~^ ERROR any use of this value will cause an error +//~| WARNING this was previously accepted by the compiler +//~| invalid vtable: size is bigger than largest supported object + +#[repr(transparent)] +struct W<T>(T); + +// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn +fn drop_me(_: *mut usize) {} + +const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| invalid vtable: alignment `1000` is not a power of 2 + +const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = + unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; +//~^^ ERROR it is undefined behavior to use this value +//~| invalid vtable: size is bigger than largest supported object + +fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr b/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr index c13271a1e5e..df02bdaa33c 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-int-array.32bit.stderr @@ -8,7 +8,7 @@ LL | | [ ... | LL | | ] LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [0] + | |__^ type validation failed at [0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { @@ -25,7 +25,7 @@ LL | | mem::transmute( ... | LL | | ) LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [1] + | |__^ type validation failed at [1]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { @@ -42,7 +42,7 @@ LL | | mem::transmute( ... | LL | | ) LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [2] + | |__^ type validation failed at [2]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr b/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr index c13271a1e5e..df02bdaa33c 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-int-array.64bit.stderr @@ -8,7 +8,7 @@ LL | | [ ... | LL | | ] LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [0] + | |__^ type validation failed at [0]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { @@ -25,7 +25,7 @@ LL | | mem::transmute( ... | LL | | ) LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [1] + | |__^ type validation failed at [1]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { @@ -42,7 +42,7 @@ LL | | mem::transmute( ... | LL | | ) LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at [2] + | |__^ type validation failed at [2]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 12, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-int-array.rs b/src/test/ui/consts/const-eval/ub-int-array.rs index 635cbb8cef6..7e0fb33bc11 100644 --- a/src/test/ui/consts/const-eval/ub-int-array.rs +++ b/src/test/ui/consts/const-eval/ub-int-array.rs @@ -13,7 +13,7 @@ union MaybeUninit<T: Copy> { const UNINIT_INT_0: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed: encountered uninitialized bytes at [0] +//~| type validation failed at [0]: encountered uninitialized bytes [ MaybeUninit { uninit: () }.init, 1, @@ -22,7 +22,7 @@ const UNINIT_INT_0: [u32; 3] = unsafe { }; const UNINIT_INT_1: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed: encountered uninitialized bytes at [1] +//~| type validation failed at [1]: encountered uninitialized bytes mem::transmute( [ 0u8, @@ -42,7 +42,7 @@ const UNINIT_INT_1: [u32; 3] = unsafe { }; const UNINIT_INT_2: [u32; 3] = unsafe { //~^ ERROR it is undefined behavior to use this value -//~| type validation failed: encountered uninitialized bytes at [2] +//~| type validation failed at [2]: encountered uninitialized bytes mem::transmute( [ 0u8, diff --git a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr index ce8ab632fcf..b68b9d6a180 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr @@ -56,7 +56,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:34:1 | LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr index 3f49a262ae4..687d96a1831 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr @@ -56,7 +56,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:34:1 | LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 1, align: 1) { diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr index d4a61a46319..bae44a42464 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:36:1 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr index 17da7c25bac..697ff0a55ec 100644 --- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:33:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:36:1 | LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr index 4155a8a2ef9..350bd941939 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr @@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 0, align: 1) {} diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr index def795c7f56..13a4fde0830 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr @@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 0, align: 1) {} diff --git a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr index 33251535be9..17a96386f4b 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -6,7 +6,7 @@ LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; LL | | let another_var = 13; LL | | move || { let _ = bad_ref; let _ = another_var; } LL | | }; - | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)> + | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr index de6033702ae..11922e32ae1 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -6,7 +6,7 @@ LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; LL | | let another_var = 13; LL | | move || { let _ = bad_ref; let _ = another_var; } LL | | }; - | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)> + | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index c69674a6721..f0934418a9b 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:40:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:52:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:55:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -138,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -149,7 +149,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:87:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -160,7 +160,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:90:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -186,7 +186,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -197,7 +197,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:108:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:111:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -252,7 +252,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:119:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -263,7 +263,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index bb95343a786..0bb8c17ac82 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:40:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:52:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:55:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -138,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:81:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -149,7 +149,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:87:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -160,7 +160,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:90:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -186,7 +186,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -197,7 +197,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:108:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:111:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -252,7 +252,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:119:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -263,7 +263,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:123:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index 6d44b3c8b28..b1ab03400c1 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -16,7 +16,7 @@ LL | / const FIELD_PATH: Struct = Struct { LL | | a: 42, LL | | b: unsafe { UNION.field3 }, LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes + | |__^ type validation failed at .b: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -33,7 +33,7 @@ LL | | unsafe { UNION.field3 }, ... | LL | | a: 42, LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at .b[1] + | |__^ type validation failed at .b[1]: encountered uninitialized bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 40, align: 8) { diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index 10820986fa7..9bc63d9328c 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,8 +2,7 @@ #[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(); diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr index 79fdd05be30..b41d786169b 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.stderr +++ b/src/test/ui/consts/const-eval/unwind-abort.stderr @@ -1,4 +1,4 @@ -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!() @@ -6,15 +6,13 @@ 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`. diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index e25abab7e37..ae9b9bfd281 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -23,7 +23,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:18:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 0, align: 1) {} diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index e25abab7e37..ae9b9bfd281 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -23,7 +23,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:18:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 0, align: 1) {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs index 1ce78147970..031e67a1e3c 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -9,5 +9,5 @@ fn main() { 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 } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr index b643ecc0ce8..c6077da768b 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr @@ -1,12 +1,4 @@ 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 | LL | let a: [u8; foo()]; @@ -14,6 +6,6 @@ LL | let a: [u8; foo()]; | = 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`. diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.rs b/src/test/ui/consts/const-needs_drop-monomorphic.rs new file mode 100644 index 00000000000..9f66e3cfa23 --- /dev/null +++ b/src/test/ui/consts/const-needs_drop-monomorphic.rs @@ -0,0 +1,17 @@ +// Check that evaluation of needs_drop<T> fails when T is not monomorphic. +#![feature(const_generics)] +#![allow(const_evaluatable_unchecked)] +#![allow(incomplete_features)] + +struct Bool<const B: bool> {} +impl Bool<true> { + fn assert() {} +} +fn f<T>() { + Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + //~^ ERROR no function or associated item named `assert` found + //~| ERROR constant expression depends on a generic parameter +} +fn main() { + f::<u32>(); +} diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.stderr b/src/test/ui/consts/const-needs_drop-monomorphic.stderr new file mode 100644 index 00000000000..0770d06e15b --- /dev/null +++ b/src/test/ui/consts/const-needs_drop-monomorphic.stderr @@ -0,0 +1,20 @@ +error[E0599]: no function or associated item named `assert` found for struct `Bool<{ std::mem::needs_drop::<T>() }>` in the current scope + --> $DIR/const-needs_drop-monomorphic.rs:11:46 + | +LL | struct Bool<const B: bool> {} + | -------------------------- function or associated item `assert` not found for this +... +LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + | ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds + +error: constant expression depends on a generic parameter + --> $DIR/const-needs_drop-monomorphic.rs:11:5 + | +LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/consts/const-unwrap.stderr b/src/test/ui/consts/const-unwrap.stderr index 0100dce5a96..95f4711cb65 100644 --- a/src/test/ui/consts/const-unwrap.stderr +++ b/src/test/ui/consts/const-unwrap.stderr @@ -1,4 +1,4 @@ -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"), @@ -13,10 +13,8 @@ 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`. diff --git a/src/test/ui/consts/const_fn_unsize.gated.stderr b/src/test/ui/consts/const_fn_unsize.gated.stderr deleted file mode 100644 index 8a65c274ca9..00000000000 --- a/src/test/ui/consts/const_fn_unsize.gated.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/const_fn_unsize.rs:16:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const_fn_unsize.rs b/src/test/ui/consts/const_fn_unsize.rs index 0cab3b0a031..01da57320c2 100644 --- a/src/test/ui/consts/const_fn_unsize.rs +++ b/src/test/ui/consts/const_fn_unsize.rs @@ -1,16 +1,21 @@ -// gate-test-const_fn_unsize - -// revisions: stock gated - -#![feature(rustc_attrs)] -#![cfg_attr(gated, feature(const_fn_unsize))] +// run-pass +#![feature(slice_ptr_len)] use std::ptr::NonNull; +#[allow(unused)] const fn test() { let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>; - //[stock]~^ unsizing cast } -#[rustc_error] -fn main() {} //[gated]~ fatal error triggered by #[rustc_error] +// Regression test for #75118. +pub const fn dangling_slice<T>() -> NonNull<[T]> { + NonNull::<[T; 1]>::dangling() +} + +const C: NonNull<[i32]> = dangling_slice(); + +fn main() { + assert_eq!(C.as_ptr(), NonNull::<[i32; 1]>::dangling().as_ptr() as *mut _); + assert_eq!(C.as_ptr().len(), 1); +} diff --git a/src/test/ui/consts/const_fn_unsize.stock.stderr b/src/test/ui/consts/const_fn_unsize.stock.stderr deleted file mode 100644 index cc746d4f175..00000000000 --- a/src/test/ui/consts/const_fn_unsize.stock.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/const_fn_unsize.rs:11:14 - | -LL | let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/assert.const_panic.stderr b/src/test/ui/consts/control-flow/assert.const_panic.stderr index 665b4240011..8e1a2b5eb46 100644 --- a/src/test/ui/consts/control-flow/assert.const_panic.stderr +++ b/src/test/ui/consts/control-flow/assert.const_panic.stderr @@ -1,4 +1,4 @@ -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); @@ -6,10 +6,8 @@ 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`. diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs index a21f28604bd..90017fee193 100644 --- a/src/test/ui/consts/control-flow/assert.rs +++ b/src/test/ui/consts/control-flow/assert.rs @@ -10,6 +10,5 @@ const _: () = assert!(true); 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() {} diff --git a/src/test/ui/consts/copy-intrinsic.rs b/src/test/ui/consts/copy-intrinsic.rs deleted file mode 100644 index 9dc595f37fa..00000000000 --- a/src/test/ui/consts/copy-intrinsic.rs +++ /dev/null @@ -1,45 +0,0 @@ -// ignore-tidy-linelength -#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)] -use std::{ptr, mem}; - -const COPY_ZERO: () = unsafe { - // Since we are not copying anything, this should be allowed. - let src = (); - let mut dst = (); - ptr::copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0); -}; - -const COPY_OOB_1: () = unsafe { - let mut x = 0i32; - let dangle = (&mut x as *mut i32).wrapping_add(10); - // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs. - ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR any use of this value will cause an error - //~| memory access failed: pointer must be in-bounds - //~| previously accepted -}; -const COPY_OOB_2: () = unsafe { - let x = 0i32; - let dangle = (&x as *const i32).wrapping_add(10); - // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs. - ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR any use of this value will cause an error - //~| memory access failed: pointer must be in-bounds - //~| previously accepted -}; - -const COPY_SIZE_OVERFLOW: () = unsafe { - let x = 0; - let mut y = 0; - ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error - //~| overflow computing total size of `copy` - //~| previously accepted -}; -const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { - let x = 0; - let mut y = 0; - ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error - //~| overflow computing total size of `copy_nonoverlapping` - //~| previously accepted -}; - -fn main() { -} diff --git a/src/test/ui/consts/copy-intrinsic.stderr b/src/test/ui/consts/copy-intrinsic.stderr deleted file mode 100644 index 2736cdeac69..00000000000 --- a/src/test/ui/consts/copy-intrinsic.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error: any use of this value will cause an error - --> $DIR/copy-intrinsic.rs:16:5 - | -LL | / const COPY_OOB_1: () = unsafe { -LL | | let mut x = 0i32; -LL | | let dangle = (&mut x as *mut i32).wrapping_add(10); -LL | | // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs. -LL | | ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4 -LL | | -LL | | -LL | | }; - | |__- - | - = 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> - -error: any use of this value will cause an error - --> $DIR/copy-intrinsic.rs:24:5 - | -LL | / const COPY_OOB_2: () = unsafe { -LL | | let x = 0i32; -LL | | let dangle = (&x as *const i32).wrapping_add(10); -LL | | // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs. -LL | | ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4 -LL | | -LL | | -LL | | }; - | |__- - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> - -error: any use of this value will cause an error - --> $DIR/copy-intrinsic.rs:32:5 - | -LL | / const COPY_SIZE_OVERFLOW: () = unsafe { -LL | | let x = 0; -LL | | let mut y = 0; -LL | | ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` -LL | | -LL | | -LL | | }; - | |__- - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> - -error: any use of this value will cause an error - --> $DIR/copy-intrinsic.rs:39:5 - | -LL | / const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe { -LL | | let x = 0; -LL | | let mut y = 0; -LL | | ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` -LL | | -LL | | -LL | | }; - | |__- - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/consts/issue-79690.64bit.stderr b/src/test/ui/consts/issue-79690.64bit.stderr index 2639bc4812c..57e62d0b90f 100644 --- a/src/test/ui/consts/issue-79690.64bit.stderr +++ b/src/test/ui/consts/issue-79690.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-79690.rs:30:1 | LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer at .1.<deref>.size.foo, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/issue-83182.32bit.stderr b/src/test/ui/consts/issue-83182.32bit.stderr index 3352f0e1724..57f1e43d88c 100644 --- a/src/test/ui/consts/issue-83182.32bit.stderr +++ b/src/test/ui/consts/issue-83182.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-83182.rs:5:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/issue-83182.64bit.stderr b/src/test/ui/consts/issue-83182.64bit.stderr index b7570720748..f5aaec91b01 100644 --- a/src/test/ui/consts/issue-83182.64bit.stderr +++ b/src/test/ui/consts/issue-83182.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-83182.rs:5:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/issue-83182.rs b/src/test/ui/consts/issue-83182.rs index 55a0722e5dd..f714fd6e8f9 100644 --- a/src/test/ui/consts/issue-83182.rs +++ b/src/test/ui/consts/issue-83182.rs @@ -4,5 +4,5 @@ use std::mem; struct MyStr(str); const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; //~^ ERROR: it is undefined behavior to use this value -//~| type validation failed: encountered a pointer in `str` +//~| type validation failed at .<deref>.0: encountered a pointer in `str` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index e46127c36bf..b7904e6841b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -133,13 +133,13 @@ const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~^ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` -//~| ERROR unsizing cast -//~| ERROR unsizing cast const fn no_unsafe() { unsafe {} } const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } -//~^ ERROR unsizing cast +//~^ ERROR trait bounds other than `Sized` +//~| ERROR trait bounds other than `Sized` +//~| ERROR trait bounds other than `Sized` const fn no_fn_ptrs(_x: fn()) {} //~^ ERROR function pointer diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index e6ce7e12520..d31d4121936 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -288,32 +288,32 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:134:63 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:41 | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^^ +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:134:63 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:42 | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^^ +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:141:42 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:42 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable error[E0658]: function pointers cannot appear in constant functions --> $DIR/min_const_fn.rs:144:21 diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 4a22ef2dffd..6ca1e59b3af 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) { //~^ ERROR trait bounds other than `Sized` } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } -//~^ ERROR unsizing cast +//~^ ERROR trait bounds other than `Sized` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index cf635d65699..ce844a2f071 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -7,14 +7,14 @@ LL | x.0.field; = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index 62126ef2bab..5374088028b 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | / const MUH: Meh = Meh { LL | | x: &UnsafeCell::new(42), LL | | }; - | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref> + | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -15,7 +15,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:27:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 606184e5732..7c4842db24c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value LL | / const MUH: Meh = Meh { LL | | x: &UnsafeCell::new(42), LL | | }; - | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref> + | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -15,7 +15,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/mutable_references_err.rs:27:1 | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/std/alloc.32bit.stderr b/src/test/ui/consts/std/alloc.32bit.stderr index bb9ccbba376..67bc3202c10 100644 --- a/src/test/ui/consts/std/alloc.32bit.stderr +++ b/src/test/ui/consts/std/alloc.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:8:1 | LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/std/alloc.64bit.stderr b/src/test/ui/consts/std/alloc.64bit.stderr index 2c891b1d79c..ec89dec272d 100644 --- a/src/test/ui/consts/std/alloc.64bit.stderr +++ b/src/test/ui/consts/std/alloc.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/alloc.rs:8:1 | LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs deleted file mode 100644 index af6bc2d85fd..00000000000 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Regression test for #75118. - -use std::ptr::NonNull; - -pub const fn dangling_slice<T>() -> NonNull<[T]> { - NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts to types besides slices -} - -fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr deleted file mode 100644 index 79691cddfb4..00000000000 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/unsizing-cast-non-null.rs:6:5 - | -LL | NonNull::<[T; 0]>::dangling() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/validate_never_arrays.32bit.stderr b/src/test/ui/consts/validate_never_arrays.32bit.stderr index 2d1bba391e8..e2f5175bf0a 100644 --- a/src/test/ui/consts/validate_never_arrays.32bit.stderr +++ b/src/test/ui/consts/validate_never_arrays.32bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:4:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:8:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/src/test/ui/consts/validate_never_arrays.64bit.stderr b/src/test/ui/consts/validate_never_arrays.64bit.stderr index dd677f1b21e..c145eddef57 100644 --- a/src/test/ui/consts/validate_never_arrays.64bit.stderr +++ b/src/test/ui/consts/validate_never_arrays.64bit.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:4:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:8:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!` | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/src/test/ui/deduplicate-diagnostics.duplicate.stderr b/src/test/ui/deduplicate-diagnostics.duplicate.stderr index 3b100b59995..cd4700c7a7c 100644 --- a/src/test/ui/deduplicate-diagnostics.duplicate.stderr +++ b/src/test/ui/deduplicate-diagnostics.duplicate.stderr @@ -22,12 +22,6 @@ error[E0452]: malformed lint attribute input LL | #[deny("literal")] | ^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute input - --> $DIR/deduplicate-diagnostics.rs:8:8 - | -LL | #[deny("literal")] - | ^^^^^^^^^ bad attribute argument - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0452`. diff --git a/src/test/ui/deduplicate-diagnostics.rs b/src/test/ui/deduplicate-diagnostics.rs index c5d41ff2fda..7d1c4f5f838 100644 --- a/src/test/ui/deduplicate-diagnostics.rs +++ b/src/test/ui/deduplicate-diagnostics.rs @@ -7,5 +7,4 @@ struct S; #[deny("literal")] //~ ERROR malformed lint attribute input //[duplicate]~| ERROR malformed lint attribute input - //[duplicate]~| ERROR malformed lint attribute input fn main() {} diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.rs b/src/test/ui/dep-graph/dep-graph-check-attr.rs index 1026efc1b1d..a45bf24f8c1 100644 --- a/src/test/ui/dep-graph/dep-graph-check-attr.rs +++ b/src/test/ui/dep-graph/dep-graph-check-attr.rs @@ -5,7 +5,7 @@ #![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 diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.stderr b/src/test/ui/dep-graph/dep-graph-check-attr.stderr index 945a4237c12..46f4e4358cf 100644 --- a/src/test/ui/dep-graph/dep-graph-check-attr.stderr +++ b/src/test/ui/dep-graph/dep-graph-check-attr.stderr @@ -1,7 +1,7 @@ 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 diff --git a/src/test/ui/deprecation/deprecation-lint.rs b/src/test/ui/deprecation/deprecation-lint.rs index b6c791c15fd..35e42a6857f 100644 --- a/src/test/ui/deprecation/deprecation-lint.rs +++ b/src/test/ui/deprecation/deprecation-lint.rs @@ -430,6 +430,24 @@ mod this_crate2 { // 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() {} diff --git a/src/test/ui/error-codes/E0107.rs b/src/test/ui/error-codes/E0107.rs index f7f6afa860e..840700c9cc6 100644 --- a/src/test/ui/error-codes/E0107.rs +++ b/src/test/ui/error-codes/E0107.rs @@ -1,5 +1,7 @@ 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, @@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> { 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() {} diff --git a/src/test/ui/error-codes/E0107.stderr b/src/test/ui/error-codes/E0107.stderr index 299776b08f2..3c7aa6de541 100644 --- a/src/test/ui/error-codes/E0107.stderr +++ b/src/test/ui/error-codes/E0107.stderr @@ -1,5 +1,5 @@ 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 @@ -17,7 +17,7 @@ LL | buzz: Buzz<'a, 'a>, | ^^^^ 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 @@ -25,13 +25,13 @@ LL | bar: Bar<'a>, | 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 @@ -44,6 +44,90 @@ note: struct defined here, with 1 lifetime parameter: `'a` 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`. diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index ad854837ae5..246f69558ff 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -14,7 +14,7 @@ LL | static BAR: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&str` + | help: replace with the correct type: `&str` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0452.rs b/src/test/ui/error-codes/E0452.rs index 4e5a6c93014..5066cd99be9 100644 --- a/src/test/ui/error-codes/E0452.rs +++ b/src/test/ui/error-codes/E0452.rs @@ -2,7 +2,5 @@ //~| ERROR E0452 //~| ERROR E0452 //~| ERROR E0452 - //~| ERROR E0452 - //~| ERROR E0452 fn main() { } diff --git a/src/test/ui/error-codes/E0452.stderr b/src/test/ui/error-codes/E0452.stderr index 30c11e3274e..f67b740ffe2 100644 --- a/src/test/ui/error-codes/E0452.stderr +++ b/src/test/ui/error-codes/E0452.stderr @@ -22,18 +22,6 @@ error[E0452]: malformed lint attribute input LL | #![allow(foo = "")] | ^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute input - --> $DIR/E0452.rs:1:10 - | -LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/E0452.rs:1:10 - | -LL | #![allow(foo = "")] - | ^^^^^^^^ bad attribute argument - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0452`. diff --git a/src/test/ui/error-codes/E0453.rs b/src/test/ui/error-codes/E0453.rs index 6fa8dd9717f..ca9573c5b46 100644 --- a/src/test/ui/error-codes/E0453.rs +++ b/src/test/ui/error-codes/E0453.rs @@ -3,6 +3,5 @@ #[allow(non_snake_case)] //~^ ERROR allow(non_snake_case) incompatible //~| ERROR allow(non_snake_case) incompatible -//~| ERROR allow(non_snake_case) incompatible fn main() { } diff --git a/src/test/ui/error-codes/E0453.stderr b/src/test/ui/error-codes/E0453.stderr index 21c43cc052e..6d60dc84c21 100644 --- a/src/test/ui/error-codes/E0453.stderr +++ b/src/test/ui/error-codes/E0453.stderr @@ -16,15 +16,6 @@ LL | LL | #[allow(non_snake_case)] | ^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(non_snake_case) incompatible with previous forbid - --> $DIR/E0453.rs:3:9 - | -LL | #![forbid(non_snake_case)] - | -------------- `forbid` level set here -LL | -LL | #[allow(non_snake_case)] - | ^^^^^^^^^^^^^^ overruled by previous forbid - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/error-codes/E0602.stderr b/src/test/ui/error-codes/E0602.stderr index 70137cb1662..2b372263345 100644 --- a/src/test/ui/error-codes/E0602.stderr +++ b/src/test/ui/error-codes/E0602.stderr @@ -6,10 +6,6 @@ error[E0602]: unknown lint: `bogus` | = note: requested on the command line with `-D bogus` -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0602`. diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index 43269c095d6..6314e7a3a8a 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -8,7 +8,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $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 diff --git a/src/test/ui/extern/external-doc-error.rs b/src/test/ui/extern/external-doc-error.rs deleted file mode 100644 index 4e89f7464da..00000000000 --- a/src/test/ui/extern/external-doc-error.rs +++ /dev/null @@ -1,31 +0,0 @@ -// 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() {} diff --git a/src/test/ui/extern/external-doc-error.stderr b/src/test/ui/extern/external-doc-error.stderr deleted file mode 100644 index b180cd66c52..00000000000 --- a/src/test/ui/extern/external-doc-error.stderr +++ /dev/null @@ -1,38 +0,0 @@ -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 - diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr index 04efea0b230..df0de7a9590 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr @@ -58,6 +58,14 @@ LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrins = 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 | @@ -68,49 +76,41 @@ LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } = 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 diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.rs b/src/test/ui/feature-gates/feature-gate-external_doc.rs deleted file mode 100644 index 4e6e293846c..00000000000 --- a/src/test/ui/feature-gates/feature-gate-external_doc.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental - //~| ERROR: `#[doc(include)]` is experimental -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr deleted file mode 100644 index bd2aefe90c1..00000000000 --- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr +++ /dev/null @@ -1,21 +0,0 @@ -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`. diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.rs b/src/test/ui/feature-gates/feature-gate-lint-reasons.rs index b124e9b2f4d..7756074e235 100644 --- a/src/test/ui/feature-gates/feature-gate-lint-reasons.rs +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.rs @@ -1,6 +1,5 @@ #![warn(nonstandard_style, reason = "the standard should be respected")] //~^ ERROR lint reasons are experimental //~| ERROR lint reasons are experimental -//~| ERROR lint reasons are experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr index a7d5ea6b937..12793c7a28f 100644 --- a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr @@ -16,15 +16,6 @@ LL | #![warn(nonstandard_style, reason = "the standard should be respected")] = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information = help: add `#![feature(lint_reasons)]` to the crate attributes to enable -error[E0658]: lint reasons are experimental - --> $DIR/feature-gate-lint-reasons.rs:1:28 - | -LL | #![warn(nonstandard_style, reason = "the standard should be respected")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information - = help: add `#![feature(lint_reasons)]` to the crate attributes to enable - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs deleted file mode 100644 index f6a92b0d0bf..00000000000 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.rs +++ /dev/null @@ -1,10 +0,0 @@ -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() {} diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr deleted file mode 100644 index c2ec7ae16a3..00000000000 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr +++ /dev/null @@ -1,18 +0,0 @@ -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 - diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs new file mode 100644 index 00000000000..2e05acbfa17 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs @@ -0,0 +1,27 @@ +fn main() { + // destructure through a qualified path + let <Foo as A>::Assoc { br } = StructStruct { br: 2 }; + //~^ ERROR usage of qualified paths in this context is experimental + let _ = <Foo as A>::Assoc { br: 2 }; + //~^ ERROR usage of qualified paths in this context is experimental + let <E>::V(..) = E::V(0); + //~^ ERROR usage of qualified paths in this context is experimental +} + +struct StructStruct { + br: i8, +} + +struct Foo; + +trait A { + type Assoc; +} + +impl A for Foo { + type Assoc = StructStruct; +} + +enum E { + V(u8) +} diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr new file mode 100644 index 00000000000..b49cc40800f --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr @@ -0,0 +1,30 @@ +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/feature-gate-more-qualified-paths.rs:3:9 + | +LL | let <Foo as A>::Assoc { br } = StructStruct { br: 2 }; + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/feature-gate-more-qualified-paths.rs:5:13 + | +LL | let _ = <Foo as A>::Assoc { br: 2 }; + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/feature-gate-more-qualified-paths.rs:7:9 + | +LL | let <E>::V(..) = E::V(0); + | ^^^^^^ + | + = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs index 518aa20dd68..518aa20dd68 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr index dbee5f316b0..dbee5f316b0 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs new file mode 100644 index 00000000000..33f9c539313 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs @@ -0,0 +1,8 @@ +// gate-test-raw_dylib +// only-windows-gnu +#[link(name = "foo", kind = "raw-dylib")] +//~^ ERROR: kind="raw-dylib" is unstable +//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr new file mode 100644 index 00000000000..14dfadf4126 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr @@ -0,0 +1,18 @@ +warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu + --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: kind="raw-dylib" is unstable + --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + = help: add `#![feature(raw_dylib)]` to the crate attributes to enable + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs index 29edd0f9ef9..49de24ea9ab 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs @@ -1,3 +1,5 @@ +// gate-test-raw_dylib +// only-windows-msvc #[link(name = "foo", kind = "raw-dylib")] //~^ ERROR: kind="raw-dylib" is unstable extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr index a670b6c6c2a..11988080812 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr @@ -1,5 +1,5 @@ error[E0658]: kind="raw-dylib" is unstable - --> $DIR/feature-gate-raw-dylib.rs:1:1 + --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1 | LL | #[link(name = "foo", kind = "raw-dylib")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr index 0bd3dbf6863..3afbea07931 100644 --- a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45729-unsafe-in-generator.rs:5:9 + --> $DIR/issue-45729-unsafe-in-generator.rs:8:9 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs index 638a1994bb5..379c36d2ca3 100644 --- a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(generators)] fn main() { diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr new file mode 100644 index 00000000000..10d768f19fc --- /dev/null +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45729-unsafe-in-generator.rs:8:9 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 96a8d6d70e0..46d27baa545 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -29,11 +29,11 @@ LL | require_send(send_gen); | = 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 `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]` = note: required because it appears within the type `impl Generator` = note: required because it appears within the type `impl Generator` = note: required because it appears within the type `{impl Generator, ()}` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl Generator, ()}]` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 2384ed3d249..448cb2a043a 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -9,7 +9,7 @@ LL | assert_send(|| { | = help: the trait `Sync` is not implemented for `Cell<i32>` = note: required because of the requirements on the impl of `Send` for `&Cell<i32>` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6]` error: generator cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 @@ -20,7 +20,7 @@ LL | fn assert_sync<T: Sync>(_: T) {} LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>` + = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6]`, the trait `Sync` is not implemented for `Cell<i32>` note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | diff --git a/src/test/ui/generator/static-mut-reference-across-yield.rs b/src/test/ui/generator/static-mut-reference-across-yield.rs index 2926bba9978..0fa6d9cdc77 100644 --- a/src/test/ui/generator/static-mut-reference-across-yield.rs +++ b/src/test/ui/generator/static-mut-reference-across-yield.rs @@ -1,4 +1,7 @@ // build-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #![feature(generators)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs index ec2ed9926e2..272cd361968 100644 --- a/src/test/ui/generics/wrong-number-of-args.rs +++ b/src/test/ui/generics/wrong-number-of-args.rs @@ -66,6 +66,12 @@ mod lifetime_and_type { //~| 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 { diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 17a924cedad..4e921db8c25 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -213,14 +213,42 @@ help: consider introducing a named lifetime parameter 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>; | ^^ - - @@ -230,7 +258,7 @@ LL | type A = Ty<A, B>; | ^^^^^^^^ 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 @@ -238,7 +266,7 @@ LL | type B = Ty<usize>; | 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>; | ^^ - - @@ -248,7 +276,7 @@ LL | type B = Ty<usize, B>; | ^^^ 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 @@ -256,19 +284,19 @@ LL | type E = Ty<usize, String, char, f64>; | 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>; | ^^ - - @@ -278,7 +306,7 @@ LL | type F = Ty<A, B>; | ^^^^ 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 @@ -286,13 +314,13 @@ LL | type A = Box<dyn NonGeneric<usize>>; | 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 @@ -303,7 +331,7 @@ LL | type B<'a> = Box<dyn GenericLifetime<'a>>; | ^^^^ ^^^^^^^^^^^^^^^^^^^ 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 @@ -311,19 +339,19 @@ LL | type C = Box<dyn GenericLifetime<'static, 'static>>; | 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> { | ^^^^^^^^^^^ - @@ -333,7 +361,7 @@ LL | type D = Box<dyn 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 @@ -341,13 +369,13 @@ LL | type E = Box<dyn GenericType<String, usize>>; | 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 @@ -358,13 +386,13 @@ LL | type F<'a> = Box<dyn GenericLifetime<'a>>; | ^^^^ ^^ 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> { | ^^^^^^^^^^^ - @@ -374,7 +402,7 @@ LL | type G = Box<dyn 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 @@ -382,13 +410,13 @@ LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>; | 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 @@ -399,7 +427,7 @@ LL | type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>; | ^^^^ ^^^ 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 @@ -407,13 +435,13 @@ LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>; | 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 @@ -424,7 +452,7 @@ LL | type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>; | ^^^^ ^^^ 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 @@ -432,19 +460,19 @@ LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>; | 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> { | ^^^^^^^^^^^^^ - @@ -454,7 +482,7 @@ LL | type A = Box<dyn GenericTypeAT<A, AssocTy=()>>; | ^^ 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 @@ -462,13 +490,13 @@ LL | type B = 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 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 @@ -476,19 +504,19 @@ LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>; | 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> { | ^^^^^^^^^^^^^ - @@ -498,7 +526,7 @@ LL | type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>; | ^^^ 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 @@ -509,13 +537,13 @@ LL | type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>; | ^^^^ ^^^ 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> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -525,13 +553,13 @@ LL | type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>; | ^^ 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> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -541,7 +569,7 @@ LL | type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>; | ^^^ 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 @@ -549,19 +577,19 @@ LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=() | 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> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -571,7 +599,7 @@ LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy | ^^^ 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 @@ -582,7 +610,7 @@ LL | type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>; | ^^^^ ^^^ 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 @@ -593,7 +621,7 @@ LL | type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>> | ^^^^ ^^^ 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 @@ -601,13 +629,13 @@ LL | type E = 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 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 @@ -615,13 +643,13 @@ LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT | 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 @@ -629,13 +657,13 @@ LL | type G = 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:229:26 + --> $DIR/wrong-number-of-args.rs:235:26 | LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -643,13 +671,13 @@ LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As | 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 @@ -657,19 +685,19 @@ LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As | 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> { | ^^^^^^^^^^^^^^^^^ - - @@ -679,7 +707,7 @@ LL | type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>; | ^^^^^ 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 @@ -687,7 +715,7 @@ LL | type B = 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> { | ^^^^^^^^^^^^^^^^^ - - @@ -697,7 +725,7 @@ LL | type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>; | ^^^ 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 @@ -705,13 +733,13 @@ LL | type C = 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[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 @@ -722,7 +750,7 @@ LL | type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>> | ^^^^ ^^^^^^^ 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 @@ -730,7 +758,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>; | 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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -740,7 +768,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()> | ^^^^ 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 @@ -751,13 +779,13 @@ LL | type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy= | ^^^^ ^^^^^^^ 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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -767,7 +795,7 @@ LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>; | ^^ 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 @@ -775,7 +803,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()> | 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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -785,13 +813,13 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy | ^^^^ 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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -801,7 +829,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy= | ^^^ 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 @@ -809,7 +837,7 @@ LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy | 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> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -819,7 +847,7 @@ LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass | ^^^^ 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 @@ -835,7 +863,7 @@ LL | type A = HashMap<K, V>; | ^^^^^^^^^^^^^ 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 @@ -853,7 +881,7 @@ LL | type B = HashMap<String, V>; | ^^^ 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 @@ -867,7 +895,7 @@ LL | pub struct HashMap<K, V, S = RandomState> { | ^^^^^^^ 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 @@ -883,7 +911,7 @@ LL | type C = HashMap<'static, K, V>; | ^^^^^^ 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 @@ -897,7 +925,7 @@ LL | pub struct HashMap<K, V, S = RandomState> { | ^^^^^^^ - - - 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 @@ -913,7 +941,7 @@ LL | type E = HashMap<K, V>; | ^^^^ 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 @@ -929,7 +957,7 @@ LL | type A = Result<T, E>; | ^^^^^^^^^^^^ 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 @@ -947,7 +975,7 @@ LL | type B = Result<String, E>; | ^^^ 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 @@ -961,7 +989,7 @@ LL | pub enum Result<T, E> { | ^^^^^^ 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 @@ -977,7 +1005,7 @@ LL | type C = Result<'static, T, E>; | ^^^^^^ 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 @@ -991,7 +1019,7 @@ LL | pub enum Result<T, E> { | ^^^^^^ - - 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 @@ -1006,7 +1034,7 @@ help: add missing 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`. diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs index 238f3fa31ed..45dcb74a6e0 100644 --- a/src/test/ui/impl-trait/example-calendar.rs +++ b/src/test/ui/impl-trait/example-calendar.rs @@ -3,7 +3,6 @@ #![feature(fn_traits, step_trait, - step_trait_ext, unboxed_closures, )] @@ -157,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate { } } -unsafe impl std::iter::Step for NaiveDate { +impl std::iter::Step for NaiveDate { fn steps_between(_: &Self, _: &Self) -> Option<usize> { unimplemented!() } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr index d7a9e5463b3..ff99d037d19 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr @@ -1,5 +1,5 @@ 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))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ 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 diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr index e2d745cdec8..4b23ba81604 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr @@ -1,5 +1,5 @@ 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 diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs index b5adabb7abd..1ead78e02ed 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -1,6 +1,5 @@ // 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))] diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs index 3911769b0c6..41b6a9eb055 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs @@ -3,8 +3,6 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs index 553dea7aa6e..d0277336b25 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs @@ -3,10 +3,8 @@ // 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. @@ -26,4 +24,4 @@ fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> { (a, a) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs index 9d345502aab..b9857b7aa2f 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs @@ -3,10 +3,9 @@ // 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. @@ -28,4 +27,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> { (a, b) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs index c0930ec5944..be455f53350 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs @@ -3,10 +3,8 @@ // 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. @@ -26,4 +24,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { (a, b) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs index ed36bda7db7..7235d89019f 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs @@ -3,8 +3,6 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index 129af80ce4a..8cf89f164b1 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -1,5 +1,5 @@ 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> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs index db1641b0140..3a97624647e 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index b42ff1486f0..a6bc8fec283 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -1,11 +1,11 @@ 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> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index de6d5edcae5..1bcb28120ed 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -1,5 +1,5 @@ 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> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs index 7f9c92f15a2..d4c60a4e892 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} @@ -18,7 +16,7 @@ struct Ordinary<'a>(&'a u8); // 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: // diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 254643c406c..a219e747415 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -1,11 +1,11 @@ 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> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs index 3c8682bb62a..c4bcfe5b281 100644 --- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(member_constraints)] - trait MultiRegionTrait<'a, 'b> {} impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {} diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 0f89ec2475c..b9b2ce249f7 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -95,7 +95,7 @@ LL | / move || { LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 @@ -117,7 +117,7 @@ LL | | let x = generator_hold(); LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 diff --git a/src/test/ui/intrinsics/issue-28575.stderr b/src/test/ui/intrinsics/issue-28575.mir.stderr index 66369decf42..c42498390c7 100644 --- a/src/test/ui/intrinsics/issue-28575.stderr +++ b/src/test/ui/intrinsics/issue-28575.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-28575.rs:8:5 + --> $DIR/issue-28575.rs:11:5 | LL | FOO() | ^^^ use of extern static diff --git a/src/test/ui/intrinsics/issue-28575.rs b/src/test/ui/intrinsics/issue-28575.rs index 141136d25b2..410f664f89d 100644 --- a/src/test/ui/intrinsics/issue-28575.rs +++ b/src/test/ui/intrinsics/issue-28575.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(intrinsics)] extern "C" { diff --git a/src/test/ui/intrinsics/issue-28575.thir.stderr b/src/test/ui/intrinsics/issue-28575.thir.stderr new file mode 100644 index 00000000000..c42498390c7 --- /dev/null +++ b/src/test/ui/intrinsics/issue-28575.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28575.rs:11:5 + | +LL | FOO() + | ^^^ 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 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/issue-84297-reifying-copy.rs b/src/test/ui/intrinsics/issue-84297-reifying-copy.rs new file mode 100644 index 00000000000..08ba9ce7ecb --- /dev/null +++ b/src/test/ui/intrinsics/issue-84297-reifying-copy.rs @@ -0,0 +1,9 @@ +// check-pass + +fn main() { + let _unused = if true { + core::ptr::copy::<i32> + } else { + core::ptr::copy_nonoverlapping::<i32> + }; +} diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 4a91198ab9f..72c0d7913e5 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -1,5 +1,7 @@ // 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}`. diff --git a/src/test/ui/issues/issue-11740.rs b/src/test/ui/issues/issue-11740.rs index dc10a205f24..9faeb7770a7 100644 --- a/src/test/ui/issues/issue-11740.rs +++ b/src/test/ui/issues/issue-11740.rs @@ -1,4 +1,6 @@ // check-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck struct Attr { name: String, diff --git a/src/test/ui/issues/issue-14227.stderr b/src/test/ui/issues/issue-14227.mir.stderr index f9cdbe452df..8e7a2514dd6 100644 --- a/src/test/ui/issues/issue-14227.stderr +++ b/src/test/ui/issues/issue-14227.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-14227.rs:4:21 + --> $DIR/issue-14227.rs:7:21 | LL | static CRASH: u32 = symbol; | ^^^^^^ use of extern static diff --git a/src/test/ui/issues/issue-14227.rs b/src/test/ui/issues/issue-14227.rs index a1fde14600a..5f866ec9061 100644 --- a/src/test/ui/issues/issue-14227.rs +++ b/src/test/ui/issues/issue-14227.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { pub static symbol: u32; } diff --git a/src/test/ui/issues/issue-14227.thir.stderr b/src/test/ui/issues/issue-14227.thir.stderr new file mode 100644 index 00000000000..8e7a2514dd6 --- /dev/null +++ b/src/test/ui/issues/issue-14227.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-14227.rs:7:21 + | +LL | static CRASH: u32 = symbol; + | ^^^^^^ 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 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.mir.stderr index 81a91db3711..d7e8c08bb01 100644 --- a/src/test/ui/issues/issue-16538.stderr +++ b/src/test/ui/issues/issue-16538.mir.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-16538.rs:11:27 + --> $DIR/issue-16538.rs:14:27 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*const usize` cannot be shared between threads safely - --> $DIR/issue-16538.rs:11:1 + --> $DIR/issue-16538.rs:14:1 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely @@ -14,7 +14,7 @@ LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); = 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:11:34 + --> $DIR/issue-16538.rs:14:34 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^ use of extern static diff --git a/src/test/ui/issues/issue-16538.rs b/src/test/ui/issues/issue-16538.rs index 7d6eefa5b1e..1e8ecf015c8 100644 --- a/src/test/ui/issues/issue-16538.rs +++ b/src/test/ui/issues/issue-16538.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + mod Y { pub type X = usize; extern "C" { diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr new file mode 100644 index 00000000000..435334c3228 --- /dev/null +++ b/src/test/ui/issues/issue-16538.thir.stderr @@ -0,0 +1,27 @@ +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 + | +LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `*const usize` cannot be shared between threads safely + --> $DIR/issue-16538.rs:14:1 + | +LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `*const usize` + = note: shared static variables must have a type that implements `Sync` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0015, E0133, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index 60027853609..f90e89efb4a 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)` 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; | ^ diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index 823ffc6de6d..47ee544c02a 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Self` as `&dyn Index<usize, Output = <Self as 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>); | ^ diff --git a/src/test/ui/issues/issue-28324.stderr b/src/test/ui/issues/issue-28324.mir.stderr index d7dad992152..aff8bf7927d 100644 --- a/src/test/ui/issues/issue-28324.stderr +++ b/src/test/ui/issues/issue-28324.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-28324.rs:5:24 + --> $DIR/issue-28324.rs:8:24 | LL | pub static BAZ: u32 = *&error_message_count; | ^^^^^^^^^^^^^^^^^^^^ use of extern static diff --git a/src/test/ui/issues/issue-28324.rs b/src/test/ui/issues/issue-28324.rs index f74726e8166..fbe83e325ed 100644 --- a/src/test/ui/issues/issue-28324.rs +++ b/src/test/ui/issues/issue-28324.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { static error_message_count: u32; } diff --git a/src/test/ui/issues/issue-28324.thir.stderr b/src/test/ui/issues/issue-28324.thir.stderr new file mode 100644 index 00000000000..c696c359830 --- /dev/null +++ b/src/test/ui/issues/issue-28324.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28324.rs:8:25 + | +LL | pub static BAZ: u32 = *&error_message_count; + | ^^^^^^^^^^^^^^^^^^^ 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 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index 9f5968399a3..b08fe8c7352 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -2,7 +2,12 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` --> $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 diff --git a/src/test/ui/issues/issue-30123.stderr b/src/test/ui/issues/issue-30123.stderr index bc6731601f0..e9d934332f1 100644 --- a/src/test/ui/issues/issue-30123.stderr +++ b/src/test/ui/issues/issue-30123.stderr @@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st | 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 diff --git a/src/test/ui/issues/issue-39367.rs b/src/test/ui/issues/issue-39367.rs index 8314be3d14c..e7beb8a0392 100644 --- a/src/test/ui/issues/issue-39367.rs +++ b/src/test/ui/issues/issue-39367.rs @@ -1,4 +1,7 @@ // 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) diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr index 09d5594f73f..017dd831f71 100644 --- a/src/test/ui/issues/issue-41880.stderr +++ b/src/test/ui/issues/issue-41880.stderr @@ -1,4 +1,4 @@ -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> { diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr index 321698e7636..9e9cbcf33ae 100644 --- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr @@ -1,5 +1,5 @@ error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -8,13 +8,13 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8 + --> $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:9:38 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -23,7 +23,7 @@ LL | |w: &mut Vec<u32>| { unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 | LL | unsafe { | ------ because it's nested under this `unsafe` block diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs index de275ff701a..ac1cfd62a05 100644 --- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #[deny(unused_unsafe)] fn main() { let mut v = Vec::<i32>::with_capacity(24); diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr new file mode 100644 index 00000000000..9e9cbcf33ae --- /dev/null +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr @@ -0,0 +1,35 @@ +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 + diff --git a/src/test/ui/issues/issue-47412.stderr b/src/test/ui/issues/issue-47412.mir.stderr index aebcbf07463..96e50ba6799 100644 --- a/src/test/ui/issues/issue-47412.stderr +++ b/src/test/ui/issues/issue-47412.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/issue-47412.rs:11:11 + --> $DIR/issue-47412.rs:14:11 | LL | match u.void {} | ^^^^^^ access to union field @@ -7,7 +7,7 @@ LL | match u.void {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-47412.rs:17:11 + --> $DIR/issue-47412.rs:21:11 | LL | match *ptr {} | ^^^^ dereference of raw pointer diff --git a/src/test/ui/issues/issue-47412.rs b/src/test/ui/issues/issue-47412.rs index 2d1ea72280b..d395285eee0 100644 --- a/src/test/ui/issues/issue-47412.rs +++ b/src/test/ui/issues/issue-47412.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #[derive(Copy, Clone)] enum Void {} @@ -9,7 +12,8 @@ fn union_field() { union Union { unit: (), void: Void } let u = Union { unit: () }; match u.void {} - //~^ ERROR access to union field is unsafe + //[mir]~^ ERROR access to union field is unsafe + // FIXME(thir-unsafeck): AccessToUnionField unimplemented } fn raw_ptr_deref() { diff --git a/src/test/ui/issues/issue-47412.thir.stderr b/src/test/ui/issues/issue-47412.thir.stderr new file mode 100644 index 00000000000..66a0cfcd710 --- /dev/null +++ b/src/test/ui/issues/issue-47412.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-47412.rs:21:11 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr index 6a744812e41..a84c048fab9 100644 --- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr +++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr @@ -37,7 +37,7 @@ LL | const A = "A".$fn(); | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `bool` + | help: replace with the correct type: `bool` ... LL | / suite! { LL | | len; diff --git a/src/test/ui/layout/issue-84108.rs b/src/test/ui/layout/issue-84108.rs new file mode 100644 index 00000000000..dd025c9b443 --- /dev/null +++ b/src/test/ui/layout/issue-84108.rs @@ -0,0 +1,14 @@ +// See issue #84108 -- this is a test to ensure we do not ICE +// on this invalid code. + +#![crate_type = "lib"] + +static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42); +//~^ ERROR cannot find type `OsStr` in this scope + +const BAR: (&Path, [u8], usize) = ("hello", [], 42); +//~^ ERROR cannot find type `Path` in this scope +//~| ERROR the size for values of type `[u8]` cannot be known at compilation time + +static BAZ: ([u8], usize) = ([], 0); +//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/src/test/ui/layout/issue-84108.stderr b/src/test/ui/layout/issue-84108.stderr new file mode 100644 index 00000000000..36be6424110 --- /dev/null +++ b/src/test/ui/layout/issue-84108.stderr @@ -0,0 +1,44 @@ +error[E0412]: cannot find type `OsStr` in this scope + --> $DIR/issue-84108.rs:6:24 + | +LL | static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42); + | ^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::ffi::OsStr; + | + +error[E0412]: cannot find type `Path` in this scope + --> $DIR/issue-84108.rs:9:14 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::path::Path; + | + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-84108.rs:9:12 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-84108.rs:13:13 + | +LL | static BAZ: ([u8], usize) = ([], 0); + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0412. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/lint/crate_level_only_lint.rs b/src/test/ui/lint/crate_level_only_lint.rs index d9673faa214..38c5487183c 100644 --- a/src/test/ui/lint/crate_level_only_lint.rs +++ b/src/test/ui/lint/crate_level_only_lint.rs @@ -4,12 +4,10 @@ mod foo { #![allow(uncommon_codepoints)] //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] -//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] #[allow(uncommon_codepoints)] //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] -//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] const BAR: f64 = 0.000001; } @@ -17,6 +15,5 @@ const BAR: f64 = 0.000001; #[allow(uncommon_codepoints)] //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] -//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] fn main() { } diff --git a/src/test/ui/lint/crate_level_only_lint.stderr b/src/test/ui/lint/crate_level_only_lint.stderr index 8fb06df2a48..83bea0412ff 100644 --- a/src/test/ui/lint/crate_level_only_lint.stderr +++ b/src/test/ui/lint/crate_level_only_lint.stderr @@ -11,13 +11,13 @@ LL | #![deny(uncommon_codepoints, unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:9:9 + --> $DIR/crate_level_only_lint.rs:8:9 | LL | #[allow(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:17:9 + --> $DIR/crate_level_only_lint.rs:15:9 | LL | #[allow(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ @@ -29,34 +29,16 @@ LL | #![allow(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:9:9 + --> $DIR/crate_level_only_lint.rs:8:9 | LL | #[allow(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:17:9 + --> $DIR/crate_level_only_lint.rs:15:9 | LL | #[allow(uncommon_codepoints)] | ^^^^^^^^^^^^^^^^^^^ -error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:4:10 - | -LL | #![allow(uncommon_codepoints)] - | ^^^^^^^^^^^^^^^^^^^ - -error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:9:9 - | -LL | #[allow(uncommon_codepoints)] - | ^^^^^^^^^^^^^^^^^^^ - -error: allow(uncommon_codepoints) is ignored unless specified at crate level - --> $DIR/crate_level_only_lint.rs:17:9 - | -LL | #[allow(uncommon_codepoints)] - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/lint/forbid-group-group-2.rs b/src/test/ui/lint/forbid-group-group-2.rs index b12fd72da74..7d8a3981814 100644 --- a/src/test/ui/lint/forbid-group-group-2.rs +++ b/src/test/ui/lint/forbid-group-group-2.rs @@ -17,10 +17,4 @@ //~| WARNING previously accepted by the compiler //~| ERROR incompatible with previous //~| WARNING previously accepted by the compiler -//~| ERROR incompatible with previous -//~| WARNING previously accepted by the compiler -//~| ERROR incompatible with previous -//~| WARNING previously accepted by the compiler -//~| ERROR incompatible with previous -//~| WARNING previously accepted by the compiler fn main() {} diff --git a/src/test/ui/lint/forbid-group-group-2.stderr b/src/test/ui/lint/forbid-group-group-2.stderr index 214e949c11a..d8c09e6526a 100644 --- a/src/test/ui/lint/forbid-group-group-2.stderr +++ b/src/test/ui/lint/forbid-group-group-2.stderr @@ -75,41 +75,5 @@ LL | #[allow(nonstandard_style)] = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> -error: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/forbid-group-group-2.rs:7:9 - | -LL | #![forbid(warnings)] - | -------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - | - = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> - -error: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/forbid-group-group-2.rs:7:9 - | -LL | #![forbid(warnings)] - | -------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - | - = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> - -error: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/forbid-group-group-2.rs:7:9 - | -LL | #![forbid(warnings)] - | -------- `forbid` level set here -... -LL | #[allow(nonstandard_style)] - | ^^^^^^^^^^^^^^^^^ overruled by previous forbid - | - = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/lint/forbid-group-member.rs b/src/test/ui/lint/forbid-group-member.rs index 6f1b2e9f668..664edeaa8b4 100644 --- a/src/test/ui/lint/forbid-group-member.rs +++ b/src/test/ui/lint/forbid-group-member.rs @@ -12,8 +12,6 @@ //~| WARNING previously accepted //~| WARNING incompatible with previous forbid //~| WARNING previously accepted -//~| WARNING incompatible with previous forbid -//~| WARNING previously accepted fn main() { let a: (); } diff --git a/src/test/ui/lint/forbid-group-member.stderr b/src/test/ui/lint/forbid-group-member.stderr index c818d7ff606..72772a42bed 100644 --- a/src/test/ui/lint/forbid-group-member.stderr +++ b/src/test/ui/lint/forbid-group-member.stderr @@ -35,17 +35,5 @@ LL | #[allow(unused_variables)] = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> -warning: allow(unused_variables) incompatible with previous forbid - --> $DIR/forbid-group-member.rs:8:9 - | -LL | #![forbid(unused)] - | ------ `forbid` level set here -LL | -LL | #[allow(unused_variables)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid - | - = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> - -warning: 4 warnings emitted +warning: 3 warnings emitted diff --git a/src/test/ui/lint/forbid-member-group.rs b/src/test/ui/lint/forbid-member-group.rs index 3279029a9cb..e2f76825a2d 100644 --- a/src/test/ui/lint/forbid-member-group.rs +++ b/src/test/ui/lint/forbid-member-group.rs @@ -6,7 +6,6 @@ #[allow(unused)] //~^ ERROR incompatible with previous forbid //~| ERROR incompatible with previous forbid -//~| ERROR incompatible with previous forbid fn main() { let a: (); } diff --git a/src/test/ui/lint/forbid-member-group.stderr b/src/test/ui/lint/forbid-member-group.stderr index 1d8ab4d5edb..39700af4d59 100644 --- a/src/test/ui/lint/forbid-member-group.stderr +++ b/src/test/ui/lint/forbid-member-group.stderr @@ -16,15 +16,6 @@ LL | LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid -error[E0453]: allow(unused) incompatible with previous forbid - --> $DIR/forbid-member-group.rs:6:9 - | -LL | #![forbid(unused_variables)] - | ---------------- `forbid` level set here -LL | -LL | #[allow(unused)] - | ^^^^^^ overruled by previous forbid - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs new file mode 100644 index 00000000000..0a3e20b4f7d --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs @@ -0,0 +1,11 @@ +// compile-flags: --force-warns elided_lifetimes_in_paths -Zunstable-options +// check-pass + +struct Foo<'a> { + x: &'a u32, +} + +fn foo(x: &Foo) {} +//~^ WARN hidden lifetime parameters in types are deprecated + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr new file mode 100644 index 00000000000..0e0e934c765 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs new file mode 100644 index 00000000000..0abc4913726 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns const_err -Zunstable-options +// 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() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr new file mode 100644 index 00000000000..bad12f94b18 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr @@ -0,0 +1,14 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.rs b/src/test/ui/lint/force-warn/force-allowed-warning.rs new file mode 100644 index 00000000000..bac0e4f8f8e --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-warning.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns dead_code -Zunstable-options +// check-pass + +#![allow(dead_code)] + +fn dead_function() {} +//~^ WARN function is never used + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/force-allowed-warning.stderr new file mode 100644 index 00000000000..145798a32a9 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-warning.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs new file mode 100644 index 00000000000..e721760ab2d --- /dev/null +++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs @@ -0,0 +1,8 @@ +// compile-flags: --force-warns const_err -Zunstable-options +// 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() {} diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr new file mode 100644 index 00000000000..4b004cf367d --- /dev/null +++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr @@ -0,0 +1,14 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs new file mode 100644 index 00000000000..0dc1ce28ac4 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns dead_code -Zunstable-options +// check-pass + +#![allow(warnings)] + +fn dead_function() {} +//~^ WARN function is never used + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr new file mode 100644 index 00000000000..577dbe1fea8 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs new file mode 100644 index 00000000000..4f637c7fefa --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns nonstandard_style -Zunstable-options +// check-pass + +#![allow(warnings)] + +pub fn FUNCTION() {} +//~^ WARN function `FUNCTION` should have a snake case name + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr new file mode 100644 index 00000000000..8665fa2610a --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs new file mode 100644 index 00000000000..bb2f394aef3 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns bare_trait_objects -Zunstable-options +// 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() {} diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr new file mode 100644 index 00000000000..40750ffea8c --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr @@ -0,0 +1,12 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs new file mode 100644 index 00000000000..d8a81d73afb --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns rust-2018-idioms -Zunstable-options +// 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() {} diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr new file mode 100644 index 00000000000..88ae846caa0 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr @@ -0,0 +1,12 @@ +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 + diff --git a/src/test/ui/lint/force-warn/force-warn-group.rs b/src/test/ui/lint/force-warn/force-warn-group.rs new file mode 100644 index 00000000000..c97eeabbd4e --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns rust_2018_idioms -Zunstable-options +// 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() {} diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/force-warn-group.stderr new file mode 100644 index 00000000000..f808727991e --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group.stderr @@ -0,0 +1,12 @@ +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 + diff --git a/src/test/ui/lint/issue-80988.rs b/src/test/ui/lint/issue-80988.rs index 16a041928db..1e116206f7b 100644 --- a/src/test/ui/lint/issue-80988.rs +++ b/src/test/ui/lint/issue-80988.rs @@ -11,6 +11,4 @@ //~| WARNING being phased out //~| WARNING incompatible with previous forbid //~| WARNING being phased out -//~| WARNING incompatible with previous forbid -//~| WARNING being phased out fn main() {} diff --git a/src/test/ui/lint/issue-80988.stderr b/src/test/ui/lint/issue-80988.stderr index 4cae11f97c0..deee267d0c6 100644 --- a/src/test/ui/lint/issue-80988.stderr +++ b/src/test/ui/lint/issue-80988.stderr @@ -35,17 +35,5 @@ LL | #[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 #81670 <https://github.com/rust-lang/rust/issues/81670> -warning: deny(warnings) incompatible with previous forbid - --> $DIR/issue-80988.rs:7:8 - | -LL | #![forbid(warnings)] - | -------- `forbid` level set here -LL | -LL | #[deny(warnings)] - | ^^^^^^^^ overruled by previous forbid - | - = 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 #81670 <https://github.com/rust-lang/rust/issues/81670> - -warning: 4 warnings emitted +warning: 3 warnings emitted diff --git a/src/test/ui/lint/issue-83477.rs b/src/test/ui/lint/issue-83477.rs index 0eba52acfa3..ab62f0c8b8c 100644 --- a/src/test/ui/lint/issue-83477.rs +++ b/src/test/ui/lint/issue-83477.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunstable-options // check-pass #![warn(rustc::internal)] diff --git a/src/test/ui/lint/issue-83477.stderr b/src/test/ui/lint/issue-83477.stderr index dbe0c9e0130..028890f3623 100644 --- a/src/test/ui/lint/issue-83477.stderr +++ b/src/test/ui/lint/issue-83477.stderr @@ -1,5 +1,5 @@ warning: unknown lint: `rustc::foo::bar::default_hash_types` - --> $DIR/issue-83477.rs:4:9 + --> $DIR/issue-83477.rs:5:9 | LL | #[allow(rustc::foo::bar::default_hash_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` @@ -7,19 +7,19 @@ LL | #[allow(rustc::foo::bar::default_hash_types)] = note: `#[warn(unknown_lints)]` on by default warning: unknown lint: `rustc::foo::default_hash_types` - --> $DIR/issue-83477.rs:8:9 + --> $DIR/issue-83477.rs:9:9 | LL | #[allow(rustc::foo::default_hash_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types` warning: Prefer FxHashMap over HashMap, it has better performance - --> $DIR/issue-83477.rs:13:31 + --> $DIR/issue-83477.rs:14:31 | LL | let _ = std::collections::HashMap::<String, String>::new(); | ^^^^^^^ help: use: `FxHashMap` | note: the lint level is defined here - --> $DIR/issue-83477.rs:2:9 + --> $DIR/issue-83477.rs:3:9 | LL | #![warn(rustc::internal)] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs index e69d0dab496..c18cb881032 100644 --- a/src/test/ui/lint/lint-ctypes-fn.rs +++ b/src/test/ui/lint/lint-ctypes-fn.rs @@ -8,6 +8,8 @@ extern crate libc; use std::default::Default; use std::marker::PhantomData; +trait Trait {} + trait Mirror { type It: ?Sized; } impl<T: ?Sized> Mirror for T { type It = Self; } @@ -74,6 +76,15 @@ pub extern "C" fn box_type(p: Box<u32>) { } 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` diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr index e6a0778ddb2..d591d4ad292 100644 --- a/src/test/ui/lint/lint-ctypes-fn.stderr +++ b/src/test/ui/lint/lint-ctypes-fn.stderr @@ -1,5 +1,5 @@ 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 @@ -13,7 +13,7 @@ LL | #![deny(improper_ctypes_definitions)] = 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 @@ -21,8 +21,32 @@ LL | pub extern "C" fn str_type(p: &str) { } = 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 @@ -31,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { } = 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 @@ -39,7 +63,7 @@ LL | pub extern "C" fn i128_type(p: i128) { } = 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 @@ -47,7 +71,7 @@ LL | pub extern "C" fn u128_type(p: u128) { } = 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 @@ -56,7 +80,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } = 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 @@ -65,7 +89,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { } = 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 @@ -73,26 +97,26 @@ LL | pub extern "C" fn zero_size(p: ZeroSize) { } = 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 @@ -100,7 +124,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> { = 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 @@ -109,7 +133,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { } = 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 @@ -118,7 +142,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { } = 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 @@ -126,7 +150,7 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } = 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 @@ -135,7 +159,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = 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 @@ -143,7 +167,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> { = 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 @@ -152,7 +176,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { } = 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 @@ -160,5 +184,5 @@ LL | pub extern "C" fn used_generic5<T>() -> Vec<T> { = 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 diff --git a/src/test/ui/lint/lint-forbid-attr.rs b/src/test/ui/lint/lint-forbid-attr.rs index 13ebb6dccd8..6d4cfd83424 100644 --- a/src/test/ui/lint/lint-forbid-attr.rs +++ b/src/test/ui/lint/lint-forbid-attr.rs @@ -3,6 +3,5 @@ #[allow(deprecated)] //~^ ERROR allow(deprecated) incompatible //~| ERROR allow(deprecated) incompatible -//~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-attr.stderr b/src/test/ui/lint/lint-forbid-attr.stderr index cb0b25d1115..48228c5dfdd 100644 --- a/src/test/ui/lint/lint-forbid-attr.stderr +++ b/src/test/ui/lint/lint-forbid-attr.stderr @@ -16,15 +16,6 @@ LL | LL | #[allow(deprecated)] | ^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(deprecated) incompatible with previous forbid - --> $DIR/lint-forbid-attr.rs:3:9 - | -LL | #![forbid(deprecated)] - | ---------- `forbid` level set here -LL | -LL | #[allow(deprecated)] - | ^^^^^^^^^^ overruled by previous forbid - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/lint-forbid-cmdline.rs b/src/test/ui/lint/lint-forbid-cmdline.rs index 38bb8d29d3f..5246ccb57a6 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.rs +++ b/src/test/ui/lint/lint-forbid-cmdline.rs @@ -2,6 +2,5 @@ #[allow(deprecated)] //~ ERROR allow(deprecated) incompatible //~| ERROR allow(deprecated) incompatible - //~| ERROR allow(deprecated) incompatible fn main() { } diff --git a/src/test/ui/lint/lint-forbid-cmdline.stderr b/src/test/ui/lint/lint-forbid-cmdline.stderr index 5b1b015c4dd..0a92e58c04a 100644 --- a/src/test/ui/lint/lint-forbid-cmdline.stderr +++ b/src/test/ui/lint/lint-forbid-cmdline.stderr @@ -14,14 +14,6 @@ LL | #[allow(deprecated)] | = note: `forbid` lint level was set on command line -error[E0453]: allow(deprecated) incompatible with previous forbid - --> $DIR/lint-forbid-cmdline.rs:3:9 - | -LL | #[allow(deprecated)] - | ^^^^^^^^^^ overruled by previous forbid - | - = note: `forbid` lint level was set on command line - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/lint-malformed.rs b/src/test/ui/lint/lint-malformed.rs index cf5570753d8..188e702f98b 100644 --- a/src/test/ui/lint/lint-malformed.rs +++ b/src/test/ui/lint/lint-malformed.rs @@ -3,6 +3,4 @@ //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute - //~| ERROR malformed lint attribute fn main() { } diff --git a/src/test/ui/lint/lint-malformed.stderr b/src/test/ui/lint/lint-malformed.stderr index 6dc8d498444..b3a41a786c1 100644 --- a/src/test/ui/lint/lint-malformed.stderr +++ b/src/test/ui/lint/lint-malformed.stderr @@ -28,18 +28,6 @@ error[E0452]: malformed lint attribute input LL | #![allow(bar = "baz")] | ^^^^^^^^^^^ bad attribute argument -error[E0452]: malformed lint attribute input - --> $DIR/lint-malformed.rs:2:10 - | -LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/lint-malformed.rs:2:10 - | -LL | #![allow(bar = "baz")] - | ^^^^^^^^^^^ bad attribute argument - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0452`. diff --git a/src/test/ui/lint/lint-removed-cmdline.stderr b/src/test/ui/lint/lint-removed-cmdline.stderr index fc2ba92479c..9be532ef234 100644 --- a/src/test/ui/lint/lint-removed-cmdline.stderr +++ b/src/test/ui/lint/lint-removed-cmdline.stderr @@ -10,10 +10,6 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point | = note: requested on the command line with `-D raw_pointer_derive` -warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok - | - = note: requested on the command line with `-D raw_pointer_derive` - error: unused variable: `unused` --> $DIR/lint-removed-cmdline.rs:12:17 | @@ -27,5 +23,5 @@ LL | #[deny(warnings)] | ^^^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` -error: aborting due to previous error; 4 warnings emitted +error: aborting due to previous error; 3 warnings emitted diff --git a/src/test/ui/lint/lint-renamed-cmdline.stderr b/src/test/ui/lint/lint-renamed-cmdline.stderr index 1c37a5baa6d..8dfd61ac927 100644 --- a/src/test/ui/lint/lint-renamed-cmdline.stderr +++ b/src/test/ui/lint/lint-renamed-cmdline.stderr @@ -10,10 +10,6 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` | = note: requested on the command line with `-D bare_trait_object` -warning: lint `bare_trait_object` has been renamed to `bare_trait_objects` - | - = note: requested on the command line with `-D bare_trait_object` - error: unused variable: `unused` --> $DIR/lint-renamed-cmdline.rs:8:17 | @@ -27,5 +23,5 @@ LL | #[deny(unused)] | ^^^^^^ = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` -error: aborting due to previous error; 4 warnings emitted +error: aborting due to previous error; 3 warnings emitted diff --git a/src/test/ui/lint/lint-unexported-no-mangle.stderr b/src/test/ui/lint/lint-unexported-no-mangle.stderr index 66d64e8937a..a11ee769c7c 100644 --- a/src/test/ui/lint/lint-unexported-no-mangle.stderr +++ b/src/test/ui/lint/lint-unexported-no-mangle.stderr @@ -22,14 +22,6 @@ warning: lint `private_no_mangle_statics` has been removed: no longer a warning, | = note: requested on the command line with `-F private_no_mangle_statics` -warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported - | - = note: requested on the command line with `-F private_no_mangle_fns` - -warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported - | - = note: requested on the command line with `-F private_no_mangle_statics` - error: const items should never be `#[no_mangle]` --> $DIR/lint-unexported-no-mangle.rs:9:1 | @@ -48,5 +40,5 @@ LL | pub const PUB_FOO: u64 = 1; | | | help: try a static value: `pub static` -error: aborting due to 2 previous errors; 8 warnings emitted +error: aborting due to 2 previous errors; 6 warnings emitted diff --git a/src/test/ui/lint/lint-unknown-lint-cmdline.stderr b/src/test/ui/lint/lint-unknown-lint-cmdline.stderr index 27e7ee7fc03..3855d552792 100644 --- a/src/test/ui/lint/lint-unknown-lint-cmdline.stderr +++ b/src/test/ui/lint/lint-unknown-lint-cmdline.stderr @@ -16,15 +16,6 @@ error[E0602]: unknown lint: `dead_cod` = help: did you mean: `dead_code` = note: requested on the command line with `-D dead_cod` -error[E0602]: unknown lint: `bogus` - | - = note: requested on the command line with `-D bogus` - -error[E0602]: unknown lint: `dead_cod` - | - = help: did you mean: `dead_code` - = note: requested on the command line with `-D dead_cod` - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0602`. diff --git a/src/test/ui/lint/reasons-erroneous.rs b/src/test/ui/lint/reasons-erroneous.rs index 03cf0679fce..cd693ae166c 100644 --- a/src/test/ui/lint/reasons-erroneous.rs +++ b/src/test/ui/lint/reasons-erroneous.rs @@ -3,15 +3,11 @@ #![warn(absolute_paths_not_starting_with_crate, reason = 0)] //~^ ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE reason must be a string literal //~| NOTE reason must be a string literal //~| NOTE reason must be a string literal #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] //~^ ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE reason must be a string literal //~| NOTE reason must be a string literal //~| NOTE reason must be a string literal #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] @@ -19,10 +15,6 @@ //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE bad attribute argument -//~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument @@ -32,10 +24,6 @@ //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE bad attribute argument -//~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument @@ -45,10 +33,6 @@ //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE bad attribute argument -//~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument //~| NOTE bad attribute argument @@ -56,15 +40,11 @@ #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] //~^ ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE reason in lint attribute must come last //~| NOTE reason in lint attribute must come last //~| NOTE reason in lint attribute must come last #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] //~^ ERROR malformed lint attribute //~| ERROR malformed lint attribute -//~| ERROR malformed lint attribute -//~| NOTE reason in lint attribute must come last //~| NOTE reason in lint attribute must come last //~| NOTE reason in lint attribute must come last #![warn(missing_copy_implementations, reason)] diff --git a/src/test/ui/lint/reasons-erroneous.stderr b/src/test/ui/lint/reasons-erroneous.stderr index d7926b73cee..f65ca08694d 100644 --- a/src/test/ui/lint/reasons-erroneous.stderr +++ b/src/test/ui/lint/reasons-erroneous.stderr @@ -5,61 +5,61 @@ LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] | ^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:10:40 + --> $DIR/reasons-erroneous.rs:8:40 | LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 + --> $DIR/reasons-erroneous.rs:13:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 + --> $DIR/reasons-erroneous.rs:13:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 + --> $DIR/reasons-erroneous.rs:22:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 + --> $DIR/reasons-erroneous.rs:22:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 + --> $DIR/reasons-erroneous.rs:31:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 + --> $DIR/reasons-erroneous.rs:31:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:56:44 + --> $DIR/reasons-erroneous.rs:40:44 | LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:63:25 + --> $DIR/reasons-erroneous.rs:45:25 | LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last warning: unknown lint: `reason` - --> $DIR/reasons-erroneous.rs:70:39 + --> $DIR/reasons-erroneous.rs:50:39 | LL | #![warn(missing_copy_implementations, reason)] | ^^^^^^ @@ -73,119 +73,59 @@ LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] | ^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:10:40 + --> $DIR/reasons-erroneous.rs:8:40 | LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 + --> $DIR/reasons-erroneous.rs:13:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 + --> $DIR/reasons-erroneous.rs:13:29 | LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 + --> $DIR/reasons-erroneous.rs:22:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 + --> $DIR/reasons-erroneous.rs:22:23 | LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 + --> $DIR/reasons-erroneous.rs:31:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 + --> $DIR/reasons-erroneous.rs:31:36 | LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:56:44 + --> $DIR/reasons-erroneous.rs:40:44 | LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:63:25 + --> $DIR/reasons-erroneous.rs:45:25 | LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:3:58 - | -LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] - | ^ reason must be a string literal - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:10:40 - | -LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 - | -LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:17:29 - | -LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 - | -LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:30:23 - | -LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 - | -LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:43:36 - | -LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:56:44 - | -LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] - | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last - -error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:63:25 - | -LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last - -error: aborting due to 30 previous errors; 1 warning emitted +error: aborting due to 20 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0452`. diff --git a/src/test/ui/lint/register-tool-lint.rs b/src/test/ui/lint/register-tool-lint.rs index 0ba5a37b167..17d3afbf6e2 100644 --- a/src/test/ui/lint/register-tool-lint.rs +++ b/src/test/ui/lint/register-tool-lint.rs @@ -7,5 +7,3 @@ //~| HELP add `#![register_tool(abc)]` //~| ERROR unknown tool name `abc` //~| HELP add `#![register_tool(abc)]` -//~| ERROR unknown tool name `abc` -//~| HELP add `#![register_tool(abc)]` diff --git a/src/test/ui/lint/register-tool-lint.stderr b/src/test/ui/lint/register-tool-lint.stderr index 750c74cec1e..842d845ff7c 100644 --- a/src/test/ui/lint/register-tool-lint.stderr +++ b/src/test/ui/lint/register-tool-lint.stderr @@ -14,14 +14,6 @@ LL | #![warn(abc::my_lint)] | = help: add `#![register_tool(abc)]` to the crate root -error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint` - --> $DIR/register-tool-lint.rs:5:9 - | -LL | #![warn(abc::my_lint)] - | ^^^ - | - = help: add `#![register_tool(abc)]` to the crate root - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0710`. diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 21342e2ef37..d17514303ab 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -1,420 +1,3 @@ -{ - "message": "cannot find type `Iter` in this scope", - "code": { - "code": "E0412", - "explanation": "A used type name is not in scope. +{"message":"`--error-format=pretty-json` is unstable","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: `--error-format=pretty-json` is unstable\u001b[0m -Erroneous code examples: - -```compile_fail,E0412 -impl Something {} // error: type name `Something` is not in scope - -// or: - -trait Foo { - fn bar(N); // error: type name `N` is not in scope -} - -// or: - -fn foo(x: T) {} // type name `T` is not in scope -``` - -To fix this error, please verify you didn't misspell the type name, you did -declare it or imported it into the scope. Examples: - -``` -struct Something; - -impl Something {} // ok! - -// or: - -trait Foo { - type N; - - fn bar(_: Self::N); // ok! -} - -// or: - -fn foo<T>(x: T) {} // ok! -``` - -Another case that causes this error is when a type is imported into a parent -module. To fix this, you can follow the suggestion and use File directly or -`use super::File;` which will import the types from the parent namespace. An -example that causes this error is below: - -```compile_fail,E0412 -use std::fs::File; - -mod foo { - fn some_function(f: File) {} -} -``` - -``` -use std::fs::File; - -mod foo { - // either - use super::File; - // or - // use std::fs::File; - fn foo(f: File) {} -} -# fn main() {} // don't insert it for us; that'll break imports -``` -" - }, - "level": "error", - "spans": [ - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 541, - "byte_end": 545, - "line_start": 12, - "line_end": 12, - "column_start": 12, - "column_end": 16, - "is_primary": true, - "text": [ - { - "text": " let x: Iter;", - "highlight_start": 12, - "highlight_end": 16 - } - ], - "label": "not found in this scope", - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "consider importing one of these items", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::binary_heap::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::btree_map::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::btree_set::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::hash_map::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::hash_set::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::linked_list::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::collections::vec_deque::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::option::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::path::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::result::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::slice::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - }, - { - "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 518, - "byte_end": 518, - "line_start": 11, - "line_end": 11, - "column_start": 1, - "column_end": 1, - "is_primary": true, - "text": [ - { - "text": "fn main() {", - "highlight_start": 1, - "highlight_end": 1 - } - ], - "label": null, - "suggested_replacement": "use std::sync::mpsc::Iter; - -", - "suggestion_applicability": "Unspecified", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m and 8 other candidates\u001b[0m - -" -} -{ - "message": "aborting due to previous error", - "code": null, - "level": "error", - "spans": [], - "children": [], - "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m - -" -} -{ - "message": "For more information about this error, try `rustc --explain E0412`.", - "code": null, - "level": "failure-note", - "spans": [], - "children": [], - "rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m -" -} +"} diff --git a/src/test/ui/lto-still-runs-thread-dtors.rs b/src/test/ui/lto-still-runs-thread-dtors.rs index 635ad783b31..1c7368b36e1 100644 --- a/src/test/ui/lto-still-runs-thread-dtors.rs +++ b/src/test/ui/lto-still-runs-thread-dtors.rs @@ -2,6 +2,8 @@ // compile-flags: -C lto // no-prefer-dynamic // ignore-emscripten no threads support +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck use std::thread; diff --git a/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs new file mode 100644 index 00000000000..26d4c96d524 --- /dev/null +++ b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs @@ -0,0 +1,11 @@ +// edition:2018 + +#[macro_export] +macro_rules! custom_matches { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { + match $expression { + $( $pattern )|+ $( if $guard )? => true, + _ => false + } + } +} diff --git a/src/test/ui/macros/cross-crate-pat-span.rs b/src/test/ui/macros/cross-crate-pat-span.rs new file mode 100644 index 00000000000..ed67142ce3d --- /dev/null +++ b/src/test/ui/macros/cross-crate-pat-span.rs @@ -0,0 +1,12 @@ +// 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'); +} diff --git a/src/test/ui/macros/issue-84429-matches-edition.rs b/src/test/ui/macros/issue-84429-matches-edition.rs new file mode 100644 index 00000000000..53f134c265f --- /dev/null +++ b/src/test/ui/macros/issue-84429-matches-edition.rs @@ -0,0 +1,9 @@ +// 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'); +} diff --git a/src/test/ui/macros/local-ambiguity-multiple-parsing-options.stderr b/src/test/ui/macros/local-ambiguity-multiple-parsing-options.stderr index 0ae56c42221..68b278fd3c8 100644 --- a/src/test/ui/macros/local-ambiguity-multiple-parsing-options.stderr +++ b/src/test/ui/macros/local-ambiguity-multiple-parsing-options.stderr @@ -1,10 +1,10 @@ -error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j'). +error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). --> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12 | LL | ambiguity!(error); | ^^^^^ -error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j'). +error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12 | LL | ambiguity!(error); diff --git a/src/test/ui/manual/manual-link-unsupported-kind.rs b/src/test/ui/manual/manual-link-unsupported-kind.rs new file mode 100644 index 00000000000..34814db593f --- /dev/null +++ b/src/test/ui/manual/manual-link-unsupported-kind.rs @@ -0,0 +1,5 @@ +// compile-flags:-l raw-dylib=foo +// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static + +fn main() { +} diff --git a/src/test/ui/manual/manual-link-unsupported-kind.stderr b/src/test/ui/manual/manual-link-unsupported-kind.stderr new file mode 100644 index 00000000000..acb4463cb04 --- /dev/null +++ b/src/test/ui/manual/manual-link-unsupported-kind.stderr @@ -0,0 +1,2 @@ +error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static + diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr index 1658efa28bf..1dc29d2088c 100644 --- a/src/test/ui/match/match-ref-mut-invariance.nll.stderr +++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr @@ -9,6 +9,9 @@ LL | match self.0 { ref mut x => x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr index dc227a36566..8b87c3da28b 100644 --- a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr +++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr @@ -10,6 +10,9 @@ LL | x | ^ returning this value requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to previous error diff --git a/src/test/ui/matches2021.rs b/src/test/ui/matches2021.rs new file mode 100644 index 00000000000..1090b1578ba --- /dev/null +++ b/src/test/ui/matches2021.rs @@ -0,0 +1,12 @@ +// 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!((), ()); +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs new file mode 100644 index 00000000000..3df928b5d80 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs @@ -0,0 +1,106 @@ +// 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 +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr new file mode 100644 index 00000000000..1671e5e5e64 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -0,0 +1,97 @@ +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`. diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr index 8400aab308e..961234cf7e8 100644 --- a/src/test/ui/mir/issue-80742.stderr +++ b/src/test/ui/mir/issue-80742.stderr @@ -1,4 +1,4 @@ -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>() @@ -35,7 +35,7 @@ LL | pub trait Debug { = 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>() diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 388c978d038..6a97d1ee3b8 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -24,7 +24,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $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 diff --git a/src/test/ui/nll/type-check-pointer-coercions.stderr b/src/test/ui/nll/type-check-pointer-coercions.stderr index 39fd98f7151..ccb3d33ac40 100644 --- a/src/test/ui/nll/type-check-pointer-coercions.stderr +++ b/src/test/ui/nll/type-check-pointer-coercions.stderr @@ -34,6 +34,9 @@ LL | x | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to &i32 + = note: mutable pointers are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/type-check-pointer-coercions.rs:13:5 @@ -47,6 +50,9 @@ LL | x | ^ returning this value requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable pointer to &i32 + = note: mutable pointers are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'b` and `'a` must be the same: replace one with the other diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr index f350b861eb6..b488af820b8 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.stderr +++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr @@ -9,6 +9,9 @@ LL | x == y; | ^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/type-check-pointer-comparisons.rs:6:10 @@ -21,6 +24,9 @@ LL | x == y; | ^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'a` and `'b` must be the same: replace one with the other @@ -35,6 +41,9 @@ LL | x == y; | ^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable pointer to &i32 + = note: mutable pointers are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/type-check-pointer-comparisons.rs:12:10 @@ -47,6 +56,9 @@ LL | x == y; | ^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable pointer to &i32 + = note: mutable pointers are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'a` and `'b` must be the same: replace one with the other @@ -61,6 +73,9 @@ LL | f == g; | ^ requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/type-check-pointer-comparisons.rs:18:10 @@ -73,6 +88,9 @@ LL | f == g; | ^ requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to &i32 + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance help: `'a` and `'b` must be the same: replace one with the other diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index 68e6fa838b4..24985386a97 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -2,6 +2,8 @@ // ignore-android // ignore-emscripten no processes // ignore-sgx no processes +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![feature(rustc_private)] diff --git a/src/test/ui/panics/panic-macro-any-wrapped.rs b/src/test/ui/panics/panic-macro-any-wrapped.rs index 95ae6ffe8be..100ac10c767 100644 --- a/src/test/ui/panics/panic-macro-any-wrapped.rs +++ b/src/test/ui/panics/panic-macro-any-wrapped.rs @@ -1,5 +1,5 @@ // run-fail -// error-pattern:panicked at 'Box<Any>' +// error-pattern:panicked at 'Box<dyn Any>' // ignore-emscripten no processes #![allow(non_fmt_panic)] diff --git a/src/test/ui/panics/panic-macro-any.rs b/src/test/ui/panics/panic-macro-any.rs index d2a7ba3713a..a5ba30220e8 100644 --- a/src/test/ui/panics/panic-macro-any.rs +++ b/src/test/ui/panics/panic-macro-any.rs @@ -1,5 +1,5 @@ // run-fail -// error-pattern:panicked at 'Box<Any>' +// error-pattern:panicked at 'Box<dyn Any>' // ignore-emscripten no processes #![feature(box_syntax)] diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.rs b/src/test/ui/parser/brace-after-qualified-path-in-match.rs deleted file mode 100644 index f4152086162..00000000000 --- a/src/test/ui/parser/brace-after-qualified-path-in-match.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - match 10 { - <T as Trait>::Type{key: value} => (), - //~^ ERROR unexpected `{` after qualified path - _ => (), - } -} diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.stderr b/src/test/ui/parser/brace-after-qualified-path-in-match.stderr deleted file mode 100644 index d6fdf353f07..00000000000 --- a/src/test/ui/parser/brace-after-qualified-path-in-match.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unexpected `{` after qualified path - --> $DIR/brace-after-qualified-path-in-match.rs:3:27 - | -LL | <T as Trait>::Type{key: value} => (), - | ------------------^ unexpected `{` after qualified path - | | - | the qualified path - -error: aborting due to previous error - diff --git a/src/test/ui/parser/fn-field-parse-error-ice.rs b/src/test/ui/parser/fn-field-parse-error-ice.rs new file mode 100644 index 00000000000..4ea55062fc4 --- /dev/null +++ b/src/test/ui/parser/fn-field-parse-error-ice.rs @@ -0,0 +1,10 @@ +// 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() {} diff --git a/src/test/ui/parser/fn-field-parse-error-ice.stderr b/src/test/ui/parser/fn-field-parse-error-ice.stderr new file mode 100644 index 00000000000..d582f61cc97 --- /dev/null +++ b/src/test/ui/parser/fn-field-parse-error-ice.stderr @@ -0,0 +1,24 @@ +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`. diff --git a/src/test/ui/parser/issue-84104.rs b/src/test/ui/parser/issue-84104.rs new file mode 100644 index 00000000000..998949b94a4 --- /dev/null +++ b/src/test/ui/parser/issue-84104.rs @@ -0,0 +1,3 @@ +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected one of +#[i=i::<ښܖ< diff --git a/src/test/ui/parser/issue-84104.stderr b/src/test/ui/parser/issue-84104.stderr new file mode 100644 index 00000000000..aff31f2c971 --- /dev/null +++ b/src/test/ui/parser/issue-84104.stderr @@ -0,0 +1,16 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-84104.rs:3:13 + | +LL | #[i=i::<ښܖ< + | - ^ + | | + | unclosed delimiter + +error: expected one of `>`, a const expression, lifetime, or type, found `]` + --> $DIR/issue-84104.rs:3:13 + | +LL | #[i=i::<ښܖ< + | ^ expected one of `>`, a const expression, lifetime, or type + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-84148-1.rs b/src/test/ui/parser/issue-84148-1.rs new file mode 100644 index 00000000000..25f7ba4d1f8 --- /dev/null +++ b/src/test/ui/parser/issue-84148-1.rs @@ -0,0 +1,4 @@ +fn f(t:for<>t?) +//~^ ERROR: expected parameter name +//~| ERROR: expected one of +//~| ERROR: expected one of diff --git a/src/test/ui/parser/issue-84148-1.stderr b/src/test/ui/parser/issue-84148-1.stderr new file mode 100644 index 00000000000..98506568d82 --- /dev/null +++ b/src/test/ui/parser/issue-84148-1.stderr @@ -0,0 +1,23 @@ +error: expected parameter name, found `?` + --> $DIR/issue-84148-1.rs:1:14 + | +LL | fn f(t:for<>t?) + | ^ expected parameter name + +error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` + --> $DIR/issue-84148-1.rs:1:14 + | +LL | fn f(t:for<>t?) + | ^ + | | + | expected one of `(`, `)`, `+`, `,`, `::`, or `<` + | help: missing `,` + +error: expected one of `->`, `;`, `where`, or `{`, found `<eof>` + --> $DIR/issue-84148-1.rs:1:15 + | +LL | fn f(t:for<>t?) + | ^ expected one of `->`, `;`, `where`, or `{` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/issue-84148-2.rs b/src/test/ui/parser/issue-84148-2.rs new file mode 100644 index 00000000000..257a3fd6720 --- /dev/null +++ b/src/test/ui/parser/issue-84148-2.rs @@ -0,0 +1,4 @@ +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected parameter name +// error-pattern: expected one of +fn f(t:for<>t? diff --git a/src/test/ui/parser/issue-84148-2.stderr b/src/test/ui/parser/issue-84148-2.stderr new file mode 100644 index 00000000000..6f314da4360 --- /dev/null +++ b/src/test/ui/parser/issue-84148-2.stderr @@ -0,0 +1,31 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-84148-2.rs:4:16 + | +LL | fn f(t:for<>t? + | - ^ + | | + | unclosed delimiter + +error: expected parameter name, found `?` + --> $DIR/issue-84148-2.rs:4:14 + | +LL | fn f(t:for<>t? + | ^ expected parameter name + +error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?` + --> $DIR/issue-84148-2.rs:4:14 + | +LL | fn f(t:for<>t? + | ^ + | | + | expected one of `(`, `)`, `+`, `,`, `::`, or `<` + | help: missing `,` + +error: expected one of `->`, `;`, `where`, or `{`, found `<eof>` + --> $DIR/issue-84148-2.rs:4:16 + | +LL | fn f(t:for<>t? + | ^ expected one of `->`, `;`, `where`, or `{` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.rs b/src/test/ui/parser/paren-after-qualified-path-in-match.rs deleted file mode 100644 index 68b1c2baf10..00000000000 --- a/src/test/ui/parser/paren-after-qualified-path-in-match.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - match 10 { - <T as Trait>::Type(2) => (), - //~^ ERROR unexpected `(` after qualified path - _ => (), - } -} diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.stderr b/src/test/ui/parser/paren-after-qualified-path-in-match.stderr deleted file mode 100644 index af21f919546..00000000000 --- a/src/test/ui/parser/paren-after-qualified-path-in-match.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unexpected `(` after qualified path - --> $DIR/paren-after-qualified-path-in-match.rs:3:27 - | -LL | <T as Trait>::Type(2) => (), - | ------------------^ unexpected `(` after qualified path - | | - | the qualified path - -error: aborting due to previous error - diff --git a/src/test/ui/parser/unmatched-langle-1.rs b/src/test/ui/parser/unmatched-langle-1.rs new file mode 100644 index 00000000000..fdf2ae39801 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-1.rs @@ -0,0 +1,9 @@ +// Check that a suggestion is issued if there are too many `<`s in a +// generic argument list, and that the parser recovers properly. + +fn main() { + foo::<<<<Ty<i32>>(); + //~^ ERROR: unmatched angle brackets + //~| ERROR: cannot find function `foo` in this scope [E0425] + //~| ERROR: cannot find type `Ty` in this scope [E0412] +} diff --git a/src/test/ui/parser/unmatched-langle-1.stderr b/src/test/ui/parser/unmatched-langle-1.stderr new file mode 100644 index 00000000000..c8072b4c59a --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-1.stderr @@ -0,0 +1,22 @@ +error: unmatched angle brackets + --> $DIR/unmatched-langle-1.rs:5:10 + | +LL | foo::<<<<Ty<i32>>(); + | ^^^ help: remove extra angle brackets + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/unmatched-langle-1.rs:5:5 + | +LL | foo::<<<<Ty<i32>>(); + | ^^^ not found in this scope + +error[E0412]: cannot find type `Ty` in this scope + --> $DIR/unmatched-langle-1.rs:5:14 + | +LL | foo::<<<<Ty<i32>>(); + | ^^ not found in this scope + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0412, E0425. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/parser/unmatched-langle-2.rs b/src/test/ui/parser/unmatched-langle-2.rs new file mode 100644 index 00000000000..8de0d7d89e4 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-2.rs @@ -0,0 +1,15 @@ +// When there are too many opening `<`s, the compiler would previously +// suggest nonsense if the `<`s were interspersed with other tokens: +// +// error: unmatched angle brackets +// --> unmatched-langle.rs:2:10 +// | +// 2 | foo::<Ty<<<i32>(); +// | ^^^ help: remove extra angle brackets +// +// This test makes sure that this is no longer happening. + +fn main() { + foo::<Ty<<<i32>(); + //~^ ERROR: expected `::`, found `(` +} diff --git a/src/test/ui/parser/unmatched-langle-2.stderr b/src/test/ui/parser/unmatched-langle-2.stderr new file mode 100644 index 00000000000..773bb33d8d3 --- /dev/null +++ b/src/test/ui/parser/unmatched-langle-2.stderr @@ -0,0 +1,8 @@ +error: expected `::`, found `(` + --> $DIR/unmatched-langle-2.rs:13:20 + | +LL | foo::<Ty<<<i32>(); + | ^ expected `::` + +error: aborting due to previous error + diff --git a/src/test/ui/prelude2021.rs b/src/test/ui/prelude2021.rs new file mode 100644 index 00000000000..3a9fd693228 --- /dev/null +++ b/src/test/ui/prelude2021.rs @@ -0,0 +1,7 @@ +// check-pass +// edition:2021 +// compile-flags: -Zunstable-options + +fn main() { + let _: u16 = 123i32.try_into().unwrap(); +} diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs new file mode 100644 index 00000000000..d4067a33592 --- /dev/null +++ b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs @@ -0,0 +1,37 @@ +// check-pass +// aux-build:test-macros.rs + +#![feature(decl_macro)] +#![feature(stmt_expr_attributes)] + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + +macro mac { + (expr $expr:expr) => { + #[derive(Print)] + enum E { + V = { let _ = $expr; 0 }, + } + }, + (stmt $stmt:stmt) => { + #[derive(Print)] + enum E { + V = { let _ = { $stmt }; 0 }, + } + }, +} + +const PATH: u8 = 2; + +fn main() { + mac!(expr #[allow(warnings)] 0); + mac!(stmt 0); + mac!(stmt {}); + mac!(stmt PATH); + mac!(stmt 0 + 1); + mac!(stmt PATH + 1); +} diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout new file mode 100644 index 00000000000..e37a483cb87 --- /dev/null +++ b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout @@ -0,0 +1,540 @@ +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #4 bytes(299..303), + }, + Ident { + ident: "E", + span: #4 bytes(304..305), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #4 bytes(320..321), + }, + Punct { + ch: '=', + spacing: Alone, + span: #4 bytes(322..323), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #4 bytes(326..329), + }, + Ident { + ident: "_", + span: #4 bytes(330..331), + }, + Punct { + ch: '=', + spacing: Alone, + span: #4 bytes(332..333), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: #0 bytes(541..542), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: #0 bytes(543..548), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: #0 bytes(549..557), + }, + ], + span: #0 bytes(548..558), + }, + ], + span: #0 bytes(542..559), + }, + Punct { + ch: '#', + spacing: Alone, + span: #0 bytes(541..542), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: #0 bytes(543..548), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: #0 bytes(549..557), + }, + ], + span: #0 bytes(548..558), + }, + ], + span: #0 bytes(542..559), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #0 bytes(560..561), + }, + ], + span: #4 bytes(334..339), + }, + Punct { + ch: ';', + spacing: Alone, + span: #4 bytes(339..340), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #4 bytes(341..342), + }, + ], + span: #4 bytes(324..344), + }, + Punct { + ch: ',', + spacing: Alone, + span: #4 bytes(344..345), + }, + ], + span: #4 bytes(306..355), + }, +] +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #8 bytes(423..427), + }, + Ident { + ident: "E", + span: #8 bytes(428..429), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #8 bytes(444..445), + }, + Punct { + ch: '=', + spacing: Alone, + span: #8 bytes(446..447), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #8 bytes(450..453), + }, + Ident { + ident: "_", + span: #8 bytes(454..455), + }, + Punct { + ch: '=', + spacing: Alone, + span: #8 bytes(456..457), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #0 bytes(578..579), + }, + ], + span: #8 bytes(460..465), + }, + ], + span: #8 bytes(458..467), + }, + Punct { + ch: ';', + spacing: Alone, + span: #8 bytes(467..468), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #8 bytes(469..470), + }, + ], + span: #8 bytes(448..472), + }, + Punct { + ch: ',', + spacing: Alone, + span: #8 bytes(472..473), + }, + ], + span: #8 bytes(430..483), + }, +] +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #12 bytes(423..427), + }, + Ident { + ident: "E", + span: #12 bytes(428..429), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #12 bytes(444..445), + }, + Punct { + ch: '=', + spacing: Alone, + span: #12 bytes(446..447), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #12 bytes(450..453), + }, + Ident { + ident: "_", + span: #12 bytes(454..455), + }, + Punct { + ch: '=', + spacing: Alone, + span: #12 bytes(456..457), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Brace, + stream: TokenStream [], + span: #0 bytes(596..598), + }, + ], + span: #12 bytes(460..465), + }, + ], + span: #12 bytes(458..467), + }, + Punct { + ch: ';', + spacing: Alone, + span: #12 bytes(467..468), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #12 bytes(469..470), + }, + ], + span: #12 bytes(448..472), + }, + Punct { + ch: ',', + spacing: Alone, + span: #12 bytes(472..473), + }, + ], + span: #12 bytes(430..483), + }, +] +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #16 bytes(423..427), + }, + Ident { + ident: "E", + span: #16 bytes(428..429), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #16 bytes(444..445), + }, + Punct { + ch: '=', + spacing: Alone, + span: #16 bytes(446..447), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #16 bytes(450..453), + }, + Ident { + ident: "_", + span: #16 bytes(454..455), + }, + Punct { + ch: '=', + spacing: Alone, + span: #16 bytes(456..457), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "PATH", + span: #0 bytes(615..619), + }, + ], + span: #16 bytes(460..465), + }, + ], + span: #16 bytes(458..467), + }, + Punct { + ch: ';', + spacing: Alone, + span: #16 bytes(467..468), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #16 bytes(469..470), + }, + ], + span: #16 bytes(448..472), + }, + Punct { + ch: ',', + spacing: Alone, + span: #16 bytes(472..473), + }, + ], + span: #16 bytes(430..483), + }, +] +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #20 bytes(423..427), + }, + Ident { + ident: "E", + span: #20 bytes(428..429), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #20 bytes(444..445), + }, + Punct { + ch: '=', + spacing: Alone, + span: #20 bytes(446..447), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #20 bytes(450..453), + }, + Ident { + ident: "_", + span: #20 bytes(454..455), + }, + Punct { + ch: '=', + spacing: Alone, + span: #20 bytes(456..457), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #0 bytes(636..637), + }, + Punct { + ch: '+', + spacing: Alone, + span: #0 bytes(638..639), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: #0 bytes(640..641), + }, + ], + span: #20 bytes(460..465), + }, + ], + span: #20 bytes(458..467), + }, + Punct { + ch: ';', + spacing: Alone, + span: #20 bytes(467..468), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #20 bytes(469..470), + }, + ], + span: #20 bytes(448..472), + }, + Punct { + ch: ',', + spacing: Alone, + span: #20 bytes(472..473), + }, + ], + span: #20 bytes(430..483), + }, +] +PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "enum", + span: #24 bytes(423..427), + }, + Ident { + ident: "E", + span: #24 bytes(428..429), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "V", + span: #24 bytes(444..445), + }, + Punct { + ch: '=', + spacing: Alone, + span: #24 bytes(446..447), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "let", + span: #24 bytes(450..453), + }, + Ident { + ident: "_", + span: #24 bytes(454..455), + }, + Punct { + ch: '=', + spacing: Alone, + span: #24 bytes(456..457), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "PATH", + span: #0 bytes(658..662), + }, + Punct { + ch: '+', + spacing: Alone, + span: #0 bytes(663..664), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: #0 bytes(665..666), + }, + ], + span: #24 bytes(460..465), + }, + ], + span: #24 bytes(458..467), + }, + Punct { + ch: ';', + spacing: Alone, + span: #24 bytes(467..468), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #24 bytes(469..470), + }, + ], + span: #24 bytes(448..472), + }, + Punct { + ch: ',', + spacing: Alone, + span: #24 bytes(472..473), + }, + ], + span: #24 bytes(430..483), + }, +] diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr index 695f5506d5e..4ddea2c27b2 100644 --- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr +++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -23,6 +23,9 @@ LL | a(x, y); | ^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to &isize + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: higher-ranked subtype error --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12 diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr index a28f7aa3e08..a9cf128bb62 100644 --- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr +++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr @@ -23,6 +23,9 @@ LL | a(x, y, z); | ^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to &isize + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: higher-ranked subtype error --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12 diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr index 37f7fcf2e33..db86572f1cf 100644 --- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr +++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr @@ -23,6 +23,9 @@ LL | a(x, y); | ^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to &isize + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: higher-ranked subtype error --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12 diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr index f92923a1125..bf325d56013 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr @@ -10,6 +10,9 @@ LL | x | ^ returning this value requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of a mutable reference to dyn Dummy + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: lifetime may not live long enough --> $DIR/regions-trait-object-subtyping.rs:22:5 @@ -23,6 +26,9 @@ LL | x | ^ returning this value requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a mutable reference to dyn Dummy + = note: mutable references are invariant over their type parameter + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance error: aborting due to 2 previous errors diff --git a/src/test/ui/reify-intrinsic.rs b/src/test/ui/reify-intrinsic.rs index 05535b92cca..9eb2f724017 100644 --- a/src/test/ui/reify-intrinsic.rs +++ b/src/test/ui/reify-intrinsic.rs @@ -1,6 +1,6 @@ // check-fail -#![feature(intrinsics)] +#![feature(core_intrinsics, intrinsics)] fn a() { let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; @@ -14,8 +14,8 @@ fn b() { fn c() { let _ = [ - std::intrinsics::copy_nonoverlapping::<i32>, - std::intrinsics::copy::<i32>, + std::intrinsics::likely, + std::intrinsics::unlikely, //~^ ERROR cannot coerce ]; } diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr index 5d82fdbd311..69c11b5c56f 100644 --- a/src/test/ui/reify-intrinsic.stderr +++ b/src/test/ui/reify-intrinsic.stderr @@ -22,11 +22,11 @@ LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) error[E0308]: cannot coerce intrinsics to function pointers --> $DIR/reify-intrinsic.rs:18:9 | -LL | std::intrinsics::copy::<i32>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers +LL | std::intrinsics::unlikely, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | - = note: expected type `unsafe extern "rust-intrinsic" fn(_, _, _) {copy_nonoverlapping::<i32>}` - found fn item `unsafe extern "rust-intrinsic" fn(_, _, _) {std::intrinsics::copy::<i32>}` + = note: expected type `extern "rust-intrinsic" fn(_) -> _ {likely}` + found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}` error: aborting due to 3 previous errors diff --git a/src/test/ui/resolve/issue-85348.rs b/src/test/ui/resolve/issue-85348.rs new file mode 100644 index 00000000000..3a33c193408 --- /dev/null +++ b/src/test/ui/resolve/issue-85348.rs @@ -0,0 +1,12 @@ +// 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() {} diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr new file mode 100644 index 00000000000..f475c26f32b --- /dev/null +++ b/src/test/ui/resolve/issue-85348.stderr @@ -0,0 +1,25 @@ +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`. diff --git a/src/test/ui/resolve/shadow-const-param.rs b/src/test/ui/resolve/shadow-const-param.rs new file mode 100644 index 00000000000..c435c16dc67 --- /dev/null +++ b/src/test/ui/resolve/shadow-const-param.rs @@ -0,0 +1,20 @@ +// 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() {} diff --git a/src/test/ui/resolve/shadow-const-param.stderr b/src/test/ui/resolve/shadow-const-param.stderr new file mode 100644 index 00000000000..fbd0d811000 --- /dev/null +++ b/src/test/ui/resolve/shadow-const-param.stderr @@ -0,0 +1,20 @@ +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`. diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs new file mode 100644 index 00000000000..e9690f03f45 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs @@ -0,0 +1,8 @@ +// only-windows-gnu +// check-pass +// compile-flags: --crate-type lib +#![feature(raw_dylib)] +//~^ WARNING: the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu +extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr new file mode 100644 index 00000000000..6e24112b3c3 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/raw-dylib-msvc-only.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + +warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu + --> $DIR/raw-dylib-msvc-only.rs:6:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs new file mode 100644 index 00000000000..7a5d7ac2934 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs @@ -0,0 +1,7 @@ +// ignore-windows +// compile-flags: --crate-type lib +#![feature(raw_dylib)] +//~^ WARNING: the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows +extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr new file mode 100644 index 00000000000..f3879b63f91 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/raw-dylib-windows-only.rs:3:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + +error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows + --> $DIR/raw-dylib-windows-only.rs:5:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs index 58a2c271ecf..e0842bfa4cd 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs @@ -8,6 +8,8 @@ // check-pass // only-x86_64 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs index af35bc2014b..a59d7c2d784 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs @@ -1,6 +1,8 @@ // Tests #73631: closures inherit `#[target_feature]` annotations // check-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr index 06cfdde3fb9..cf5815df56e 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:9:21 + --> $DIR/fn-ptr.rs:11:21 | LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs index 3ecea5c5313..c95d4a08e48 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs @@ -1,3 +1,5 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr new file mode 100644 index 00000000000..cf5815df56e --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/fn-ptr.rs:11:21 + | +LL | #[target_feature(enable = "sse2")] + | ---------------------------------- `#[target_feature]` added here +... +LL | let foo: fn() = foo; + | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers + | | + | expected due to this + | + = note: expected fn pointer `fn()` + found fn item `fn() {foo}` + = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr index b9f748640b5..79273a1dcbf 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:21:5 + --> $DIR/safe-calls.rs:23:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -7,7 +7,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:22:5 + --> $DIR/safe-calls.rs:24:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -15,7 +15,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:25:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -23,7 +23,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:28:5 + --> $DIR/safe-calls.rs:30:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -31,7 +31,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:31:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -39,7 +39,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:34:5 + --> $DIR/safe-calls.rs:36:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -47,7 +47,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:35:5 + --> $DIR/safe-calls.rs:37:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -55,7 +55,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:38:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -63,7 +63,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:42:5 + --> $DIR/safe-calls.rs:44:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -71,7 +71,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:45:18 + --> $DIR/safe-calls.rs:47:18 | LL | const name: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index 8da3affc447..de0b89f46ba 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -1,3 +1,5 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr new file mode 100644 index 00000000000..79273a1dcbf --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -0,0 +1,83 @@ +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:23:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:24:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:25:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:30:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:31:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:36:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:37:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:38:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:44:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:47:18 + | +LL | const name: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/running-with-no-runtime.rs b/src/test/ui/running-with-no-runtime.rs index c321e86dc18..c575a6bec8e 100644 --- a/src/test/ui/running-with-no-runtime.rs +++ b/src/test/ui/running-with-no-runtime.rs @@ -1,6 +1,8 @@ // run-pass // ignore-emscripten spawning processes is not supported // ignore-sgx no processes +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![feature(start)] diff --git a/src/test/ui/rustdoc/deny-invalid-doc-attrs.rs b/src/test/ui/rustdoc/deny-invalid-doc-attrs.rs new file mode 100644 index 00000000000..02e9c67915f --- /dev/null +++ b/src/test/ui/rustdoc/deny-invalid-doc-attrs.rs @@ -0,0 +1,7 @@ +#![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() {} diff --git a/src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr b/src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr new file mode 100644 index 00000000000..a14ab8fe4bc --- /dev/null +++ b/src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr @@ -0,0 +1,16 @@ +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 + diff --git a/src/test/ui/rustdoc/doc-inline-extern-crate.rs b/src/test/ui/rustdoc/doc-inline-extern-crate.rs new file mode 100644 index 00000000000..0eb4c149060 --- /dev/null +++ b/src/test/ui/rustdoc/doc-inline-extern-crate.rs @@ -0,0 +1,9 @@ +#[doc(inline)] +//~^ ERROR conflicting +#[doc(no_inline)] +pub extern crate core; + +// no warning +pub extern crate alloc; + +fn main() {} diff --git a/src/test/ui/rustdoc/doc-inline-extern-crate.stderr b/src/test/ui/rustdoc/doc-inline-extern-crate.stderr new file mode 100644 index 00000000000..41518295b12 --- /dev/null +++ b/src/test/ui/rustdoc/doc-inline-extern-crate.stderr @@ -0,0 +1,13 @@ +error: conflicting doc inlining attributes + --> $DIR/doc-inline-extern-crate.rs:1:7 + | +LL | #[doc(inline)] + | ^^^^^^ this attribute... +LL | +LL | #[doc(no_inline)] + | ^^^^^^^^^ ...conflicts with this attribute + | + = help: remove one of the conflicting attributes + +error: aborting due to previous error + diff --git a/src/test/ui/safe-extern-statics-mut.stderr b/src/test/ui/safe-extern-statics-mut.mir.stderr index 38803883414..cec5f9d9c9f 100644 --- a/src/test/ui/safe-extern-statics-mut.stderr +++ b/src/test/ui/safe-extern-statics-mut.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:11:13 + --> $DIR/safe-extern-statics-mut.rs:13:13 | LL | let b = B; | ^ use of mutable static @@ -7,7 +7,7 @@ LL | let b = B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:12:14 + --> $DIR/safe-extern-statics-mut.rs:14:14 | LL | let rb = &B; | ^^ use of mutable static @@ -15,7 +15,7 @@ LL | let rb = &B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:13:14 + --> $DIR/safe-extern-statics-mut.rs:15:14 | LL | let xb = XB; | ^^ use of mutable static @@ -23,7 +23,7 @@ LL | let xb = XB; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:14:15 + --> $DIR/safe-extern-statics-mut.rs:16:15 | LL | let xrb = &XB; | ^^^ use of mutable static diff --git a/src/test/ui/safe-extern-statics-mut.rs b/src/test/ui/safe-extern-statics-mut.rs index 324fa443aa5..389a4589a71 100644 --- a/src/test/ui/safe-extern-statics-mut.rs +++ b/src/test/ui/safe-extern-statics-mut.rs @@ -1,4 +1,6 @@ // aux-build:extern-statics.rs +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck extern crate extern_statics; use extern_statics::*; diff --git a/src/test/ui/safe-extern-statics-mut.thir.stderr b/src/test/ui/safe-extern-statics-mut.thir.stderr new file mode 100644 index 00000000000..8e6d2805a0b --- /dev/null +++ b/src/test/ui/safe-extern-statics-mut.thir.stderr @@ -0,0 +1,35 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:13:13 + | +LL | let b = B; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:14:15 + | +LL | let rb = &B; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:15:14 + | +LL | let xb = XB; + | ^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:16:16 + | +LL | let xrb = &XB; + | ^^ 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 4 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/safe-extern-statics.stderr b/src/test/ui/safe-extern-statics.mir.stderr index b42572ea3ee..102abd0816f 100644 --- a/src/test/ui/safe-extern-statics.stderr +++ b/src/test/ui/safe-extern-statics.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:11:13 + --> $DIR/safe-extern-statics.rs:13:13 | LL | let a = A; | ^ use of extern static @@ -7,7 +7,7 @@ LL | let a = A; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:12:14 + --> $DIR/safe-extern-statics.rs:14:14 | LL | let ra = &A; | ^^ use of extern static @@ -15,7 +15,7 @@ LL | let ra = &A; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:13:14 + --> $DIR/safe-extern-statics.rs:15:14 | LL | let xa = XA; | ^^ use of extern static @@ -23,7 +23,7 @@ LL | let xa = XA; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:14:15 + --> $DIR/safe-extern-statics.rs:16:15 | LL | let xra = &XA; | ^^^ use of extern static diff --git a/src/test/ui/safe-extern-statics.rs b/src/test/ui/safe-extern-statics.rs index 6fa4c4aaca5..0aa90c442ea 100644 --- a/src/test/ui/safe-extern-statics.rs +++ b/src/test/ui/safe-extern-statics.rs @@ -1,4 +1,6 @@ // aux-build:extern-statics.rs +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck extern crate extern_statics; use extern_statics::*; diff --git a/src/test/ui/safe-extern-statics.thir.stderr b/src/test/ui/safe-extern-statics.thir.stderr new file mode 100644 index 00000000000..7fd2182c4c6 --- /dev/null +++ b/src/test/ui/safe-extern-statics.thir.stderr @@ -0,0 +1,35 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:13:13 + | +LL | let a = A; + | ^ 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[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:14:15 + | +LL | let ra = &A; + | ^ 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[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:15:14 + | +LL | let xa = XA; + | ^^ 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[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:16:16 + | +LL | let xra = &XA; + | ^^ 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 4 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/sanitize/crt-static.rs b/src/test/ui/sanitize/crt-static.rs new file mode 100644 index 00000000000..f5dd2a40cc4 --- /dev/null +++ b/src/test/ui/sanitize/crt-static.rs @@ -0,0 +1,5 @@ +// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/src/test/ui/sanitize/crt-static.stderr b/src/test/ui/sanitize/crt-static.stderr new file mode 100644 index 00000000000..3a9c636d760 --- /dev/null +++ b/src/test/ui/sanitize/crt-static.stderr @@ -0,0 +1,4 @@ +error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/issue-85915-simd-ptrs.rs b/src/test/ui/simd/issue-85915-simd-ptrs.rs new file mode 100644 index 00000000000..6fe415545f8 --- /dev/null +++ b/src/test/ui/simd/issue-85915-simd-ptrs.rs @@ -0,0 +1,67 @@ +// 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.]); + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs index 103132c18ae..da5c42a1a98 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs @@ -1,5 +1,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)] diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs new file mode 100644 index 00000000000..ae321c974b9 --- /dev/null +++ b/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs @@ -0,0 +1,23 @@ +// 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])); +} diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs new file mode 100644 index 00000000000..3e02b08ce5d --- /dev/null +++ b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs @@ -0,0 +1,12 @@ +// 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; +} diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr new file mode 100644 index 00000000000..3888e7a0f38 --- /dev/null +++ b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr @@ -0,0 +1,4 @@ +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 + diff --git a/src/test/ui/simd/simd-type-wide-ptr.rs b/src/test/ui/simd/simd-type-wide-ptr.rs new file mode 100644 index 00000000000..88f62a07ea0 --- /dev/null +++ b/src/test/ui/simd/simd-type-wide-ptr.rs @@ -0,0 +1,12 @@ +// 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; +} diff --git a/src/test/ui/simd/simd-type-wide-ptr.stderr b/src/test/ui/simd/simd-type-wide-ptr.stderr new file mode 100644 index 00000000000..51d3c005072 --- /dev/null +++ b/src/test/ui/simd/simd-type-wide-ptr.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/wasm-simd-indirect.rs b/src/test/ui/simd/wasm-simd-indirect.rs new file mode 100644 index 00000000000..88f92fce2b2 --- /dev/null +++ b/src/test/ui/simd/wasm-simd-indirect.rs @@ -0,0 +1,31 @@ +// build-pass + +#[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() {} diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.mir.stderr index c35a3349121..c2adb7be7a2 100644 --- a/src/test/ui/span/lint-unused-unsafe.stderr +++ b/src/test/ui/span/lint-unused-unsafe.mir.stderr @@ -1,23 +1,23 @@ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:16:13 + --> $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:4:9 + --> $DIR/lint-unused-unsafe.rs:7:9 | LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:17:13 + --> $DIR/lint-unused-unsafe.rs:20:13 | LL | fn bad2() { unsafe { bad1() } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:18:20 + --> $DIR/lint-unused-unsafe.rs:21:20 | LL | unsafe fn bad3() { unsafe {} } | ---------------- ^^^^^^ unnecessary `unsafe` block @@ -25,13 +25,13 @@ LL | unsafe fn bad3() { unsafe {} } | because it's nested under this `unsafe` fn error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:19:13 + --> $DIR/lint-unused-unsafe.rs:22:13 | LL | fn bad4() { unsafe { callback(||{}) } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:20:20 + --> $DIR/lint-unused-unsafe.rs:23:20 | LL | unsafe fn bad5() { unsafe { unsf() } } | ---------------- ^^^^^^ unnecessary `unsafe` block @@ -39,7 +39,7 @@ LL | unsafe fn bad5() { unsafe { unsf() } } | because it's nested under this `unsafe` fn error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:23:9 + --> $DIR/lint-unused-unsafe.rs:26:9 | LL | unsafe { // don't put the warning here | ------ because it's nested under this `unsafe` block @@ -47,7 +47,7 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:29:5 + --> $DIR/lint-unused-unsafe.rs:32:5 | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn @@ -55,7 +55,7 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:30:9 + --> $DIR/lint-unused-unsafe.rs:33:9 | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn diff --git a/src/test/ui/span/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs index b6c4894d918..b889cc981ca 100644 --- a/src/test/ui/span/lint-unused-unsafe.rs +++ b/src/test/ui/span/lint-unused-unsafe.rs @@ -1,5 +1,8 @@ // 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)] diff --git a/src/test/ui/span/lint-unused-unsafe.thir.stderr b/src/test/ui/span/lint-unused-unsafe.thir.stderr new file mode 100644 index 00000000000..dda45c3679a --- /dev/null +++ b/src/test/ui/span/lint-unused-unsafe.thir.stderr @@ -0,0 +1,66 @@ +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 + diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr index e7ed0b710b2..a4659bc8712 100644 --- a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:6:5 + --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5 | LL | a += 3; | ^^^^^^ use of mutable static @@ -7,7 +7,7 @@ LL | a += 3; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:7:5 + --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5 | LL | a = 4; | ^^^^^ use of mutable static @@ -15,7 +15,7 @@ LL | a = 4; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:8:14 + --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14 | LL | let _b = a; | ^ use of mutable static diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs index 90aa2537a82..4f96acb3375 100644 --- a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { static mut a: i32; } diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr new file mode 100644 index 00000000000..2c62d4d8f3b --- /dev/null +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5 + | +LL | a += 3; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5 + | +LL | a = 4; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14 + | +LL | let _b = a; + | ^ 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 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/static/static-mut-requires-unsafe.stderr b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr index 85e468b333c..0d4ce056fc2 100644 --- a/src/test/ui/static/static-mut-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:4:5 + --> $DIR/static-mut-requires-unsafe.rs:7:5 | LL | a += 3; | ^^^^^^ use of mutable static @@ -7,7 +7,7 @@ LL | a += 3; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:5:5 + --> $DIR/static-mut-requires-unsafe.rs:8:5 | LL | a = 4; | ^^^^^ use of mutable static @@ -15,7 +15,7 @@ LL | a = 4; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:6:14 + --> $DIR/static-mut-requires-unsafe.rs:9:14 | LL | let _b = a; | ^ use of mutable static diff --git a/src/test/ui/static/static-mut-requires-unsafe.rs b/src/test/ui/static/static-mut-requires-unsafe.rs index 413b97e431d..ea3ba095007 100644 --- a/src/test/ui/static/static-mut-requires-unsafe.rs +++ b/src/test/ui/static/static-mut-requires-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + static mut a: isize = 3; fn main() { diff --git a/src/test/ui/static/static-mut-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr new file mode 100644 index 00000000000..1a1cf14271a --- /dev/null +++ b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:7:5 + | +LL | a += 3; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:8:5 + | +LL | a = 4; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:9:14 + | +LL | let _b = a; + | ^ 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 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs new file mode 100644 index 00000000000..d71747f9687 --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs @@ -0,0 +1,18 @@ +// 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); + } + ) +} diff --git a/src/test/ui/suggestions/format-borrow.rs b/src/test/ui/suggestions/format-borrow.rs index 63930e7f787..599a79fc08a 100644 --- a/src/test/ui/suggestions/format-borrow.rs +++ b/src/test/ui/suggestions/format-borrow.rs @@ -3,4 +3,8 @@ fn main() { //~^ 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 } diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr index 05d8fcd3ed6..0881b024712 100644 --- a/src/test/ui/suggestions/format-borrow.stderr +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -18,6 +18,26 @@ LL | let b: String = &format!("b"); | | 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`. diff --git a/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs new file mode 100644 index 00000000000..390d8bbdd53 --- /dev/null +++ b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs @@ -0,0 +1,9 @@ +// 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() { +} diff --git a/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr new file mode 100644 index 00000000000..735aeb0e0e7 --- /dev/null +++ b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr @@ -0,0 +1,20 @@ +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`. diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs new file mode 100644 index 00000000000..fa9d1a88928 --- /dev/null +++ b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs @@ -0,0 +1,25 @@ +// Tests that a suggestion is issued for type mismatch errors when a +// 1-tuple is expected and a parenthesized expression of non-tuple +// type is supplied. + +fn foo<T>(_t: (T,)) {} +struct S { _s: (String,) } + +fn main() { + let _x: (i32,) = (5); + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + foo((Some(3))); + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + let _s = S { _s: ("abc".to_string()) }; + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + // Do not issue the suggestion if the found type is already a tuple. + let t = (1, 2); + let _x: (i32,) = (t); + //~^ ERROR: mismatched types [E0308] +} diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr new file mode 100644 index 00000000000..575379690b4 --- /dev/null +++ b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:9:22 + | +LL | let _x: (i32,) = (5); + | ------ ^^^ expected tuple, found integer + | | + | expected due to this + | + = note: expected tuple `(i32,)` + found type `{integer}` +help: use a trailing comma to create a tuple with one element + | +LL | let _x: (i32,) = (5,); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:13:9 + | +LL | foo((Some(3))); + | ^^^^^^^^^ expected tuple, found enum `Option` + | + = note: expected tuple `(_,)` + found enum `Option<{integer}>` +help: use a trailing comma to create a tuple with one element + | +LL | foo((Some(3),)); + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:17:22 + | +LL | let _s = S { _s: ("abc".to_string()) }; + | ^^^^^^^^^^^^^^^^^^^ expected tuple, found struct `String` + | + = note: expected tuple `(String,)` + found struct `String` +help: use a trailing comma to create a tuple with one element + | +LL | let _s = S { _s: ("abc".to_string(),) }; + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:23:22 + | +LL | let _x: (i32,) = (t); + | ------ ^^^ expected a tuple with 1 element, found one with 2 elements + | | + | expected due to this + | + = note: expected tuple `(i32,)` + found tuple `({integer}, {integer})` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs index 924bfd82eb8..66e1e77c905 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -17,7 +17,6 @@ fn main() { let fp = BufWriter::new(fp); //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied writeln!(fp, "hello world").unwrap(); //~ ERROR the method } diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index a9b06214fe8..71b09d43612 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -11,19 +11,6 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | LL | let fp = BufWriter::new(fp); - | ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` - | - ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL - | -LL | pub struct BufWriter<W: Write> { - | ----- required by this bound in `BufWriter` - | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - -error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:14 - | -LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL @@ -34,7 +21,7 @@ LL | pub struct BufWriter<W: Write> { = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:22:5 + --> $DIR/mut-borrow-needed-by-trait.rs:21:5 | LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds @@ -49,7 +36,7 @@ LL | pub struct BufWriter<W: Write> { which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-ref-macro.rs b/src/test/ui/suggestions/suggest-ref-macro.rs new file mode 100644 index 00000000000..6f780f32a14 --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-macro.rs @@ -0,0 +1,29 @@ +// 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 +} diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr new file mode 100644 index 00000000000..147001f0c94 --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-macro.stderr @@ -0,0 +1,34 @@ +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`. diff --git a/src/test/ui/suggestions/unnamable-types.rs b/src/test/ui/suggestions/unnamable-types.rs new file mode 100644 index 00000000000..5d0616443e5 --- /dev/null +++ b/src/test/ui/suggestions/unnamable-types.rs @@ -0,0 +1,39 @@ +// Test that we do not suggest to add type annotations for unnamable types. + +#![crate_type="lib"] +#![feature(generators)] + +const A = 5; +//~^ ERROR: missing type for `const` item +//~| HELP: provide a type for the item + +static B: _ = "abc"; +//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures +//~| NOTE: not allowed in type signatures +//~| HELP: replace with the correct type + + +// FIXME: this should also suggest a function pointer, as the closure is non-capturing +const C: _ = || 42; +//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures +//~| NOTE: not allowed in type signatures +//~| NOTE: however, the inferred type + +struct S<T> { t: T } +const D = S { t: { let i = 0; move || -> i32 { i } } }; +//~^ ERROR: missing type for `const` item +//~| NOTE: however, the inferred type + + +fn foo() -> i32 { 42 } +const E = foo; +//~^ ERROR: missing type for `const` item +//~| HELP: provide a type for the item +const F = S { t: foo }; +//~^ ERROR: missing type for `const` item +//~| HELP: provide a type for the item + + +const G = || -> i32 { yield 0; return 1; }; +//~^ ERROR: missing type for `const` item +//~| NOTE: however, the inferred type diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr new file mode 100644 index 00000000000..05a7baa68ba --- /dev/null +++ b/src/test/ui/suggestions/unnamable-types.stderr @@ -0,0 +1,66 @@ +error: missing type for `const` item + --> $DIR/unnamable-types.rs:6:7 + | +LL | const A = 5; + | ^ help: provide a type for the item: `A: i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/unnamable-types.rs:10:11 + | +LL | static B: _ = "abc"; + | ^ + | | + | not allowed in type signatures + | help: replace with the correct type: `&str` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/unnamable-types.rs:17:10 + | +LL | const C: _ = || 42; + | ^ not allowed in type signatures + | +note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named + --> $DIR/unnamable-types.rs:17:14 + | +LL | const C: _ = || 42; + | ^^^^^ + +error: missing type for `const` item + --> $DIR/unnamable-types.rs:23:7 + | +LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; + | ^ + | +note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named + --> $DIR/unnamable-types.rs:23:11 + | +LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing type for `const` item + --> $DIR/unnamable-types.rs:29:7 + | +LL | const E = foo; + | ^ help: provide a type for the item: `E: fn() -> i32` + +error: missing type for `const` item + --> $DIR/unnamable-types.rs:32:7 + | +LL | const F = S { t: foo }; + | ^ help: provide a type for the item: `F: S<fn() -> i32>` + +error: missing type for `const` item + --> $DIR/unnamable-types.rs:37:7 + | +LL | const G = || -> i32 { yield 0; return 1; }; + | ^ + | +note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43]` cannot be named + --> $DIR/unnamable-types.rs:37:11 + | +LL | const G = || -> i32 { yield 0; return 1; }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs index 164830fecee..7cdf404242d 100644 --- a/src/test/ui/target-feature/gate.rs +++ b/src/test/ui/target-feature/gate.rs @@ -27,6 +27,7 @@ // gate-test-f16c_target_feature // gate-test-riscv_target_feature // gate-test-ermsb_target_feature +// gate-test-bpf_target_feature #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr index 2d6abcc0a01..ee542b60a26 100644 --- a/src/test/ui/target-feature/gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:31:18 + --> $DIR/gate.rs:32:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs new file mode 100644 index 00000000000..4b868684a52 --- /dev/null +++ b/src/test/ui/target-feature/wasm-safe.rs @@ -0,0 +1,44 @@ +// 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() {} diff --git a/src/test/ui/test-attrs/test-type.rs b/src/test/ui/test-attrs/test-type.rs new file mode 100644 index 00000000000..3f0fa81373f --- /dev/null +++ b/src/test/ui/test-attrs/test-type.rs @@ -0,0 +1,28 @@ +// compile-flags: --test +// run-flags: --test-threads=1 +// check-run-results +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// ignore-emscripten no threads support +// run-pass + + +#[test] +fn test_ok() { + let _a = true; +} + +#[test] +#[should_panic] +fn test_panic() { + panic!(); +} + +#[test] +#[ignore] +fn test_no_run() { + loop{ + println!("Hello, world"); + } +} + +fn main() {} diff --git a/src/test/ui/test-attrs/test-type.run.stdout b/src/test/ui/test-attrs/test-type.run.stdout new file mode 100644 index 00000000000..be2fd8ae68c --- /dev/null +++ b/src/test/ui/test-attrs/test-type.run.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test test_no_run ... ignored +test test_ok ... ok +test test_panic - should panic ... ok + +test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/ui/test-panic-abort-nocapture.run.stdout b/src/test/ui/test-panic-abort-nocapture.run.stdout index 15b19676a7c..8a91732a754 100644 --- a/src/test/ui/test-panic-abort-nocapture.run.stdout +++ b/src/test/ui/test-panic-abort-nocapture.run.stdout @@ -2,7 +2,7 @@ running 4 tests test it_fails ... about to fail FAILED -test it_panics ... about to panic +test it_panics - should panic ... about to panic ok test it_works ... about to succeed ok diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout index 467f834afec..f608a8cdc55 100644 --- a/src/test/ui/test-panic-abort.run.stdout +++ b/src/test/ui/test-panic-abort.run.stdout @@ -2,7 +2,7 @@ running 5 tests test it_exits ... FAILED test it_fails ... FAILED -test it_panics ... ok +test it_panics - should panic ... ok test it_works ... ok test no_residual_environment ... ok diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs new file mode 100644 index 00000000000..dc542fe2db9 --- /dev/null +++ b/src/test/ui/thread-local-static.rs @@ -0,0 +1,17 @@ +// 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 + //~| ERROR calls in constant functions are limited to constant functions +} + +fn main() {} diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr new file mode 100644 index 00000000000..a213282eb85 --- /dev/null +++ b/src/test/ui/thread-local-static.stderr @@ -0,0 +1,50 @@ +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[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/thread-local-static.rs:9:5 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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 6 previous errors + +Some errors have detailed explanations: E0013, E0015, E0133, E0658. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/tool_lints.rs b/src/test/ui/tool_lints.rs index 9e4aa7a939a..ef27532f6de 100644 --- a/src/test/ui/tool_lints.rs +++ b/src/test/ui/tool_lints.rs @@ -1,5 +1,4 @@ #[warn(foo::bar)] //~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar` //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` -//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` fn main() {} diff --git a/src/test/ui/tool_lints.stderr b/src/test/ui/tool_lints.stderr index e06f6ddc1ca..d36cd193b15 100644 --- a/src/test/ui/tool_lints.stderr +++ b/src/test/ui/tool_lints.stderr @@ -14,14 +14,6 @@ LL | #[warn(foo::bar)] | = help: add `#![register_tool(foo)]` to the crate root -error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` - --> $DIR/tool_lints.rs:1:8 - | -LL | #[warn(foo::bar)] - | ^^^ - | - = help: add `#![register_tool(foo)]` to the crate root - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0710`. diff --git a/src/test/ui/traits/alias/style_lint.rs b/src/test/ui/traits/alias/style_lint.rs new file mode 100644 index 00000000000..33be20054b5 --- /dev/null +++ b/src/test/ui/traits/alias/style_lint.rs @@ -0,0 +1,8 @@ +// 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() {} diff --git a/src/test/ui/traits/alias/style_lint.stderr b/src/test/ui/traits/alias/style_lint.stderr new file mode 100644 index 00000000000..91e2ea90eb9 --- /dev/null +++ b/src/test/ui/traits/alias/style_lint.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/traits/safety-fn-body.stderr b/src/test/ui/traits/safety-fn-body.mir.stderr index 0aeb186828e..ea7b2048e83 100644 --- a/src/test/ui/traits/safety-fn-body.stderr +++ b/src/test/ui/traits/safety-fn-body.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/safety-fn-body.rs:11:9 + --> $DIR/safety-fn-body.rs:14:9 | LL | *self += 1; | ^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/traits/safety-fn-body.rs b/src/test/ui/traits/safety-fn-body.rs index df527747305..2cc4fe1b344 100644 --- a/src/test/ui/traits/safety-fn-body.rs +++ b/src/test/ui/traits/safety-fn-body.rs @@ -1,6 +1,9 @@ // Check that an unsafe impl does not imply that unsafe actions are // legal in the methods. +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + unsafe trait UnsafeTrait : Sized { fn foo(self) { } } diff --git a/src/test/ui/traits/safety-fn-body.thir.stderr b/src/test/ui/traits/safety-fn-body.thir.stderr new file mode 100644 index 00000000000..23696c32bef --- /dev/null +++ b/src/test/ui/traits/safety-fn-body.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/safety-fn-body.rs:14:9 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/try-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs index 87585822f57..385f5510fb4 100644 --- a/src/test/ui/try-trait/bad-interconversion.rs +++ b/src/test/ui/try-trait/bad-interconversion.rs @@ -20,7 +20,7 @@ fn control_flow_to_result() -> Result<u64, String> { 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> { @@ -30,18 +30,18 @@ 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(()) } diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index e396256de22..f5b315c2519 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -40,12 +40,12 @@ LL | | } = 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` @@ -66,7 +66,7 @@ LL | | } = 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> { @@ -77,10 +77,9 @@ LL | | } | |_- 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> { @@ -92,10 +91,9 @@ LL | | } | |_- 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> { diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr index 92087c2aba2..9f7d80d4f23 100644 --- a/src/test/ui/try-trait/option-to-result.stderr +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -12,13 +12,13 @@ LL | | } = 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` diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr index 0880136d71b..05b63a00dfb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr @@ -1,5 +1,5 @@ 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))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ 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 diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr index 20ebdd9cb50..ad111e23b15 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr @@ -1,11 +1,11 @@ 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 diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs index 66bb079b25a..bbc67ecc97a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.rs +++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs @@ -1,4 +1,3 @@ -#![feature(member_constraints)] // revisions: min_tait full_tait #![feature(min_type_alias_impl_trait)] #![cfg_attr(full_tait, feature(type_alias_impl_trait))] diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs new file mode 100644 index 00000000000..ecad910f7d5 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs @@ -0,0 +1,12 @@ +// check-pass +#![feature(min_type_alias_impl_trait)] + +type X<A: ToString + Clone, B: ToString + Clone> = impl ToString; + +fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) { + (a.clone(), a) +} + +fn main() { + println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1)); +} diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs new file mode 100644 index 00000000000..67351e20159 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/73481 +// This test used to cause unsoundness, since one of the two possible +// resolutions was chosen at random instead of erroring due to conflicts. + +#![feature(min_type_alias_impl_trait)] + +type X<A, B> = impl Into<&'static A>; +//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied + +fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) { + (a, a) +} + +fn main() { + println!("{}", <X<_, _> as Into<&String>>::into(f(&[1isize, 2, 3], String::new()).1)); +} diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr new file mode 100644 index 00000000000..731c6e2788d --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied + --> $DIR/multiple-def-uses-in-one-fn.rs:7:16 + | +LL | type X<A, B> = impl Into<&'static A>; + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` + | + = note: required because of the requirements on the impl of `Into<&'static B>` for `&A` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs new file mode 100644 index 00000000000..38aa18fe40e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs @@ -0,0 +1,16 @@ +// https://github.com/rust-lang/rust/issues/73481 +// This test used to cause unsoundness, since one of the two possible +// resolutions was chosen at random instead of erroring due to conflicts. + +#![feature(min_type_alias_impl_trait)] + +type X<A: ToString + Clone, B: ToString + Clone> = impl ToString; +//~^ ERROR could not find defining uses + +fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) { + (a.clone(), a) +} + +fn main() { + println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1)); +} diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr new file mode 100644 index 00000000000..c00973c0761 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr @@ -0,0 +1,8 @@ +error: could not find defining uses + --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52 + | +LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs new file mode 100644 index 00000000000..17e90005811 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/73481 +// This test used to cause unsoundness, since one of the two possible +// resolutions was chosen at random instead of erroring due to conflicts. + +#![feature(min_type_alias_impl_trait)] + +type X<A: ToString + Clone, B: ToString + Clone> = impl ToString; + +fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) { + (a, b) +} + +fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) { + (a, b) + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr new file mode 100644 index 00000000000..bbe709dccab --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 + | +LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) { + | - - found type parameter + | | + | expected type parameter +LL | (a, b) + | ^ expected type parameter `A`, found type parameter `B` + | + = note: expected type parameter `A` + found type parameter `B` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.full_tait.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.full_tait.stderr index 75e4cb3e2d8..bd7cbd444d7 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.full_tait.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.full_tait.stderr @@ -79,7 +79,7 @@ LL | static TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&str` + | help: replace with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:19:15 @@ -88,7 +88,7 @@ LL | static TEST4: _ = 145; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:22:15 @@ -210,7 +210,7 @@ LL | static B: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:80:15 @@ -244,7 +244,7 @@ LL | static FN_TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&str` + | help: replace with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:92:22 @@ -253,7 +253,7 @@ LL | static FN_TEST4: _ = 145; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:95:22 @@ -435,7 +435,7 @@ LL | const _: Option<_> = map(value); | ^^^^^^^^^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `Option<u8>` + | help: replace with the correct type: `Option<u8>` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:144:31 @@ -526,7 +526,7 @@ LL | const D: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:201:26 @@ -639,7 +639,7 @@ LL | const D: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error: aborting due to 69 previous errors; 1 warning emitted diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.min_tait.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.min_tait.stderr index c6758c52a91..afd6aaf4e55 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.min_tait.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.min_tait.stderr @@ -70,7 +70,7 @@ LL | static TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&str` + | help: replace with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:19:15 @@ -79,7 +79,7 @@ LL | static TEST4: _ = 145; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:22:15 @@ -201,7 +201,7 @@ LL | static B: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:80:15 @@ -235,7 +235,7 @@ LL | static FN_TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&str` + | help: replace with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:92:22 @@ -244,7 +244,7 @@ LL | static FN_TEST4: _ = 145; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:95:22 @@ -426,7 +426,7 @@ LL | const _: Option<_> = map(value); | ^^^^^^^^^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `Option<u8>` + | help: replace with the correct type: `Option<u8>` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:144:31 @@ -517,7 +517,7 @@ LL | const D: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:201:26 @@ -630,7 +630,7 @@ LL | const D: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error: aborting due to 69 previous errors diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr index f868c8d4834..2b64df774b0 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -14,7 +14,7 @@ LL | const TEST2: _ = 42u32; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `u32` + | help: replace with the correct type: `u32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:10:14 @@ -23,7 +23,7 @@ LL | const TEST3: _ = Some(42); | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `Option<i32>` + | help: replace with the correct type: `Option<i32>` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:13:22 @@ -38,7 +38,7 @@ LL | const TEST5: _ = 42; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:24:18 @@ -47,7 +47,7 @@ LL | const TEST6: _ = 13; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `i32` + | help: replace with the correct type: `i32` error: aborting due to 6 previous errors diff --git a/src/test/ui/unknown-lint-tool-name.rs b/src/test/ui/unknown-lint-tool-name.rs index 84ab7c1944a..cd5d2f028af 100644 --- a/src/test/ui/unknown-lint-tool-name.rs +++ b/src/test/ui/unknown-lint-tool-name.rs @@ -1,8 +1,6 @@ #![deny(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar` //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` - //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` #[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar` //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` - //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar` fn main() {} diff --git a/src/test/ui/unknown-lint-tool-name.stderr b/src/test/ui/unknown-lint-tool-name.stderr index 1d145515abf..5f8349ce6c3 100644 --- a/src/test/ui/unknown-lint-tool-name.stderr +++ b/src/test/ui/unknown-lint-tool-name.stderr @@ -7,7 +7,7 @@ LL | #![deny(foo::bar)] = help: add `#![register_tool(foo)]` to the crate root error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` - --> $DIR/unknown-lint-tool-name.rs:5:9 + --> $DIR/unknown-lint-tool-name.rs:4:9 | LL | #[allow(foo::bar)] | ^^^ @@ -23,29 +23,13 @@ LL | #![deny(foo::bar)] = help: add `#![register_tool(foo)]` to the crate root error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` - --> $DIR/unknown-lint-tool-name.rs:5:9 + --> $DIR/unknown-lint-tool-name.rs:4:9 | LL | #[allow(foo::bar)] | ^^^ | = help: add `#![register_tool(foo)]` to the crate root -error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` - --> $DIR/unknown-lint-tool-name.rs:1:9 - | -LL | #![deny(foo::bar)] - | ^^^ - | - = help: add `#![register_tool(foo)]` to the crate root - -error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar` - --> $DIR/unknown-lint-tool-name.rs:5:9 - | -LL | #[allow(foo::bar)] - | ^^^ - | - = help: add `#![register_tool(foo)]` to the crate root - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0710`. diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr index 88322c3a0a6..33f762ccf63 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45087-unreachable-unsafe.rs:3:5 + --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs index 5edf7a47e2f..071cea8fbd7 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn main() { return; *(1 as *mut u32) = 42; diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr new file mode 100644 index 00000000000..73a113652b8 --- /dev/null +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs new file mode 100644 index 00000000000..72f7b674777 --- /dev/null +++ b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs @@ -0,0 +1,27 @@ +// 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 + } + }; +} diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.mir.stderr index 4e43df495c0..f9ef7834e1e 100644 --- a/src/test/ui/unsafe/ranged_ints.stderr +++ b/src/test/ui/unsafe/ranged_ints.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - --> $DIR/ranged_ints.rs:7:14 + --> $DIR/ranged_ints.rs:10:14 | LL | let _x = NonZero(0); | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs index 0fa2da917e9..05efe87ba6e 100644 --- a/src/test/ui/unsafe/ranged_ints.rs +++ b/src/test/ui/unsafe/ranged_ints.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] #[rustc_layout_scalar_valid_range_start(1)] diff --git a/src/test/ui/unsafe/ranged_ints.thir.stderr b/src/test/ui/unsafe/ranged_ints.thir.stderr new file mode 100644 index 00000000000..f9ef7834e1e --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints.rs:10:14 + | +LL | let _x = NonZero(0); + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.mir.stderr index 584ad40a92b..33d134c7ce5 100644 --- a/src/test/ui/unsafe/ranged_ints_const.stderr +++ b/src/test/ui/unsafe/ranged_ints_const.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - --> $DIR/ranged_ints_const.rs:8:34 + --> $DIR/ranged_ints_const.rs:11:34 | LL | const fn foo() -> NonZero<u32> { NonZero(0) } | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs index 8477772867e..472b0968150 100644 --- a/src/test/ui/unsafe/ranged_ints_const.rs +++ b/src/test/ui/unsafe/ranged_ints_const.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] #[rustc_layout_scalar_valid_range_start(1)] diff --git a/src/test/ui/unsafe/ranged_ints_const.thir.stderr b/src/test/ui/unsafe/ranged_ints_const.thir.stderr new file mode 100644 index 00000000000..33d134c7ce5 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints_const.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints_const.rs:11:34 + | +LL | const fn foo() -> NonZero<u32> { NonZero(0) } + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints_macro.rs b/src/test/ui/unsafe/ranged_ints_macro.rs index 9192ecfe196..8293d029951 100644 --- a/src/test/ui/unsafe/ranged_ints_macro.rs +++ b/src/test/ui/unsafe/ranged_ints_macro.rs @@ -1,4 +1,7 @@ // build-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] macro_rules! apply { diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr index ad93267ca01..9a522fac65f 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr @@ -1,18 +1,18 @@ error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5 + --> $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:1:9 + --> $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:11:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -20,7 +20,7 @@ LL | *PTR; = 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 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static @@ -28,25 +28,25 @@ LL | VOID = (); = 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 + --> $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:2:9 + --> $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:24:5 + --> $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:22:8 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8 | LL | #[deny(warnings)] | ^^^^^^^^ @@ -54,7 +54,7 @@ LL | #[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 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -62,7 +62,7 @@ LL | *PTR; = 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 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static @@ -70,13 +70,13 @@ LL | VOID = (); = 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 + --> $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:44:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -84,7 +84,7 @@ LL | unsafe { unsafe { unsf() } } | because it's nested under this `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5 | LL | unsafe fn allow_level() { | ----------------------- because it's nested under this `unsafe` fn @@ -93,7 +93,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9 + --> $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 @@ -102,7 +102,7 @@ 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 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -110,7 +110,7 @@ LL | unsf(); = 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 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9 | LL | unsf(); | ^^^^^^ call to unsafe function diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index c8400a6fc4d..7ca714b85c2 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr new file mode 100644 index 00000000000..ad87690bb52 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr @@ -0,0 +1,122 @@ +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`. diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr index b2a30f81e05..fee645e4118 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-fn-assign-deref-ptr.rs:2:5 + --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5 | LL | *p = 0; | ^^^^^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs index 91264e790c8..a94e94375ae 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn f(p: *mut u8) { *p = 0; //~ ERROR dereference of raw pointer is unsafe return; diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr new file mode 100644 index 00000000000..bbe4a415b5e --- /dev/null +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr index 98cb7b876f8..a2614992445 100644 --- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-fn-deref-ptr.rs:2:12 + --> $DIR/unsafe-fn-deref-ptr.rs:5:12 | LL | return *p; | ^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs index 46445aa261d..dc989535bd6 100644 --- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn f(p: *const u8) -> u8 { return *p; //~ ERROR dereference of raw pointer is unsafe } diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr new file mode 100644 index 00000000000..a2614992445 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-fn-deref-ptr.rs:5:12 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr index 410d8d3fb40..99808495ea6 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-unstable-const-fn.rs:8:5 + --> $DIR/unsafe-unstable-const-fn.rs:11:5 | LL | *a == b | ^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs index c7120e05007..0476759ca6d 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![stable(feature = "foo", since = "1.33.0")] #![feature(staged_api)] #![feature(const_raw_ptr_deref)] diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr new file mode 100644 index 00000000000..99808495ea6 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-unstable-const-fn.rs:11:5 + | +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 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs index 3e1527e2c2e..e69df0359fd 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs @@ -1,7 +1,7 @@ // --extern-location with bad location type // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=badloc:in-the-test-file +// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs index 6fdf710a126..aee6233e428 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs @@ -1,7 +1,7 @@ // --extern-location with a raw reference // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=json:[{"malformed +// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs index 02a9869151f..c7988cd469e 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-json-json.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs @@ -2,7 +2,7 @@ // check-pass // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json +// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options #![warn(unused_crate_dependencies)] //~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr index 5fc8397e469..001ec6a2554 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr +++ b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr @@ -1,4 +1,4 @@ -{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":169,"byte_end":169,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":177,"byte_end":202,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;` +{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;` --> $DIR/extern-loc-json-json.rs:7:1 | LL | #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json.rs index 212610d532e..c0d76c86b89 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-json.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-json.rs @@ -2,7 +2,7 @@ // check-pass // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=json:{"key":123,"value":{}} +// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options #![warn(unused_crate_dependencies)] //~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs index 4768365a653..3590b9c2812 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs @@ -1,7 +1,7 @@ // --extern-location with no type // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=missing-loc-type +// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs index 207615ccc87..64c3d77ce08 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs @@ -2,7 +2,7 @@ // check-pass // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json +// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options #![warn(unused_crate_dependencies)] //~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr index 25f099927fd..4083bd51835 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr @@ -1,4 +1,4 @@ -{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":162,"byte_end":162,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":170,"byte_end":195,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;` +{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;` --> $DIR/extern-loc-raw-json.rs:7:1 | LL | #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs index 65b64268394..a9e7afbda31 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs @@ -1,7 +1,7 @@ // --extern-location with a raw reference // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=raw +// compile-flags:--extern-location bar=raw -Z unstable-options #![warn(unused_crate_dependencies)] diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.rs b/src/test/ui/unused-crate-deps/extern-loc-raw.rs index fc3fed1e10e..27d0975d01a 100644 --- a/src/test/ui/unused-crate-deps/extern-loc-raw.rs +++ b/src/test/ui/unused-crate-deps/extern-loc-raw.rs @@ -2,7 +2,7 @@ // check-pass // aux-crate:bar=bar.rs -// compile-flags:--extern-location bar=raw:in-the-test-file +// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options #![warn(unused_crate_dependencies)] //~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr index d031a68a51d..9c066a7bdb0 100644 --- a/src/test/ui/wf/wf-static-method.nll.stderr +++ b/src/test/ui/wf/wf-static-method.nll.stderr @@ -68,7 +68,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -LL | <Evil>::inherent_evil(b) // bug? shouldn't this be an error +LL | <Evil>::inherent_evil(b) | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/wf/wf-static-method.rs b/src/test/ui/wf/wf-static-method.rs index e5a1092175d..6e805d61265 100644 --- a/src/test/ui/wf/wf-static-method.rs +++ b/src/test/ui/wf/wf-static-method.rs @@ -47,7 +47,8 @@ fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { } fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { - <Evil>::inherent_evil(b) // bug? shouldn't this be an error + <Evil>::inherent_evil(b) + //~^ ERROR cannot infer an appropriate lifetime } diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr index 0c98a809025..c02a8fe4aaf 100644 --- a/src/test/ui/wf/wf-static-method.stderr +++ b/src/test/ui/wf/wf-static-method.stderr @@ -103,7 +103,34 @@ note: ...so that reference does not outlive borrowed content LL | <IndirectEvil>::static_evil(b) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements + --> $DIR/wf-static-method.rs:50:5 + | +LL | <Evil>::inherent_evil(b) + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 49:22... + --> $DIR/wf-static-method.rs:49:22 + | +LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | ^^ +note: ...so that reference does not outlive borrowed content + --> $DIR/wf-static-method.rs:50:27 + | +LL | <Evil>::inherent_evil(b) + | ^ +note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 49:18... + --> $DIR/wf-static-method.rs:49:18 + | +LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | ^^ +note: ...so that reference does not outlive borrowed content + --> $DIR/wf-static-method.rs:50:5 + | +LL | <Evil>::inherent_evil(b) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0312, E0478, E0495. For more information about an error, try `rustc --explain E0312`. diff --git a/src/test/ui/where-clauses/where-for-self.stderr b/src/test/ui/where-clauses/where-for-self.stderr index 84430ffcf88..d06afc1e423 100644 --- a/src/test/ui/where-clauses/where-for-self.stderr +++ b/src/test/ui/where-clauses/where-for-self.stderr @@ -6,3 +6,4 @@ LL | where for<'a> &'a T: for<'b> Bar<'b> error: aborting due to previous error +For more information about this error, try `rustc --explain E0316`. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 4e605caafe2..1e19b7b21d8 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -85,6 +85,8 @@ static TARGETS: &[&str] = &[ "armv7r-none-eabihf", "armv7s-apple-ios", "asmjs-unknown-emscripten", + "bpfeb-unknown-none", + "bpfel-unknown-none", "i386-apple-ios", "i586-pc-windows-msvc", "i586-unknown-linux-gnu", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 070e459c2d8b79c5b2ac5218064e7603329c92a +Subproject 44456677b5d1d82fe981c955dc5c67734b31f34 diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config index 9b5add4df1c..e95ea224cb6 100644 --- a/src/tools/clippy/.cargo/config +++ b/src/tools/clippy/.cargo/config @@ -2,6 +2,7 @@ uitest = "test --test compile-test" dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " +collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored" [build] rustflags = ["-Zunstable-options"] diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index ae6f1aa1b30..f27fee87dc1 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -90,6 +90,11 @@ jobs: - name: Checkout uses: actions/checkout@v2.3.3 + # FIXME: should not be necessary once 1.24.2 is the default version on the windows runner + - name: Update rustup + run: rustup self update + if: runner.os == 'Windows' + - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 204d56e2a98..41af8e190dd 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,195 @@ document. ## Unreleased / In Rust Nightly -[6ed6f1e...master](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...master) +[7c7683c...master](https://github.com/rust-lang/rust-clippy/compare/7c7683c...master) + +## Rust 1.53 + +Current beta, release 2021-06-17 + +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c) + +### New Lints + +* [`option_filter_map`] + [#6342](https://github.com/rust-lang/rust-clippy/pull/6342) +* [`branches_sharing_code`] + [#6463](https://github.com/rust-lang/rust-clippy/pull/6463) +* [`needless_for_each`] + [#6706](https://github.com/rust-lang/rust-clippy/pull/6706) +* [`if_then_some_else_none`] + [#6859](https://github.com/rust-lang/rust-clippy/pull/6859) +* [`non_octal_unix_permissions`] + [#7001](https://github.com/rust-lang/rust-clippy/pull/7001) +* [`unnecessary_self_imports`] + [#7072](https://github.com/rust-lang/rust-clippy/pull/7072) +* [`bool_assert_comparison`] + [#7083](https://github.com/rust-lang/rust-clippy/pull/7083) +* [`cloned_instead_of_copied`] + [#7098](https://github.com/rust-lang/rust-clippy/pull/7098) +* [`flat_map_option`] + [#7101](https://github.com/rust-lang/rust-clippy/pull/7101) + +### Moves and Deprecations + +* Deprecate [`filter_map`] lint + [#7059](https://github.com/rust-lang/rust-clippy/pull/7059) +* Move [`transmute_ptr_to_ptr`] to `pedantic` + [#7102](https://github.com/rust-lang/rust-clippy/pull/7102) + +### Enhancements + +* [`mem_replace_with_default`]: Also lint on common std constructors + [#6820](https://github.com/rust-lang/rust-clippy/pull/6820) +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods + [#6828](https://github.com/rust-lang/rust-clippy/pull/6828) +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: + [#6863](https://github.com/rust-lang/rust-clippy/pull/6863) + * Attempt to find a common path prefix in suggestion + * Don't lint on `Option` and `Result` + * Consider `Self` prefix +* [`explicit_deref_methods`]: Also lint on chained `deref` calls + [#6865](https://github.com/rust-lang/rust-clippy/pull/6865) +* [`or_fun_call`]: Also lint on `unsafe` blocks + [#6928](https://github.com/rust-lang/rust-clippy/pull/6928) +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and + `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938) +* [`search_is_some`]: Also check for `is_none` + [#6942](https://github.com/rust-lang/rust-clippy/pull/6942) +* [`string_lit_as_bytes`]: Also lint on `into_bytes` + [#6959](https://github.com/rust-lang/rust-clippy/pull/6959) +* [`len_without_is_empty`]: Also lint if function signatures of `len` and + `is_empty` don't match + [#6980](https://github.com/rust-lang/rust-clippy/pull/6980) +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern + [#6991](https://github.com/rust-lang/rust-clippy/pull/6991) +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!` + [#7029](https://github.com/rust-lang/rust-clippy/pull/7029) +* [`needless_return`]: Also lint in `async` functions + [#7067](https://github.com/rust-lang/rust-clippy/pull/7067) +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?` + [#7100](https://github.com/rust-lang/rust-clippy/pull/7100) +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are + now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138) + +### False Positive Fixes + +* [`upper_case_acronyms`]: No longer lints on public items + [#6805](https://github.com/rust-lang/rust-clippy/pull/6805) +* [`suspicious_map`]: No longer lints when side effects may occur inside the + `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831) +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions + [#6917](https://github.com/rust-lang/rust-clippy/pull/6917) +* [`wrong_self_convention`]: Now respects `Copy` types + [#6924](https://github.com/rust-lang/rust-clippy/pull/6924) +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come + from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935) +* [`map_entry`]: Better detect if the entry API can be used + [#6937](https://github.com/rust-lang/rust-clippy/pull/6937) +* [`or_fun_call`]: No longer lints on some `len` function calls + [#6950](https://github.com/rust-lang/rust-clippy/pull/6950) +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different + generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952) +* [`upper_case_acronyms`]: No longer lints on public items + [#6981](https://github.com/rust-lang/rust-clippy/pull/6981) +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation + of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982) +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before + suggesting to use `derive` instead + [#6993](https://github.com/rust-lang/rust-clippy/pull/6993) +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used + [#6996](https://github.com/rust-lang/rust-clippy/pull/6996) +* [`clone_on_copy`]: Only lint when using the `Clone` trait + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`wrong_self_convention`]: No longer lints inside a trait implementation + [#7002](https://github.com/rust-lang/rust-clippy/pull/7002) +* [`redundant_clone`]: No longer lints when the cloned value is modified while + the clone is in use + [#7011](https://github.com/rust-lang/rust-clippy/pull/7011) +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body + [#7018](https://github.com/rust-lang/rust-clippy/pull/7018) +* [`cargo_common_metadata`]: Remove author requirement + [#7026](https://github.com/rust-lang/rust-clippy/pull/7026) +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family + [#7060](https://github.com/rust-lang/rust-clippy/pull/7060) +* [`panic`]: No longer wrongfully lints on `debug_assert` with message + [#7063](https://github.com/rust-lang/rust-clippy/pull/7063) +* [`wrong_self_convention`]: No longer lints in trait implementations where no + `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064) +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is + involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076) +* [`suspicious_else_formatting`]: Allow Allman style braces + [#7087](https://github.com/rust-lang/rust-clippy/pull/7087) +* [`inconsistent_struct_constructor`]: No longer lints in macros + [#7097](https://github.com/rust-lang/rust-clippy/pull/7097) +* [`single_component_path_imports`]: No longer lints on macro re-exports + [#7120](https://github.com/rust-lang/rust-clippy/pull/7120) + +### Suggestion Fixes/Improvements + +* [`redundant_pattern_matching`]: Add a note when applying this lint would + change the drop order + [#6568](https://github.com/rust-lang/rust-clippy/pull/6568) +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion + [#6821](https://github.com/rust-lang/rust-clippy/pull/6821) +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains + [#6856](https://github.com/rust-lang/rust-clippy/pull/6856) +* [`inconsistent_struct_constructor`]: Make lint description and message clearer + [#6892](https://github.com/rust-lang/rust-clippy/pull/6892) +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)` + as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937) +* [`manual_flatten`]: Suggest to insert `copied` if necessary + [#6962](https://github.com/rust-lang/rust-clippy/pull/6962) +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or + when the value is from a macro call + [#6975](https://github.com/rust-lang/rust-clippy/pull/6975) +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant + [#6988](https://github.com/rust-lang/rust-clippy/pull/6988) +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`manual_map`]: Fix suggestion at the end of an if chain + [#7004](https://github.com/rust-lang/rust-clippy/pull/7004) +* Fix needless parenthesis output in multiple lint suggestions + [#7013](https://github.com/rust-lang/rust-clippy/pull/7013) +* [`needless_collect`]: Better explanation in the lint message + [#7020](https://github.com/rust-lang/rust-clippy/pull/7020) +* [`useless_vec`]: Now considers mutability + [#7036](https://github.com/rust-lang/rust-clippy/pull/7036) +* [`useless_format`]: Wrap the content in braces if necessary + [#7092](https://github.com/rust-lang/rust-clippy/pull/7092) +* [`single_match`]: Don't suggest an equality check for types which don't + implement `PartialEq` + [#7093](https://github.com/rust-lang/rust-clippy/pull/7093) +* [`from_over_into`]: Mention type in help message + [#7099](https://github.com/rust-lang/rust-clippy/pull/7099) +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call + [#7136](https://github.com/rust-lang/rust-clippy/pull/7136) + +### ICE Fixes + +* [`macro_use_imports`] + [#7022](https://github.com/rust-lang/rust-clippy/pull/7022) +* [`missing_panics_doc`] + [#7034](https://github.com/rust-lang/rust-clippy/pull/7034) +* [`tabs_in_doc_comments`] + [#7039](https://github.com/rust-lang/rust-clippy/pull/7039) +* [`missing_const_for_fn`] + [#7128](https://github.com/rust-lang/rust-clippy/pull/7128) + +### Others + +* [Clippy's lint + list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports + themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030) +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the + deprecation warning + [#7056](https://github.com/rust-lang/rust-clippy/pull/7056) ## Rust 1.52 -Current beta, release 2021-05-06 +Current stable, released 2021-05-06 [3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e) @@ -99,7 +283,7 @@ Current beta, release 2021-05-06 [#6682](https://github.com/rust-lang/rust-clippy/pull/6682) * [`unit_arg`]: No longer lints on unit arguments when they come from a path expression. [#6601](https://github.com/rust-lang/rust-clippy/pull/6601) -* [`cargo_common_metadata`]: No longer lints if +* [`cargo_common_metadata`]: No longer lints if [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field) is defined in the manifest [#6650](https://github.com/rust-lang/rust-clippy/pull/6650) @@ -124,11 +308,11 @@ Current beta, release 2021-05-06 * [`useless_format`]: Improved the documentation example [#6854](https://github.com/rust-lang/rust-clippy/pull/6854) -* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper [#6782](https://github.com/rust-lang/rust-clippy/pull/6782) ### Others -* Running `cargo clippy` after `cargo check` now works as expected +* Running `cargo clippy` after `cargo check` now works as expected (`cargo clippy` and `cargo check` no longer shares the same build cache) [#6687](https://github.com/rust-lang/rust-clippy/pull/6687) * Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed. @@ -145,7 +329,7 @@ Current beta, release 2021-05-06 ## Rust 1.51 -Current stable, released 2021-03-25 +Released 2021-03-25 [4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797) @@ -2309,6 +2493,7 @@ Released 2018-09-13 [`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 @@ -2365,6 +2550,7 @@ Released 2018-09-13 [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type +[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference @@ -2437,6 +2623,7 @@ Released 2018-09-13 [`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 @@ -2485,6 +2672,7 @@ Released 2018-09-13 [`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 @@ -2538,6 +2726,7 @@ Released 2018-09-13 [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute [`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT index 80d64472c70..238c919b69d 100644 --- a/src/tools/clippy/COPYRIGHT +++ b/src/tools/clippy/COPYRIGHT @@ -1,4 +1,4 @@ -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 diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index f010e609604..b003b15a11d 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -33,12 +33,13 @@ tempfile = { version = "3.1.0", optional = true } 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` @@ -49,7 +50,7 @@ rustc-workspace-hack = "1.0.0" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } [features] -deny-warnings = [] +deny-warnings = ["clippy_lints/deny-warnings"] integration = ["tempfile"] internal-lints = ["clippy_lints/internal-lints"] metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"] diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE index d821a4de2be..04169a42b8b 100644 --- a/src/tools/clippy/LICENSE-APACHE +++ b/src/tools/clippy/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. 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. diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT index b7c70dd4026..90a2d3950d1 100644 --- a/src/tools/clippy/LICENSE-MIT +++ b/src/tools/clippy/LICENSE-MIT @@ -1,6 +1,6 @@ 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 diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 8c0c16c443d..6c556f579ca 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -147,6 +147,7 @@ Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml value` mapping eg. ```toml +avoid-breaking-exported-api = false blacklisted-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` @@ -236,7 +237,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT ## 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 diff --git a/src/tools/clippy/build.rs b/src/tools/clippy/build.rs index 018375dbada..b5484bec3c8 100644 --- a/src/tools/clippy/build.rs +++ b/src/tools/clippy/build.rs @@ -14,6 +14,6 @@ fn main() { ); println!( "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", - rustc_tools_util::get_channel().unwrap_or_default() + rustc_tools_util::get_channel() ); } diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml new file mode 100644 index 00000000000..cda8d17eed4 --- /dev/null +++ b/src/tools/clippy/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 1e5a140e964..69f42aca8b6 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -1,5 +1,7 @@ -#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(once_cell)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; use regex::Regex; diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index f4da783502c..7040c257c83 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -1,4 +1,6 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] use clap::{App, Arg, ArgMatches, SubCommand}; use clippy_dev::{bless, fmt, ide_setup, new_lint, serve, stderr_length_check, update_lints}; diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 7ceb1da6a6e..48f2972ec58 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -30,7 +30,7 @@ rustc-semver = "1.1.0" url = { version = "2.1.0", features = ["serde"] } [features] -deny-warnings = [] +deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default internal-lints = ["clippy_utils/internal-lints"] metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"] diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs index 5fbf4bdbd18..49d4350123f 100644 --- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs @@ -3,9 +3,8 @@ use rustc_lint::{LateContext, LateLintPass}; 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; diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs index c560f545d6a..24c2a972811 100644 --- a/src/tools/clippy/clippy_lints/src/arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs @@ -1,4 +1,4 @@ -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}; diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index c565e29d078..5235b2642d1 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -1,4 +1,4 @@ -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}; @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { &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") { diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index c5b01461c1c..932cd58bf62 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { 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(..) => { @@ -343,13 +343,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { 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())); } } } diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs index f7daf3dab49..991ed94572c 100644 --- a/src/tools/clippy/clippy_lints/src/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs @@ -1,4 +1,4 @@ -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; @@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask { 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); } } } @@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp } 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)); } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 67f0e0c7870..e72399af232 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: HirId, ) { - NonminimalBoolVisitor { cx }.visit_body(body) + NonminimalBoolVisitor { cx }.visit_body(body); } } @@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { 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)?; @@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } 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() { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 040e0ca8864..c9c111a2847 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index dae5c86bd44..6e950738239 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); 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); } } } diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index 2a61d58e653..b6999bef6e7 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { "`if` chain can be rewritten with `match`", None, "consider rewriting the `if` chain to use `cmp` and `match`", - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs deleted file mode 100644 index 7e87f53e3fb..00000000000 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ /dev/null @@ -1 +0,0 @@ -pub use clippy_utils::consts::*; diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index f956d171bfb..376a14b8181 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint( } 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<'_>| { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 6e883942680..759f7d4062d 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -181,9 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { 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); } }, diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 4688b3d5105..04f3d77464f 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -1,6 +1,13 @@ +/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This +/// enables the simple extraction of the metadata without changing the current deprecation +/// declaration. +pub struct ClippyDeprecatedLint; + macro_rules! declare_deprecated_lint { - (pub $name: ident, $_reason: expr) => { - declare_lint!(pub $name, Allow, "deprecated lint") + { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => { + $(#[$attr])* + #[allow(dead_code)] + pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {}; } } @@ -134,3 +141,22 @@ declare_deprecated_lint! { 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" +} diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index e742cd626ab..840c1eba79d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Span}; +use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` @@ -310,15 +310,11 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx - .tcx - .all_local_trait_impls(()) - .get(©_id) - .map_or(false, |impls| { - impls - .iter() - .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did)) - }); + let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { + impls + .iter() + .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did)) + }); if !has_copy_impl { return; } diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index fb53b55ebd6..e67ec4e06c5 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -383,7 +383,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: let mut no_stars = String::with_capacity(doc.len()); for line in doc.lines() { let mut chars = line.chars(); - while let Some(c) = chars.next() { + for c in &mut chars { if c.is_whitespace() { no_stars.push(c); } else { diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs index 58543ae6e4e..4966638cb1b 100644 --- a/src/tools/clippy/clippy_lints/src/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs @@ -70,16 +70,16 @@ impl<'tcx> DoubleComparisons { #[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!(==); }, _ => (), }; diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs index 529807770f3..94b09bf7173 100644 --- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; 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; diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 8db5050a5ac..2eb8b1422ed 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -469,7 +469,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { 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); } diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 7a98ae39d3a..021136ac5e0 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! 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}; diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 0ecc0bc3eb6..b1a105a51c1 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -3,8 +3,8 @@ 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; @@ -40,36 +40,6 @@ declare_clippy_lint! { } 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. /// @@ -127,21 +97,22 @@ declare_clippy_lint! { 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 ]); @@ -167,33 +138,42 @@ fn partial_rmatch(post: &str, name: &str) -> usize { } 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); @@ -226,7 +206,7 @@ fn check_variant( }; span_lint_and_help( cx, - lint, + ENUM_VARIANT_NAMES, span, &format!("all variants have the same {}fix: `{}`", what, value), None, @@ -261,14 +241,14 @@ fn to_camel_case(item_name: &str) -> String { 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); @@ -286,7 +266,7 @@ impl EarlyLintPass for EnumVariantNames { ); } } - 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(); @@ -317,11 +297,9 @@ impl EarlyLintPass for EnumVariantNames { } } 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)); } diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index 90f391b5f5c..a3a8e748d99 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { vec![(left.span, lsnip), (right.span, rsnip)], ); }, - ) + ); } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } else if !lcpy && rcpy && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // &foo == bar @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // foo == &bar @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { rsnip, Applicability::MaybeIncorrect, // FIXME #2597 ); - }) + }); } }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs index f95ca86a2d0..4aa9c25b1b0 100644 --- a/src/tools/clippy/clippy_lints/src/erasing_op.rs +++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs @@ -1,11 +1,10 @@ +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`. /// diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 2f1aa53236d..8d066f305ee 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { for arg in args { // skip `foo(macro!())` if arg.span.ctxt() == expr.span.ctxt() { - check_closure(cx, arg) + check_closure(cx, arg); } } }, @@ -92,17 +92,19 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { 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; @@ -188,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a 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 }) } diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs index 41acf55dd7d..5fdf5bc9e9d 100644 --- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs +++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { 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); diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index e0b687b0205..e38384b01d4 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::{ +use clippy_utils::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; @@ -323,7 +323,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { cx, SUBOPTIMAL_FLOPS, parent.span, - "square can be computed more efficiently", + "multiply and add expressions can be calculated more efficiently and accurately", "consider using", format!( "{}.mul_add({}, {})", @@ -337,16 +337,6 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { return; } } - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "square can be computed more efficiently", - "consider using", - format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")), - Applicability::MachineApplicable, - ); } } } diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 20288427b4a..7f4fb68cf2f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { - self.mutates_static |= is_mutated_static(target) + self.mutates_static |= is_mutated_static(target); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index b8ea6990866..af759a48e10 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { 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`", ); } } diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index aa5494d5a7d..a666fee1a4a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -4,7 +4,7 @@ use rustc_middle::lint::in_external_macro; 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; @@ -13,15 +13,25 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<' 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; @@ -63,6 +73,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<' "this function has too many lines ({}/{})", line_count, too_many_lines_threshold ), - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 04730ace887..515b8887453 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { )); } } - }) + }); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs index 366b3b46a8a..99c461930e4 100644 --- a/src/tools/clippy/clippy_lints/src/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/identity_op.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; 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}; diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 30174fa2100..f2f830ca5c0 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) { "change `break` to `return` as shown", format!("return {}", snip), app, - ) + ); } #[derive(Clone, Copy, PartialEq, Eq)] @@ -147,7 +147,11 @@ fn lint_implicit_returns( visit_break_exprs(block, |break_expr, dest, sub_expr| { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && break_expr.span.ctxt() == ctxt { - lint_break(cx, break_expr.span, sub_expr.unwrap().span); + // At this point sub_expr can be `None` in async functions which either diverge, or return the + // unit type. + if let Some(sub_expr) = sub_expr { + lint_break(cx, break_expr.span, sub_expr.span); + } } else { // the break expression is from a macro call, add a return to the loop add_return = true; diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index d138c3a8acf..3b635071f28 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -58,7 +58,7 @@ declare_clippy_lint! { /// Foo { x, y }; /// ``` pub INCONSISTENT_STRUCT_CONSTRUCTOR, - style, + pedantic, "the order of the field init shorthand is inconsistent with the order in the struct definition" } diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 1c54599abc4..bfa284f333a 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -1,6 +1,6 @@ //! 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; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index afee20ce43e..6b887da2630 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { return; }, }; - span_lint(cx, lint, expr.span, msg) + span_lint(cx, lint, expr.span, msg); } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 4e0b1ae78df..ee41c4aea2f 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -1,12 +1,13 @@ //! lint on inherent implementations -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::in_macro; -use rustc_hir::def_id::DefIdMap; -use rustc_hir::{Crate, Impl, Item, ItemKind}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{in_macro, is_allowed}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::{def_id::LocalDefId, Crate, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; +use std::collections::hash_map::Entry; declare_clippy_lint! { /// **What it does:** Checks for multiple inherent implementations of a struct @@ -40,51 +41,96 @@ declare_clippy_lint! { "Multiple inherent impl that could be grouped" } -#[allow(clippy::module_name_repetitions)] -#[derive(Default)] -pub struct MultipleInherentImpl { - impls: DefIdMap<Span>, -} - -impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]); +declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]); impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { - fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl(Impl { - ref generics, - of_trait: None, - .. - }) = item.kind + fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) { + // Map from a type to it's first impl block. Needed to distinguish generic arguments. + // e.g. `Foo<Bar>` and `Foo<Baz>` + let mut type_map = FxHashMap::default(); + // List of spans to lint. (lint_span, first_span) + let mut lint_spans = Vec::new(); + + for (_, impl_ids) in cx + .tcx + .crate_inherent_impls(()) + .inherent_impls + .iter() + .filter(|(&id, impls)| { + impls.len() > 1 + // Check for `#[allow]` on the type definition + && !is_allowed( + cx, + MULTIPLE_INHERENT_IMPL, + cx.tcx.hir().local_def_id_to_hir_id(id), + ) + }) { - // Remember for each inherent implementation encountered its span and generics - // but filter out implementations that have generic params (type or lifetime) - // or are derived from a macro - if !in_macro(item.span) && generics.params.is_empty() { - self.impls.insert(item.def_id.to_def_id(), item.span); + for impl_id in impl_ids.iter().map(|id| id.expect_local()) { + match type_map.entry(cx.tcx.type_of(impl_id)) { + Entry::Vacant(e) => { + // Store the id for the first impl block of this type. The span is retrieved lazily. + e.insert(IdOrSpan::Id(impl_id)); + }, + Entry::Occupied(mut e) => { + if let Some(span) = get_impl_span(cx, impl_id) { + let first_span = match *e.get() { + IdOrSpan::Span(s) => s, + IdOrSpan::Id(id) => { + if let Some(s) = get_impl_span(cx, id) { + // Remember the span of the first block. + *e.get_mut() = IdOrSpan::Span(s); + s + } else { + // The first impl block isn't considered by the lint. Replace it with the + // current one. + *e.get_mut() = IdOrSpan::Span(span); + continue; + } + }, + }; + lint_spans.push((span, first_span)); + } + }, + } } + + // Switching to the next type definition, no need to keep the current entries around. + type_map.clear(); } - } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'_>) { - if !krate.items.is_empty() { - // Retrieve all inherent implementations from the crate, grouped by type - for impls in cx.tcx.crate_inherent_impls(()).inherent_impls.values() { - // Filter out implementations that have generic params (type or lifetime) - let mut impl_spans = impls.iter().filter_map(|impl_def| self.impls.get(impl_def)); - if let Some(initial_span) = impl_spans.next() { - impl_spans.for_each(|additional_span| { - span_lint_and_then( - cx, - MULTIPLE_INHERENT_IMPL, - *additional_span, - "multiple implementations of this structure", - |diag| { - diag.span_note(*initial_span, "first implementation here"); - }, - ) - }) - } - } + // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first. + lint_spans.sort_by_key(|x| x.0.lo()); + for (span, first_span) in lint_spans { + span_lint_and_note( + cx, + MULTIPLE_INHERENT_IMPL, + span, + "multiple implementations of this structure", + Some(first_span), + "first implementation here", + ); } } } + +/// Gets the span for the given impl block unless it's not being considered by the lint. +fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> { + let id = cx.tcx.hir().local_def_id_to_hir_id(id); + if let Node::Item(&Item { + kind: ItemKind::Impl(ref impl_item), + span, + .. + }) = cx.tcx.hir().get(id) + { + (!in_macro(span) && impl_item.generics.params.is_empty() && !is_allowed(cx, MULTIPLE_INHERENT_IMPL, id)) + .then(|| span) + } else { + None + } +} + +enum IdOrSpan { + Id(LocalDefId), + Span(Span), +} diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index c67c02eefa5..37011f5578d 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -7,9 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; 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}; @@ -177,7 +176,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, 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 { @@ -195,7 +194,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, false) + err_upcast_comparison(cx, span, lhs, false); } } } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index bb57adff7be..583514b22f9 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - 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); } } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 17e23781db7..e627b1385bc 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { 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, @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { 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, @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "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, @@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a result of a `#[must_use]` function", None, "consider explicitly using function result" - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 725aa54157e..e7dd3952b3a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -6,7 +6,6 @@ #![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)] @@ -42,6 +41,9 @@ extern crate rustc_target; 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; @@ -146,22 +148,8 @@ macro_rules! declare_clippy_lint { }; } -#[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] +#[cfg(feature = "metadata-collector-lint")] +mod deprecated_lints; mod utils; // begin lints modules, do not remove this comment, it’s used in `update_lints` @@ -289,6 +277,7 @@ mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; mod needless_arbitrary_self_type; +mod needless_bitwise_bool; mod needless_bool; mod needless_borrow; mod needless_borrowed_ref; @@ -363,6 +352,7 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; +mod unused_async; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -402,7 +392,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { #[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(), @@ -413,16 +402,6 @@ pub fn read_conf(sess: &Session) -> Conf { }, }; - 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 { @@ -502,6 +481,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "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` @@ -615,7 +602,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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, @@ -776,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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, @@ -793,13 +780,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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, @@ -834,9 +821,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: mutex_atomic::MUTEX_ATOMIC, mutex_atomic::MUTEX_INTEGER, needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, + needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, 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, @@ -960,6 +949,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_async::UNUSED_ASYNC, unused_io_amount::UNUSED_IO_AMOUNT, unused_self::UNUSED_SELF, unused_unit::UNUSED_UNIT, @@ -990,289 +980,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ]); // 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::default()); - } - } - - 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 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 - }) - }); - - 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::default()); - 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_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(arithmetic::FLOAT_ARITHMETIC), LintId::of(arithmetic::INTEGER_ARITHMETIC), @@ -1303,7 +1010,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1315,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1356,7 +1061,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1365,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1392,6 +1097,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1403,6 +1110,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1415,6 +1123,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1511,7 +1220,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(identity_op::IDENTITY_OP), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), LintId::of(inherent_to_string::INHERENT_TO_STRING), @@ -1591,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1606,6 +1315,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1635,6 +1345,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1681,7 +1392,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1764,7 +1474,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(len_zero::COMPARISON_TO_EMPTY), LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), @@ -1819,6 +1528,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1835,7 +1545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -1983,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -2027,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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), @@ -2058,14 +1769,304 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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(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); + } #[rustfmt::skip] diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 116ad072837..5ae68ba5b2f 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -205,7 +205,7 @@ fn could_use_elision<'tcx>( 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() { @@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { // `'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> { diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index e93b2e36b86..e0c5578bd60 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -231,7 +231,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -294,7 +294,7 @@ impl LiteralDigitGrouping { } }; if should_warn { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); } } } @@ -424,7 +424,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -446,7 +446,7 @@ impl DecimalLiteralRepresentation { 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); }); } } diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index ce02ad013be..f0327b5d777 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m "to write this more concisely, try", format!("&{}{}", muta, object), applicability, - ) + ); } /// Returns `true` if the type of expr is one that provides `IntoIterator` impls diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 1425d50f560..d07b5a93b67 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -88,10 +88,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { 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)); } } } @@ -100,10 +100,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { 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)); } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index 9662a0b22a3..eb82c9c27c3 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -1,16 +1,15 @@ use super::NEEDLESS_COLLECT; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +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, match_type}; -use clippy_utils::{is_trait_method, path_to_local_id, paths}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; - use rustc_span::symbol::{sym, Ident}; use rustc_span::{MultiSpan, Span}; @@ -28,23 +27,37 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if let Some(generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id); - if is_type_diagnostic_item(cx, ty, sym::vec_type) - || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) - || match_type(cx, ty, &paths::BTREEMAP) - || is_type_diagnostic_item(cx, ty, sym::hashmap_type); - if let Some(sugg) = match &*method.ident.name.as_str() { - "len" => Some("count()".to_string()), - "is_empty" => Some("next().is_none()".to_string()), - "contains" => { - let contains_arg = snippet(cx, args[1].span, "??"); - let (arg, pred) = contains_arg - .strip_prefix('&') - .map_or(("&x", &*contains_arg), |s| ("x", s)); - Some(format!("any(|{}| x == {})", arg, pred)) - } - _ => None, - }; then { + let mut applicability = Applicability::MachineApplicable; + let is_empty_sugg = "next().is_none()".to_string(); + let method_name = &*method.ident.name.as_str(); + let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) || + is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || + is_type_diagnostic_item(cx, ty, sym::LinkedList) || + is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { + match method_name { + "len" => "count()".to_string(), + "is_empty" => is_empty_sugg, + "contains" => { + let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability); + let (arg, pred) = contains_arg + .strip_prefix('&') + .map_or(("&x", &*contains_arg), |s| ("x", s)); + format!("any(|{}| x == {})", arg, pred) + } + _ => return, + } + } + else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || + is_type_diagnostic_item(cx, ty, sym::hashmap_type) { + match method_name { + "is_empty" => is_empty_sugg, + _ => return, + } + } + else { + return; + }; span_lint_and_sugg( cx, NEEDLESS_COLLECT, @@ -52,7 +65,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont NEEDLESS_COLLECT_MSG, "replace with", sugg, - Applicability::MachineApplicable, + applicability, ); } } @@ -86,7 +99,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || - match_type(cx, ty, &paths::LINKED_LIST); + is_type_diagnostic_item(cx, ty, sym::LinkedList); if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident); if let [iter_call] = &*iter_calls; then { @@ -103,9 +116,10 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo // 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| { diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index cb2c83e9029..0f6cd5de761 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", item_str, vec_str, item_str ), - ) + ); } if !matches!(pat.kind, PatKind::Wild) { diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 4db6644b9d7..2f7360210ba 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -80,10 +80,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } }, 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; }, _ => (), } @@ -207,7 +207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = InitializeVisitorState::DontWarn + self.state = InitializeVisitorState::DontWarn; }, _ => (), } @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } } - walk_pat(self, pat) + walk_pat(self, pat); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index 55404b87ec9..5f9ebad25e8 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,5 +1,5 @@ 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; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 82715d9bafa..63560047578 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -1,170 +1,347 @@ -use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::implements_trait; -use clippy_utils::usage::mutated_variables; -use clippy_utils::{ - get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, -}; +use clippy_utils::{get_enclosing_loop, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind}; +use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}; +use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; -use rustc_span::symbol::sym; +use rustc_span::{symbol::sym, Span, Symbol}; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind { - let pat = &arms[0].pat.kind; - if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) = - (pat, &match_expr.kind) - { - let iter_expr = &method_args[0]; - - // Don't lint when the iterator is recreated on every iteration - if_chain! { - if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind; - if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]); - then { - return; - } - } + let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! { + if let ExprKind::Match(scrutinee_expr, [arm, _], MatchSource::WhileLetDesugar) = expr.kind; + // check for `Some(..)` pattern + if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = arm.pat.kind; + if let Res::Def(_, pat_did) = pat_path.res; + if match_def_path(cx, pat_did, &paths::OPTION_SOME); + // check for call to `Iterator::next` + if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = scrutinee_expr.kind; + if method_name.ident.name == sym::next; + if is_trait_method(cx, scrutinee_expr, sym::Iterator); + if let Some(iter_expr) = try_parse_iter_expr(cx, iter_expr); + // get the loop containing the match expression + if let Some((_, Node::Expr(loop_expr))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); + if !uses_iter(cx, &iter_expr, arm.body); + then { + (scrutinee_expr, iter_expr, some_pat, loop_expr) + } else { + return; + } + }; - let lhs_constructor = last_path_segment(qpath); - if method_path.ident.name == sym::next - && is_trait_method(cx, match_expr, sym::Iterator) - && lhs_constructor.ident.name == sym::Some - && (pat_args.is_empty() - || !is_refutable(cx, pat_args[0]) - && !is_used_inside(cx, iter_expr, arms[0].body) - && !is_iterator_used_after_while_let(cx, iter_expr) - && !is_nested(cx, expr, &method_args[0])) - { - let mut applicability = Applicability::MachineApplicable; - let iterator = snippet_with_applicability(cx, method_args[0].span, "_", &mut applicability); - let loop_var = if pat_args.is_empty() { - "_".to_string() - } else { - snippet_with_applicability(cx, pat_args[0].span, "_", &mut applicability).into_owned() - }; - span_lint_and_sugg( - cx, - WHILE_LET_ON_ITERATOR, - expr.span.with_hi(match_expr.span.hi()), - "this loop could be written as a `for` loop", - "try", - format!("for {} in {}", loop_var, iterator), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + let loop_var = if let Some(some_pat) = some_pat.first() { + if is_refutable(cx, some_pat) { + // Refutable patterns don't work with for loops. + return; } - } -} + snippet_with_applicability(cx, some_pat.span, "..", &mut applicability) + } else { + "_".into() + }; -fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool { - let def_id = match path_to_local(expr) { - Some(id) => id, - None => return false, + // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be + // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used + // afterwards a mutable borrow of a field isn't necessary. + let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) { + "&mut " + } else { + "" }; - if let Some(used_mutably) = mutated_variables(container, cx) { - if used_mutably.contains(&def_id) { - return true; + + let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + WHILE_LET_ON_ITERATOR, + expr.span.with_hi(scrutinee_expr.span.hi()), + "this loop could be written as a `for` loop", + "try", + format!("for {} in {}{}", loop_var, ref_mut, iterator), + applicability, + ); +} + +#[derive(Debug)] +struct IterExpr { + /// The span of the whole expression, not just the path and fields stored here. + span: Span, + /// The fields used, in order of child to parent. + fields: Vec<Symbol>, + /// The path being used. + path: Res, +} +/// Parses any expression to find out which field of which variable is used. Will return `None` if +/// the expression might have side effects. +fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> { + let span = e.span; + let mut fields = Vec::new(); + loop { + match e.kind { + ExprKind::Path(ref path) => { + break Some(IterExpr { + span, + fields, + path: cx.qpath_res(path, e.hir_id), + }); + }, + ExprKind::Field(base, name) => { + fields.push(name.name); + e = base; + }, + // Dereferencing a pointer has no side effects and doesn't affect which field is being used. + ExprKind::Unary(UnOp::Deref, base) if cx.typeck_results().expr_ty(base).is_ref() => e = base, + + // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have + // already been seen. + ExprKind::Index(base, idx) if !idx.can_have_side_effects() => { + fields.clear(); + e = base; + }, + ExprKind::Unary(UnOp::Deref, base) => { + fields.clear(); + e = base; + }, + + // No effect and doesn't affect which field is being used. + ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _) => e = base, + _ => break None, } } - false } -fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool { - let def_id = match path_to_local(iter_expr) { - Some(id) => id, - None => return false, - }; - let mut visitor = VarUsedAfterLoopVisitor { - def_id, - iter_expr_id: iter_expr.hir_id, - past_while_let: false, - var_used_after_while_let: false, - }; - if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { - walk_block(&mut visitor, enclosing_block); +fn is_expr_same_field(cx: &LateContext<'_>, mut e: &Expr<'_>, mut fields: &[Symbol], path_res: Res) -> bool { + loop { + match (&e.kind, fields) { + (&ExprKind::Field(base, name), [head_field, tail_fields @ ..]) if name.name == *head_field => { + e = base; + fields = tail_fields; + }, + (ExprKind::Path(path), []) => { + break cx.qpath_res(path, e.hir_id) == path_res; + }, + (&(ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _)), _) => e = base, + _ => break false, + } } - visitor.var_used_after_while_let } -fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { - if_chain! { - if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id); - let parent_node = cx.tcx.hir().get_parent_node(loop_block.hir_id); - if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find(parent_node); - then { - return is_loop_nested(cx, loop_expr, iter_expr) - } +/// Checks if the given expression is the same field as, is a child of, or is the parent of the +/// given field. Used to check if the expression can be used while the given field is borrowed +/// mutably. e.g. if checking for `x.y`, then `x.y`, `x.y.z`, and `x` will all return true, but +/// `x.z`, and `y` will return false. +fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fields: &[Symbol], path_res: Res) -> bool { + match expr.kind { + ExprKind::Field(base, name) => { + if let Some((head_field, tail_fields)) = fields.split_first() { + if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) { + return true; + } + // Check if the expression is a parent field + let mut fields_iter = tail_fields.iter(); + while let Some(field) = fields_iter.next() { + if *field == name.name && is_expr_same_field(cx, base, fields_iter.as_slice(), path_res) { + return true; + } + } + } + + // Check if the expression is a child field. + let mut e = base; + loop { + match e.kind { + ExprKind::Field(..) if is_expr_same_field(cx, e, fields, path_res) => break true, + ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base, + ExprKind::Path(ref path) if fields.is_empty() => { + break cx.qpath_res(path, e.hir_id) == path_res; + }, + _ => break false, + } + } + }, + // If the path matches, this is either an exact match, or the expression is a parent of the field. + ExprKind::Path(ref path) => cx.qpath_res(path, expr.hir_id) == path_res, + ExprKind::DropTemps(base) | ExprKind::Type(base, _) | ExprKind::AddrOf(_, _, base) => { + is_expr_same_child_or_parent_field(cx, base, fields, path_res) + }, + _ => false, } - false } -fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { - let mut id = loop_expr.hir_id; - let iter_id = if let Some(id) = path_to_local(iter_expr) { - id - } else { - return true; +/// Strips off all field and path expressions. This will return true if a field or path has been +/// skipped. Used to skip them after failing to check for equality. +fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) { + let mut e = expr; + let e = loop { + match e.kind { + ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base, + ExprKind::Path(_) => return (None, true), + _ => break e, + } }; - loop { - let parent = cx.tcx.hir().get_parent_node(id); - if parent == id { - return false; + (Some(e), e.hir_id != expr.hir_id) +} + +/// Checks if the given expression uses the iterator. +fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool { + struct V<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + uses_iter: bool, + } + impl Visitor<'tcx> for V<'_, '_, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None } - match cx.tcx.hir().find(parent) { - Some(Node::Expr(expr)) => { - if let ExprKind::Loop(..) = expr.kind { - return true; - }; - }, - Some(Node::Block(block)) => { - let mut block_visitor = LoopNestVisitor { - hir_id: id, - iterator: iter_id, - nesting: Nesting::Unknown, - }; - walk_block(&mut block_visitor, block); - if block_visitor.nesting == Nesting::RuledOut { - return false; + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.uses_iter { + // return + } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.uses_iter = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); } - }, - Some(Node::Stmt(_)) => (), - _ => { - return false; - }, + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + if is_res_used(self.cx, self.iter_expr.path, id) { + self.uses_iter = true; + } + } else { + walk_expr(self, e); + } } - id = parent; } -} -struct VarUsedAfterLoopVisitor { - def_id: HirId, - iter_expr_id: HirId, - past_while_let: bool, - var_used_after_while_let: bool, + let mut v = V { + cx, + iter_expr, + uses_iter: false, + }; + v.visit_expr(container); + v.uses_iter } -impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor { - type Map = Map<'tcx>; +#[allow(clippy::too_many_lines)] +fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool { + struct AfterLoopVisitor<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + loop_id: HirId, + after_loop: bool, + used_iter: bool, + } + impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.past_while_let { - if path_to_local_id(expr, self.def_id) { - self.var_used_after_while_let = true; + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.used_iter { + return; + } + if self.after_loop { + if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.used_iter = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); + } + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + self.used_iter = is_res_used(self.cx, self.iter_expr.path, id); + } else { + walk_expr(self, e); + } + } else if self.loop_id == e.hir_id { + self.after_loop = true; + } else { + walk_expr(self, e); + } + } + } + + struct NestedLoopVisitor<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + local_id: HirId, + loop_id: HirId, + after_loop: bool, + found_local: bool, + used_after: bool, + } + impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_local(&mut self, l: &'tcx Local<'_>) { + if !self.after_loop { + l.pat.each_binding_or_first(&mut |_, id, _, _| { + if id == self.local_id { + self.found_local = true; + } + }); + } + if let Some(e) = l.init { + self.visit_expr(e); + } + } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.used_after { + return; + } + if self.after_loop { + if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.used_after = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); + } + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + self.used_after = is_res_used(self.cx, self.iter_expr.path, id); + } else { + walk_expr(self, e); + } + } else if e.hir_id == self.loop_id { + self.after_loop = true; + } else { + walk_expr(self, e); } - } else if self.iter_expr_id == expr.hir_id { - self.past_while_let = true; } - walk_expr(self, expr); } - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None + + if let Some(e) = get_enclosing_loop(cx.tcx, loop_expr) { + // The iterator expression will be used on the next iteration unless it is declared within the outer + // loop. + let local_id = match iter_expr.path { + Res::Local(id) => id, + _ => return true, + }; + let mut v = NestedLoopVisitor { + cx, + iter_expr, + local_id, + loop_id: loop_expr.hir_id, + after_loop: false, + found_local: false, + used_after: false, + }; + v.visit_expr(e); + v.used_after || !v.found_local + } else { + let mut v = AfterLoopVisitor { + cx, + iter_expr, + loop_id: loop_expr.hir_id, + after_loop: false, + used_iter: false, + }; + v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); + v.used_iter } } diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 314bf11e2d6..66479ae264e 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -47,7 +47,12 @@ pub struct MacroRefData { impl MacroRefData { pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self { - let mut path = cx.sess().source_map().span_to_filename(callee).prefer_local().to_string(); + let mut path = cx + .sess() + .source_map() + .span_to_filename(callee) + .prefer_local() + .to_string(); // std lib paths are <::std::module::file type> // so remove brackets, space and type. @@ -96,7 +101,8 @@ impl MacroUseImports { let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); if let Some(callee) = span.source_callee() { if !self.collected.contains(&call_site) { - self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx)); + self.mac_refs + .push(MacroRefData::new(name.to_string(), callee.def_site, cx)); self.collected.insert(call_site); } } @@ -174,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .push((*item).to_string()); check_dup.push((*item).to_string()); } - } + }, [root, rest @ ..] => { if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) { let filtered = rest @@ -198,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .push(rest.join("::")); check_dup.extend(rest.iter().map(ToString::to_string)); } - } + }, } } } @@ -206,9 +212,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { 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(", ")))); } } @@ -225,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { "remove the attribute and import the macro directly, try", help, Applicability::MaybeIncorrect, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 23428524dee..61b5fe81fa9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,4 +1,4 @@ -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; @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))), - ) + ); }); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs index 520162559e5..18038dd7819 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -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; @@ -53,21 +53,6 @@ impl LateLintPass<'_> for ManualUnwrapOr { } } -#[derive(Copy, Clone)] -enum Case { - Option, - Result, -} - -impl Case { - fn unwrap_fn_path(&self) -> &str { - match self { - Case::Option => "Option::unwrap_or", - Case::Result => "Result::unwrap_or", - } - } -} - fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { @@ -86,6 +71,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); + if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty(); if !contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) @@ -98,10 +84,10 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) { - Some(Case::Option) + if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::option_type) { + Some("Option") } else if is_type_diagnostic_item(cx, ty, sym::result_type) { - Some(Case::Result) + Some("Result") } else { None }; @@ -124,7 +110,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{}`", case.unwrap_fn_path()), + &format!("this pattern reimplements `{}::unwrap_or`", ty_name), "replace with", format!( "{}.unwrap_or({})", diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 99c35ae3bbf..e1f80ab025c 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { "remove the `map` call", String::new(), Applicability::MachineApplicable, - ) + ); } fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { @@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } else { span_lint_and_sugg( cx, @@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index a70e8b26087..cd3e3b97928 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1,4 +1,4 @@ -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, }; @@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestions.join(" | "), Applicability::MaybeIncorrect, - ) + ); }, }; } @@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp cast, ), applicability, - ) + ); } } } @@ -1478,15 +1478,34 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A ); }, PatKind::Wild => { - span_lint_and_sugg( - cx, - MATCH_SINGLE_BINDING, - expr.span, - "this match could be replaced by its body itself", - "consider using the match body instead", - snippet_body, - Applicability::MachineApplicable, - ); + if ex.can_have_side_effects() { + let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0)); + let sugg = format!( + "{};\n{}{}", + snippet_with_applicability(cx, ex.span, "..", &mut applicability), + indent, + snippet_body + ); + span_lint_and_sugg( + cx, + MATCH_SINGLE_BINDING, + expr.span, + "this match could be replaced by its scrutinee and body", + "consider using the scrutinee and body instead", + sugg, + applicability, + ); + } else { + span_lint_and_sugg( + cx, + MATCH_SINGLE_BINDING, + expr.span, + "this match could be replaced by its body itself", + "consider using the match body instead", + snippet_body, + Applicability::MachineApplicable, + ); + } }, _ => (), } @@ -1728,7 +1747,7 @@ mod redundant_pattern_match { 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), _ => {}, @@ -1857,7 +1876,7 @@ mod redundant_pattern_match { { self.res = true; } else { - self.visit_expr(self_arg) + self.visit_expr(self_arg); } } args.iter().for_each(|arg| self.visit_expr(arg)); diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs index a735c616f6e..aca96e06ef2 100644 --- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs +++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; 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. @@ -67,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { } } - let derefs: String = iter::repeat('*').take(derefs_needed).collect(); + let derefs = "*".repeat(derefs_needed); diag.span_suggestion( param.span, "try dereferencing", diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 287bff886bf..da428a7b487 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -135,7 +135,7 @@ pub(crate) trait BindInsteadOfMap { .into_iter() .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), ), - ) + ); }); true } diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index ce2e8fa8b10..1a32af5dc7a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -8,7 +8,6 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; 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; @@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, 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, diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index ecec6da3aa0..f5b4b6bf8ea 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, "try", "copied".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs index 12d560653ed..32d40d97bf4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs @@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg "try", "filter_map".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 28d0e8cd4ae..b4188d9ed30 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp } 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); @@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) - 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() diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index 52d7c15332e..68d906c3ea3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs index 06b12998b1a..64c09214a76 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs new file mode 100644 index 00000000000..919e2628c52 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs @@ -0,0 +1,99 @@ +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 + ) + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 0b1b6304def..c8ae972f18c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -32,6 +32,7 @@ mod iter_nth_zero; 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; @@ -48,6 +49,7 @@ mod single_char_push_string; 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; @@ -61,7 +63,7 @@ mod zst_offset; 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; @@ -283,30 +285,6 @@ declare_clippy_lint! { } 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(..)`. /// /// **Why is this bad?** Because you usually call `expect()` on the `Result` @@ -1657,14 +1635,69 @@ declare_clippy_lint! { "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, + } } } @@ -1673,7 +1706,6 @@ impl_lint_pass!(Methods => [ EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, - WRONG_PUB_SELF_CONVENTION, OK_EXPECT, MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, @@ -1726,7 +1758,9 @@ impl_lint_pass!(Methods => [ 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. @@ -1838,16 +1872,20 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - wrong_self_convention::check( - cx, - &name, - item.vis.node.is_pub(), - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); + 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, + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false + ); + } } } @@ -1903,7 +1941,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if let TraitItemKind::Fn(ref sig, _) = item.kind; + if sig.decl.implicit_self.has_implicit_self(); if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); + then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); @@ -1911,7 +1951,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { wrong_self_convention::check( cx, &item.ident.name.as_str(), - false, self_ty, first_arg_ty, first_arg_span, @@ -1947,7 +1986,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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); @@ -1965,6 +2004,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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) { @@ -2008,7 +2052,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("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), _ => {}, @@ -2040,6 +2084,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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); @@ -2054,7 +2101,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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); }, _ => {}, }, @@ -2069,7 +2116,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio 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); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs new file mode 100644 index 00000000000..a271df60572 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs @@ -0,0 +1,56 @@ +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, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index 75517c48a21..4c4034437da 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -87,7 +87,7 @@ pub(super) fn check( 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); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 6e2bcb113c2..a2e09e5ecec 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -6,7 +6,6 @@ use rustc_middle::ty::TyS; use rustc_span::source_map::Span; use std::fmt; -use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] @@ -21,9 +20,9 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ // 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::IsTraitItem(false)], &[SelfKind::Ref]), - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), + (&[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::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; @@ -85,18 +84,12 @@ impl fmt::Display for Convention { 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() @@ -142,7 +135,7 @@ pub(super) fn check<'tcx>( span_lint_and_help( cx, - lint, + WRONG_SELF_CONVENTION, first_arg_span, &format!( "{} usually take {}", diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index 45948f4d926..ff3473b744e 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 6966d798c53..804c04fe1b8 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -17,7 +17,7 @@ use rustc_span::hygiene::DesugaringKind; 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, @@ -355,8 +355,10 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { 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| { @@ -660,7 +662,14 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::MacroKind; if expr.span.from_expansion() { let data = expr.span.ctxt().outer_expn_data(); - matches!(data.kind, ExpnKind::Macro { kind: MacroKind::Attr, name: _, proc_macro: _ }) + matches!( + data.kind, + ExpnKind::Macro { + kind: MacroKind::Attr, + name: _, + proc_macro: _ + } + ) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index dd38316fa25..050b6805b7c 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -310,7 +310,7 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess(), expr.span) { return; } - double_neg::check(cx, expr) + double_neg::check(cx, expr); } } @@ -334,15 +334,15 @@ impl MiscEarlyLints { }; 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"); } } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 329a0009a3e..2201cf56d52 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -5,7 +5,7 @@ use rustc_lint::{EarlyContext, LintContext}; use super::UNNEEDED_FIELD_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind { + if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind { let mut wilds = 0; let type_name = npat .segments diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index 4dd032d78f1..df044538fe1 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::Span; use super::UNNEEDED_WILDCARD_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind { + if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind { if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) { if let Some((left_index, left_pat)) = patterns[..rest_index] .iter() diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index dfab3e8a931..a46a7407df0 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -7,8 +7,7 @@ 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; @@ -56,20 +55,6 @@ impl MissingDoc { *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<'_>, @@ -93,9 +78,9 @@ impl MissingDoc { 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, diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs index 64e9dc85466..1414fdc1b11 100644 --- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index cea6fce1195..6efe8ffcde0 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { 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"); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index 7dfe12cd4eb..25645a0e7a2 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { _ 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> { diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 3e2b2782ed5..fe3c4455be5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -121,7 +121,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { 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) => { @@ -129,7 +129,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { 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); } } }, diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs new file mode 100644 index 00000000000..b30bfbd4294 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_opt; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// a lazy and. + /// + /// **Why is this bad?** + /// The bitwise operators do not support short-circuiting, so it may hinder code performance. + /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` + /// + /// **Known problems:** + /// This lint evaluates only when the right side is determined to have no side effects. At this time, that + /// determination is quite conservative. + /// + /// **Example:** + /// + /// ```rust + /// let (x,y) = (true, false); + /// if x & !y {} // where both x and y are booleans + /// ``` + /// Use instead: + /// ```rust + /// let (x,y) = (true, false); + /// if x && !y {} + /// ``` + pub NEEDLESS_BITWISE_BOOL, + pedantic, + "Boolean expressions that use bitwise rather than lazy operators" +} + +declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]); + +fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if_chain! { + if !in_macro(expr.span); + if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind()); + if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr; + if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind; + if !right.can_have_side_effects(); + then { + return true; + } + } + false +} + +fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { + if let ExprKind::Binary(ref op, left, right) = expr.kind { + if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { + let op_snippet = match op.node { + BinOpKind::BitAnd => "&&", + _ => "||", + }; + return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet)); + } + } + None +} + +impl LateLintPass<'_> for NeedlessBitwiseBool { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if is_bitwise_operation(cx, expr) { + span_lint_and_then( + cx, + NEEDLESS_BITWISE_BOOL, + expr.span, + "use of bitwise operator instead of lazy operator between booleans", + |diag| { + if let Some(sugg) = suggession_snippet(cx, expr) { + diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); + } + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index dd458198637..3b3736fd3a1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if is_else_clause(cx.tcx, e) { - snip = snip.blockify() + snip = snip.blockify(); } span_lint_and_sugg( @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { |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(( @@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { "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, @@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>( 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); @@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>( "try simplifying it as shown", h(left_side, right_side).to_string(), applicability, - ) + ); }), _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index eef3c16730b..dd1dfa2bdfb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -3,16 +3,18 @@ //! 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 @@ -32,20 +34,70 @@ declare_clippy_lint! { /// 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 { @@ -85,50 +137,131 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } } } + 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, + } + } } } } diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 079b6642d58..a723a472a25 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -142,10 +142,10 @@ impl<'tcx> Visitor<'tcx> for RetCollector { 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(..) => { diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index d8417c7dc70..c64491c63e2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyS; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -63,12 +62,6 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); -#[derive(Debug)] -enum SomeOkCall<'a> { - SomeCall(&'a Expr<'a>, &'a Expr<'a>), - OkCall(&'a Expr<'a>, &'a Expr<'a>), -} - impl LateLintPass<'_> for NeedlessQuestionMark { /* * The question mark operator is compatible with both Result<T, E> and Option<T>, @@ -90,104 +83,37 @@ impl LateLintPass<'_> for NeedlessQuestionMark { */ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - let e = match &expr.kind { - ExprKind::Ret(Some(e)) => e, - _ => return, - }; - - if let Some(ok_some_call) = is_some_or_ok_call(cx, e) { - emit_lint(cx, &ok_some_call); + if let ExprKind::Ret(Some(e)) = expr.kind { + check(cx, e); } } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - // Function / Closure block - let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind { - block.expr - } else { - // Single line closure - Some(&body.value) - }; - - if_chain! { - if let Some(expr) = expr_opt; - if let Some(ok_some_call) = is_some_or_ok_call(cx, expr); - then { - emit_lint(cx, &ok_some_call); - } - }; + check(cx, body.value.peel_blocks()); } } -fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { - let (entire_expr, inner_expr) = match expr { - SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner), +fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + let inner_expr = if_chain! { + if let ExprKind::Call(path, [arg]) = &expr.kind; + if let ExprKind::Path(ref qpath) = &path.kind; + if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); + if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind; + if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; + if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind; + if expr.span.ctxt() == inner_expr.span.ctxt(); + let expr_ty = cx.typeck_results().expr_ty(expr); + let inner_ty = cx.typeck_results().expr_ty(inner_expr); + if TyS::same_type(expr_ty, inner_ty); + then { inner_expr } else { return; } }; - span_lint_and_sugg( cx, NEEDLESS_QUESTION_MARK, - entire_expr.span, + expr.span, "question mark operator is useless here", "try", format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); } - -fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> { - if_chain! { - // Check outer expression matches CALL_IDENT(ARGUMENT) format - if let ExprKind::Call(path, args) = &expr.kind; - if let ExprKind::Path(ref qpath) = &path.kind; - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); - - // Extract inner expression from ARGUMENT - if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; - if let ExprKind::Call(called, args) = &inner_expr_with_q.kind; - if args.len() == 1; - - if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind; - then { - // Extract inner expr type from match argument generated by - // question mark operator - let inner_expr = &args[0]; - - // if the inner expr is inside macro but the outer one is not, do not lint (#6921) - if differing_macro_contexts(expr.span, inner_expr.span) { - return None; - } - - let inner_ty = cx.typeck_results().expr_ty(inner_expr); - let outer_ty = cx.typeck_results().expr_ty(expr); - - // Check if outer and inner type are Option - let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type); - let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); - - // Check for Option MSRV - if outer_is_some && inner_is_some { - return Some(SomeOkCall::SomeCall(expr, inner_expr)); - } - - // Check if outer and inner type are Result - let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type); - let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type); - - // Additional check: if the error type of the Result can be converted - // via the From trait, then don't match - let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr); - - // Must meet Result MSRV - if outer_is_result && inner_is_result && does_not_call_from { - return Some(SomeOkCall::OkCall(expr, inner_expr)); - } - } - } - - None -} - -fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool { - return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr); -} diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 0704173a011..c824f6f54b5 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { 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" - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index 34fd012572f..d5e1ea6d242 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,4 @@ +use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -5,8 +6,6 @@ use rustc_lint::{LateContext, LateLintPass}; 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. /// diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index cfcaf509471..b2206a82208 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,4 +1,4 @@ -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; @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind { if has_no_effect(cx, expr) { - span_lint(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 { @@ -106,14 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { 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); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 4c8bceaf2cb..1a23e6afe28 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -126,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[ &["args", "arms"], &["qpath", "path"], &["lit", "lint"], + &["wparam", "lparam"], ]; struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>); @@ -138,7 +139,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { self.check_ident(ident); } }, - PatKind::Struct(_, ref fields, _) => { + PatKind::Struct(_, _, ref fields, _) => { for field in fields { if !field.is_shorthand { self.visit_pat(&field.pat); diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs index 9efe45336bf..fded48038e3 100644 --- a/src/tools/clippy/clippy_lints/src/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/open_options.rs @@ -123,7 +123,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `create` is called more than once", ); } else { - create = true + create = true; } create_arg = create_arg || (arg == Argument::True); }, @@ -136,7 +136,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `append` is called more than once", ); } else { - append = true + append = true; } append_arg = append_arg || (arg == Argument::True); }, @@ -149,7 +149,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `truncate` is called more than once", ); } else { - truncate = true + truncate = true; } truncate_arg = truncate_arg || (arg == Argument::True); }, @@ -162,7 +162,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `read` is called more than once", ); } else { - read = true + read = true; } read_arg = read_arg || (arg == Argument::True); }, @@ -175,7 +175,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `write` is called more than once", ); } else { - write = true + write = true; } write_arg = write_arg || (arg == Argument::True); }, diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index e527adbb892..b6af4175edf 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_lang_ctor}; +use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionSome; @@ -81,7 +81,6 @@ struct OptionIfLetElseOccurence { method_sugg: String, some_expr: String, none_expr: String, - wrap_braces: bool, } /// Extracts the body of a given arm. If the arm contains only an expression, @@ -106,37 +105,6 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { } } -/// If this is the else body of an if/else expression, then we need to wrap -/// it in curly braces. Otherwise, we don't. -fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { - let mut should_wrap = false; - - if let Some(Expr { - kind: - ExprKind::Match( - _, - arms, - MatchSource::IfLetDesugar { - contains_else_clause: true, - }, - ), - .. - }) = parent.expr - { - should_wrap = expr.hir_id == arms[1].body.hir_id; - } else if let Some(Expr { - kind: ExprKind::If(_, _, Some(else_clause)), - .. - }) = parent.expr - { - should_wrap = expr.hir_id == else_clause.hir_id; - } - - should_wrap - }) -} - fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", @@ -161,6 +129,7 @@ fn detect_option_if_let_else<'tcx>( if_chain! { if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; + if !is_else_clause(cx.tcx, expr); if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; @@ -168,13 +137,13 @@ fn detect_option_if_let_else<'tcx>( if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; if !contains_return_break_continue_macro(arms[0].body); if !contains_return_break_continue_macro(arms[1].body); + then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_arm(&arms[0])?; let none_body = extract_body_from_arm(&arms[1])?; let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); - let wrap_braces = should_wrap_in_braces(cx, expr); let (as_ref, as_mut) = match &cond_expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), @@ -190,7 +159,6 @@ fn detect_option_if_let_else<'tcx>( method_sugg: method_sugg.to_string(), some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")), none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")), - wrap_braces, }) } else { None @@ -208,13 +176,8 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(), "try", format!( - "{}{}.{}({}, {}){}", - if detection.wrap_braces { "{ " } else { "" }, - detection.option, - detection.method_sugg, - detection.none_expr, - detection.some_expr, - if detection.wrap_braces { " }" } else { "" }, + "{}.{}({}, {})", + detection.option, detection.method_sugg, detection.none_expr, detection.some_expr, ), Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 6b64846c24d..f6a70478559 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -102,10 +102,16 @@ declare_clippy_lint! { 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 @@ -120,10 +126,14 @@ impl<'tcx> PassByRefOrValue { 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); @@ -184,7 +194,6 @@ impl<'tcx> PassByRefOrValue { } 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()); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index b0674f90678..12c44436874 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -211,7 +211,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { ]; 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<_>>(); diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 30bee213900..d66bac52243 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -88,7 +88,7 @@ impl QuestionMark { "replace it with", replacement_str, applicability, - ) + ); } } } @@ -129,7 +129,7 @@ impl QuestionMark { "replace it with", replacement, applicability, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 7169f96eaf1..ae5f0627fd6 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 92921bedf4d..8f56a21ac5b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -57,7 +57,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { self.found_return = true; } - ast_visit::walk_expr(self, ex) + ast_visit::walk_expr(self, ex); } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index e091095de13..05f9e01acb4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { Applicability::MachineApplicable, ); }, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 4b5306de58e..75151167454 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs index 560a5e7c920..b479c40bca6 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index b565c77aaec..251d527c265 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } 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 { @@ -241,7 +241,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa if let Some(snippet) = snippet_opt(cx, inner_span) { diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable); } - }) + }); }, None => match replacement { RetReplacement::Empty => { diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 553987a426b..16e4d73851f 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -8,11 +8,11 @@ use rustc_lint::{LateContext, LateLintPass}; 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. /// @@ -30,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` pub SEMICOLON_IF_NOTHING_RETURNED, - restriction, + pedantic, "add a semicolon if nothing is returned" } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index d6101bd5e36..ac3f7ebd14b 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -120,7 +120,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo 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); @@ -156,7 +156,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, 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); @@ -324,14 +324,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut } 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) => { @@ -374,7 +374,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<( 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), diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index a45bb102389..1eaad438237 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -70,7 +70,7 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) { for item in items { track_uses( cx, - &item, + item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros, @@ -117,7 +117,7 @@ fn track_uses( 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); diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index a9ae2b77119..e5c58d70b60 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -158,7 +158,7 @@ impl SlowVectorInit { ) { 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"); }, }; } @@ -290,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { 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; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 4272935bc31..bb707f78fcc 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_OPERATION_GROUPINGS, - style, + nursery, "groupings of binary operations that look suspiciously like typos" } @@ -266,7 +266,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit "did you mean", sugg, applicability, - ) + ); } fn ident_swap_sugg( @@ -475,7 +475,7 @@ impl Add for IdentLocation { impl AddAssign for IdentLocation { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } @@ -506,7 +506,7 @@ impl Add for IdentDifference { impl AddAssign for IdentDifference { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index b0589b0512e..74a94db1800 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -3,6 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; 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}; @@ -100,7 +101,7 @@ impl TraitBounds { 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! { diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs index 888ecab1046..b57d158293d 100644 --- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs @@ -1,4 +1,4 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index d9b47a699dc..70b9e8adef8 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { 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(..) => (), @@ -433,7 +433,7 @@ impl Types { }, 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; diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index d81e31f5a21..45291a120ed 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -71,7 +71,7 @@ impl LateLintPass<'_> for Unicode { 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); } } } @@ -82,7 +82,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String { 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); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs index d22f7d9a96b..04542146516 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs @@ -8,7 +8,12 @@ use super::UNIT_CMP; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.from_expansion() { if let Some(callee) = expr.span.source_callee() { - if let ExpnKind::Macro { kind: MacroKind::Bang, name: symbol, proc_macro: _ } = callee.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: symbol, + proc_macro: _, + } = callee.kind + { if let ExprKind::Binary(ref cmp, left, _) = expr.kind { let op = cmp.node; if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index f2f1410aed7..a85ffa6aa95 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk}; 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; @@ -52,7 +52,19 @@ declare_clippy_lint! { "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( @@ -66,13 +78,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) { // 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. diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 3e985fa72b8..1b3c457b01a 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -1,6 +1,6 @@ #![allow(clippy::wildcard_imports, clippy::enum_glob_use)] -use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; +use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{meets_msrv, msrvs, over}; use rustc_ast::mut_visit::*; @@ -273,16 +273,16 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) |k| always_pat!(k, Tuple(ps) => ps), ), // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`. - TupleStruct(path1, ps1) => extend_with_matching_product( + TupleStruct(qself1, path1, ps1) => extend_with_matching_product( ps1, start, alternatives, |k, ps1, idx| matches!( k, - TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) + TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) ), - |k| always_pat!(k, TupleStruct(_, ps) => ps), + |k| always_pat!(k, TupleStruct(_, _, ps) => ps), ), // Transform a record pattern `S { fp_0, ..., fp_n }`. - Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives), + Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives), }; alternatives[focus_idx].kind = focus_kind; @@ -294,6 +294,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. fn extend_with_struct_pat( + qself1: &Option<ast::QSelf>, path1: &ast::Path, fps1: &mut Vec<ast::PatField>, rest1: bool, @@ -306,8 +307,9 @@ fn extend_with_struct_pat( start, alternatives, |k| { - matches!(k, Struct(path2, fps2, rest2) + matches!(k, Struct(qself2, path2, fps2, rest2) if rest1 == *rest2 // If one struct pattern has `..` so must the other. + && eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && fps1.len() == fps2.len() && fps1.iter().enumerate().all(|(idx_1, fp1)| { @@ -323,7 +325,7 @@ fn extend_with_struct_pat( })) }, // Extract `p2_k`. - |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat), + |k| always_pat!(k, Struct(_, _, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat), ); extend_with_tail_or(&mut fps1[idx].pat, tail_or) }) diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs new file mode 100644 index 00000000000..18ee07d3a95 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -0,0 +1,92 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, Item, ItemKind, YieldSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for functions that are declared `async` but have no `.await`s inside of them. + /// + /// **Why is this bad?** Async functions with no async code create overhead, both mentally and computationally. + /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which + /// causes runtime overhead and hassle for the caller. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// async fn get_random_number() -> i64 { + /// 4 // Chosen by fair dice roll. Guaranteed to be random. + /// } + /// let number_future = get_random_number(); + /// + /// // Good + /// fn get_random_number_improved() -> i64 { + /// 4 // Chosen by fair dice roll. Guaranteed to be random. + /// } + /// let number_future = async { get_random_number_improved() }; + /// ``` + pub UNUSED_ASYNC, + pedantic, + "finds async functions with no await statements" +} + +declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]); + +struct AsyncFnVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + found_await: bool, +} + +impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind { + self.found_await = true; + } + walk_expr(self, ex); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} + +impl<'tcx> LateLintPass<'tcx> for UnusedAsync { + fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Trait(..) = item.kind { + return; + } + } + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, + body: &Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind { + if matches!(asyncness, IsAsync::Async) { + let mut visitor = AsyncFnVisitor { cx, found_await: false }; + walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); + if !visitor.found_await { + span_lint_and_help( + cx, + UNUSED_ASYNC, + span, + "unused `async` for function with no await statements", + None, + "consider removing the `async` from this function", + ); + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index c27a6d4e347..ee082d30d93 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { 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 { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 4ac2ec55b98..0b58c6c0917 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -1,8 +1,8 @@ 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; @@ -38,12 +38,14 @@ declare_clippy_lint! { #[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, } } @@ -72,7 +74,7 @@ fn correct_ident(ident: &str) -> String { 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); @@ -92,27 +94,31 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) { "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)); - } + }, + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index aa4d16633ff..254b104bdef 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use clippy_utils::ty::same_type_and_consts; use clippy_utils::{in_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::{ - def, + self as hir, + def::{self, DefKind}, def_id::LocalDefId, intravisit::{walk_ty, NestedVisitorMap, Visitor}, Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment, @@ -14,7 +14,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{AssocKind, Ty, TyS}; +use rustc_middle::ty::{AssocKind, Ty}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Span}; @@ -356,7 +356,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector { 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> { @@ -385,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> { } } - walk_ty(self, hir_ty) + walk_ty(self, hir_ty); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { @@ -459,7 +459,7 @@ fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool { fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool { if_chain! { - if TyS::same_type(ty, self_ty); + if same_type_and_consts(ty, self_ty); if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; then { !matches!(path.res, def::Res::SelfTy(..)) diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 7edb280be73..2be99fb761b 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, TyS}; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if TyS::same_type(a, b) { + if same_type_and_consts(a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string(); span_lint_and_sugg( cx, @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if TyS::same_type(a, b) { + if same_type_and_consts(a, b) { let sugg = snippet(cx, args[0].span, "<expr>").into_owned(); span_lint_and_sugg( cx, @@ -110,7 +110,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); - if TyS::same_type(a_type, b); + if same_type_and_consts(a_type, b); + then { span_lint_and_help( cx, @@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); - if TyS::same_type(a_type, b); + if same_type_and_consts(a_type, b); then { let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); @@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if match_def_path(cx, def_id, &paths::FROM_FROM); - if TyS::same_type(a, b); + if same_type_and_consts(a, b); then { let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par(); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e70f8a09ebe..39ef170ae36 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { 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()); }, } }, diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 52c1dc3bdd2..0e33ae740d9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -26,13 +26,13 @@ impl TryConf { macro_rules! define_Conf { ($( - #[$doc:meta] + #[doc = $doc:literal] $(#[conf_deprecated($dep:literal)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration pub struct Conf { - $(#[$doc] pub $name: $ty,)* + $(#[doc = $doc] pub $name: $ty,)* } mod defaults { @@ -89,12 +89,42 @@ macro_rules! define_Conf { Ok(TryConf { conf, errors }) } } + + #[cfg(feature = "metadata-collector-lint")] + pub mod metadata { + use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; + + macro_rules! wrap_option { + () => (None); + ($x:literal) => (Some($x)); + } + + pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + vec![ + $( + { + let deprecation_reason = wrap_option!($($dep)?); + + ClippyConfiguration::new( + stringify!($name), + stringify!($ty), + format!("{:?}", super::defaults::$name()), + $doc, + deprecation_reason, + ) + }, + )+ + ] + } + } }; } // 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()), @@ -180,15 +210,13 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> { .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)), + } } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index ee7be24eae8..b1523e032af 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,4 +1,4 @@ -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; @@ -1100,7 +1100,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { IF_CHAIN_STYLE, if_chain_local_span(cx, local, if_chain_span), "`let` expression should be inside `then { .. }`", - ) + ); } } @@ -1141,7 +1141,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { 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`"); } } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index e85637ca758..46af03663b8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -8,9 +8,6 @@ //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such //! a simple mistake) -// # NITs -// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames - use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ @@ -22,13 +19,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Loc, Span, Symbol}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::collections::BinaryHeap; +use std::fmt; use std::fs::{self, OpenOptions}; use std::io::prelude::*; use std::path::Path; use crate::utils::internal_lints::is_lint_ref_type; use clippy_utils::{ - diagnostics::span_lint, last_path_segment, match_function_call, match_path, paths, ty::match_type, + diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type, ty::walk_ptrs_ty_depth, }; @@ -39,8 +37,52 @@ const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "i /// These groups will be ignored by the lint group matcher. This is useful for collections like /// `clippy::all` const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; -/// Lints within this group will be excluded from the collection -const EXCLUDED_LINT_GROUPS: [&str; 1] = ["clippy::internal"]; +/// Lints within this group will be excluded from the collection. These groups +/// have to be defined without the `clippy::` prefix. +const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"]; +/// Collected deprecated lint will be assigned to this group in the JSON output +const DEPRECATED_LINT_GROUP_STR: &str = "deprecated"; +/// This is the lint level for deprecated lints that will be displayed in the lint list +const DEPRECATED_LINT_LEVEL: &str = "none"; +/// This array holds Clippy's lint groups with their corresponding default lint level. The +/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`. +const DEFAULT_LINT_LEVELS: [(&str, &str); 8] = [ + ("correctness", "deny"), + ("restriction", "allow"), + ("style", "warn"), + ("pedantic", "allow"), + ("complexity", "warn"), + ("perf", "warn"), + ("cargo", "allow"), + ("nursery", "allow"), +]; +/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed +/// to only keep the actual lint group in the output. +const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; + +/// This template will be used to format the configuration section in the lint documentation. +/// The `configurations` parameter will be replaced with one or multiple formatted +/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations +macro_rules! CONFIGURATION_SECTION_TEMPLATE { + () => { + r#" +**Configuration** +This lint has the following configuration variables: + +{configurations} +"# + }; +} +/// This template will be used to format an individual `ClippyConfiguration` instance in the +/// lint documentation. +/// +/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and +/// `default` +macro_rules! CONFIGURATION_VALUE_TEMPLATE { + () => { + "* {name}: {ty}: {doc} (defaults to `{default}`)\n" + }; +} const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ &["clippy_utils", "diagnostics", "span_lint"], @@ -66,6 +108,7 @@ const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [ &["clippy_utils", "diagnostics", "multispan_sugg"], &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"], ]; +const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"]; /// The index of the applicability name of `paths::APPLICABILITY_VALUES` const APPLICABILITY_NAME_INDEX: usize = 2; @@ -102,13 +145,33 @@ declare_clippy_lint! { impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]); #[allow(clippy::module_name_repetitions)] -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct MetadataCollector { /// All collected lints /// /// We use a Heap here to have the lints added in alphabetic order in the export lints: BinaryHeap<LintMetadata>, applicability_info: FxHashMap<String, ApplicabilityInfo>, + config: Vec<ClippyConfiguration>, +} + +impl MetadataCollector { + pub fn new() -> Self { + Self { + lints: BinaryHeap::<LintMetadata>::default(), + applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), + config: collect_configs(), + } + } + + fn get_lint_configs(&self, lint_name: &str) -> Option<String> { + self.config + .iter() + .filter(|config| config.lints.iter().any(|lint| lint == lint_name)) + .map(ToString::to_string) + .reduce(|acc, x| acc + &x) + .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations)) + } } impl Drop for MetadataCollector { @@ -143,6 +206,7 @@ struct LintMetadata { id: String, id_span: SerializableSpan, group: String, + level: &'static str, docs: String, /// This field is only used in the output and will only be /// mapped shortly before the actual output. @@ -150,11 +214,12 @@ struct LintMetadata { } impl LintMetadata { - fn new(id: String, id_span: SerializableSpan, group: String, docs: String) -> Self { + fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self { Self { id, id_span, group, + level, docs, applicability: None, } @@ -182,7 +247,7 @@ impl SerializableSpan { let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); Self { - path: format!("{}", loc.file.name), + path: format!("{}", loc.file.name.prefer_remapped()), line: loc.line, } } @@ -214,6 +279,95 @@ impl Serialize for ApplicabilityInfo { } } +// ================================================================== +// Configuration +// ================================================================== +#[derive(Debug, Clone, Default)] +pub struct ClippyConfiguration { + name: String, + config_type: &'static str, + default: String, + lints: Vec<String>, + doc: String, + deprecation_reason: Option<&'static str>, +} + +impl ClippyConfiguration { + pub fn new( + name: &'static str, + config_type: &'static str, + default: String, + doc_comment: &'static str, + deprecation_reason: Option<&'static str>, + ) -> Self { + let (lints, doc) = parse_config_field_doc(doc_comment) + .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + + Self { + name: to_kebab(name), + lints, + doc, + config_type, + default, + deprecation_reason, + } + } +} + +fn collect_configs() -> Vec<ClippyConfiguration> { + crate::utils::conf::metadata::get_configuration_metadata() +} + +/// This parses the field documentation of the config struct. +/// +/// ```rust, ignore +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") +/// ``` +/// +/// Would yield: +/// ```rust, ignore +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") +/// ``` +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { + const DOC_START: &str = " Lint: "; + if_chain! { + if doc_comment.starts_with(DOC_START); + if let Some(split_pos) = doc_comment.find('.'); + then { + let mut doc_comment = doc_comment.to_string(); + let documentation = doc_comment.split_off(split_pos); + + doc_comment.make_ascii_lowercase(); + let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect(); + + Some((lints, documentation)) + } else { + None + } + } +} + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} + +impl fmt::Display for ClippyConfiguration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + CONFIGURATION_VALUE_TEMPLATE!(), + name = self.name, + ty = self.config_type, + doc = self.doc, + default = self.default + ) + } +} + +// ================================================================== +// Lint pass +// ================================================================== impl<'hir> LateLintPass<'hir> for MetadataCollector { /// Collecting lint declarations like: /// ```rust, ignore @@ -225,23 +379,48 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { /// } /// ``` fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) { - if_chain! { - // item validation - if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind; - if is_lint_ref_type(cx, ty); - // blacklist check - let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); - // metadata extraction - if let Some(group) = get_lint_group_or_lint(cx, &lint_name, item); - if let Some(docs) = extract_attr_docs_or_lint(cx, item); - then { - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - group, - docs, - )); + if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { + // Normal lint + if_chain! { + // item validation + if is_lint_ref_type(cx, ty); + // blacklist check + let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); + if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); + // metadata extraction + if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item); + if let Some(mut docs) = extract_attr_docs_or_lint(cx, item); + then { + if let Some(configuration_section) = self.get_lint_configs(&lint_name) { + docs.push_str(&configuration_section); + } + + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + group, + level, + docs, + )); + } + } + + if_chain! { + if is_deprecated_lint(cx, ty); + // blacklist check + let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); + if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); + // Metadata the little we can get from a deprecated lint + if let Some(docs) = extract_attr_docs_or_lint(cx, item); + then { + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + DEPRECATED_LINT_GROUP_STR.to_string(), + DEPRECATED_LINT_LEVEL, + docs, + )); + } } } } @@ -268,7 +447,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { // - src/misc.rs:734:9 // - src/methods/mod.rs:3545:13 // - src/methods/mod.rs:3496:13 - // We are basically unable to resolve the lint name it self. + // We are basically unable to resolve the lint name itself. return; } @@ -310,7 +489,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { .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'); @@ -318,15 +497,32 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { }) } -fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Item<'_>) -> Option<String> { +fn get_lint_group_and_level_or_lint( + cx: &LateContext<'_>, + lint_name: &str, + item: &'hir Item<'_>, +) -> Option<(String, &'static str)> { let result = cx.lint_store.check_lint_name(lint_name, Some(sym::clippy)); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { - get_lint_group(cx, lint_lst[0]) - .or_else(|| { - lint_collection_error_item(cx, item, "Unable to determine lint group"); + if let Some(group) = get_lint_group(cx, lint_lst[0]) { + if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { + return None; + } + + if let Some(level) = get_lint_level_from_group(&group) { + Some((group, level)) + } else { + lint_collection_error_item( + cx, + item, + &format!("Unable to determine lint level for found group `{}`", group), + ); None - }) - .filter(|group| !EXCLUDED_LINT_GROUPS.contains(&group.as_str())) + } + } else { + lint_collection_error_item(cx, item, "Unable to determine lint group"); + None + } } else { lint_collection_error_item(cx, item, "Unable to find lint in lint_store"); None @@ -339,14 +535,31 @@ fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> { continue; } - if lints.iter().any(|x| *x == lint_id) { - return Some((*group_name).to_string()); + if lints.iter().any(|group_lint| *group_lint == lint_id) { + let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name); + return Some((*group).to_string()); } } None } +fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { + DEFAULT_LINT_LEVELS + .iter() + .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level)) +} + +fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { + if let hir::TyKind::Path(ref path) = ty.kind { + if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) { + return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE); + } + } + + false +} + // ================================================================== // Lint emission // ================================================================== @@ -383,7 +596,7 @@ fn extract_emission_info<'hir>( 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 @@ -458,7 +671,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { 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 { @@ -517,7 +730,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { } 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); @@ -605,7 +818,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { .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) => { diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index febd4b6ff7b..1d5b7c98d31 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,5 +1,5 @@ -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; diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs index ec209b30951..3ab68df2b6d 100644 --- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { "use of `File::read_to_string`", None, "consider using `fs::read_to_string` instead", - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 7e962472c07..5229a705865 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -279,8 +279,15 @@ impl EarlyLintPass for Write { span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); self.lint_println_empty_string(cx, mac); } else if mac.path == sym!(write) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) { + if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) { if check_newlines(&fmt_str) { + let (nl_span, only_nl) = newline_span(&fmt_str); + let nl_span = match (dest, only_nl) { + // Special case of `write!(buf, "\n")`: Mark everything from the end of + // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains. + (Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()), + _ => nl_span, + }; span_lint_and_then( cx, WRITE_WITH_NEWLINE, @@ -289,14 +296,11 @@ impl EarlyLintPass for Write { |err| { err.multipart_suggestion( "use `writeln!()` instead", - vec![ - (mac.path.span, String::from("writeln")), - (newline_span(&fmt_str), String::new()), - ], + vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())], Applicability::MachineApplicable, ); }, - ) + ); } } } else if mac.path == sym!(writeln) { @@ -329,12 +333,13 @@ impl EarlyLintPass for Write { /// Given a format string that ends in a newline and its span, calculates the span of the /// newline, or the format string itself if the format string consists solely of a newline. -fn newline_span(fmtstr: &StrLit) -> Span { +/// Return this and a boolean indicating whether it only consisted of a newline. +fn newline_span(fmtstr: &StrLit) -> (Span, bool) { let sp = fmtstr.span; let contents = &fmtstr.symbol.as_str(); if *contents == r"\n" { - return sp; + return (sp, true); } let newline_sp_hi = sp.hi() @@ -351,7 +356,7 @@ fn newline_span(fmtstr: &StrLit) -> Span { panic!("expected format string to contain a newline"); }; - sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi) + (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false) } /// Stores a list of replacement spans for each argument, but only if all the replacements used an @@ -613,7 +618,7 @@ impl Write { |err| { err.multipart_suggestion( &format!("use `{}!` instead", suggested), - vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())], + vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())], Applicability::MachineApplicable, ); }, diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 350b1cf25ff..a1ea743ba80 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -1,4 +1,4 @@ -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}; diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 0a1d4e11142..93ed3b18400 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -14,6 +14,7 @@ unicode-normalization = "0.1" rustc-semver="1.1.0" [features] +deny-warnings = [] internal-lints = [] metadata-collector-lint = [] diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 93e10c836cc..e6d84bc7560 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -47,9 +47,9 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), - (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)), - (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => { - lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) + (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)), + (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { + lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) }, (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), @@ -78,6 +78,14 @@ pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool { l.position == r.position && eq_ty(&l.ty, &r.ty) } +pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool { + match (l, r) { + (Some(l), Some(r)) => eq_qself(l, r), + (None, None) => true, + _ => false + } +} + pub fn eq_path(l: &Path, r: &Path) -> bool { over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r)) } @@ -170,7 +178,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_path(&lse.path, &rse.path) + eq_maybe_qself(&lse.qself, &rse.qself) + && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r)) }, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index c0584e1e226..0318c483959 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -115,7 +115,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' 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"); } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 2a305d8bcbe..0d7fdeeb920 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -229,25 +229,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { 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(); @@ -273,8 +273,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } }, - 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, } @@ -349,7 +349,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ) .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; } diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index a4efae54894..7c94474cb35 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -167,7 +167,7 @@ pub fn span_lint_hir_and_then( cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, - sp: Span, + sp: impl Into<MultiSpan>, msg: &str, f: impl FnOnce(&mut DiagnosticBuilder<'_>), ) { @@ -223,7 +223,7 @@ pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: 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`. diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 0c0e4d3b4ce..8be36756b33 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -58,7 +58,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> { } 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, _)) @@ -70,7 +70,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> { 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, @@ -112,7 +112,7 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool { // } // ``` 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; @@ -140,14 +140,14 @@ pub fn for_loop<'tcx>( 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)); } @@ -182,7 +182,7 @@ pub enum VecArgs<'a> { /// 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(); @@ -194,8 +194,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve 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)); } @@ -227,7 +227,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx /// 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; @@ -238,12 +238,12 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx 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]); @@ -252,8 +252,8 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx // 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); } @@ -261,7 +261,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx } } 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 diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3b01158acd9..a21ad42c061 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -2,20 +2,19 @@ use crate::consts::{constant_context, constant_simple}; 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 @@ -95,12 +94,12 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { 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; } @@ -110,11 +109,9 @@ impl HirEqInterExpr<'_, '_, '_> { // 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, } } @@ -165,12 +162,18 @@ impl HirEqInterExpr<'_, '_, '_> { 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) { @@ -192,20 +195,20 @@ impl HirEqInterExpr<'_, '_, '_> { &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) @@ -215,58 +218,50 @@ impl HirEqInterExpr<'_, '_, '_> { 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)) @@ -277,7 +272,7 @@ impl HirEqInterExpr<'_, '_, '_> { } 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 { @@ -290,6 +285,7 @@ impl HirEqInterExpr<'_, '_, '_> { 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, @@ -308,11 +304,11 @@ impl HirEqInterExpr<'_, '_, '_> { /// 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)) => { @@ -323,15 +319,13 @@ impl HirEqInterExpr<'_, '_, '_> { 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)) @@ -344,10 +338,10 @@ impl HirEqInterExpr<'_, '_, '_> { #[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, @@ -359,14 +353,14 @@ impl HirEqInterExpr<'_, '_, '_> { 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| { @@ -390,12 +384,9 @@ impl HirEqInterExpr<'_, '_, '_> { #[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) @@ -404,14 +395,14 @@ impl HirEqInterExpr<'_, '_, '_> { 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()) } } @@ -519,7 +510,7 @@ pub struct SpanlessHash<'a, 'tcx> { /// 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> { @@ -527,7 +518,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { Self { cx, maybe_typeck_results: cx.maybe_typeck_results(), - s: StableHasher::new(), + s: FxHasher::default(), } } @@ -540,17 +531,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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)] @@ -561,21 +546,16 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // 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); }, @@ -584,22 +564,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); }, @@ -607,39 +585,35 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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), @@ -694,22 +668,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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 { @@ -717,39 +689,39 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); } }, @@ -759,8 +731,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); }, } @@ -773,19 +745,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } 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); @@ -795,7 +767,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); } @@ -815,11 +787,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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 { @@ -838,7 +810,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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 { @@ -864,6 +836,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { _ => { for seg in path.segments { self.hash_name(seg.ident.name); + self.hash_generic_args(seg.args().args); } }, } @@ -875,7 +848,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); } }, @@ -888,7 +861,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); }, } @@ -921,25 +894,24 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); }, } @@ -950,24 +922,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { 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); }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9ac9500b4eb..769836aaf18 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,10 +1,16 @@ #![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))] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)] +// warn on the same lints as `clippy_lints` +#![warn(trivial_casts, trivial_numeric_casts)] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] +// warn on rustc internal lints +#![warn(rustc::internal)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) @@ -57,7 +63,7 @@ use std::hash::BuildHasherDefault; 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; @@ -322,7 +328,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) /// 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; } @@ -332,8 +338,8 @@ pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { 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"), } } @@ -361,8 +367,8 @@ pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx h 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, } } @@ -382,8 +388,8 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment /// ``` 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) { @@ -451,7 +457,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { /// 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); } @@ -655,13 +661,13 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec 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; } @@ -706,7 +712,7 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> { 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, } } @@ -848,13 +854,31 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio 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, }) } +/// Gets the loop enclosing the given expression, if any. +pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + let map = tcx.hir(); + for (_, node) in map.parent_iter(expr.hir_id) { + match node { + Node::Expr( + e @ Expr { + kind: ExprKind::Loop(..), + .. + }, + ) => return Some(e), + Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (), + _ => break, + } + } + None +} + /// Gets the parent node if it's an impl block. pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { let map = tcx.hir(); @@ -947,7 +971,12 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: mac_name, + proc_macro: _, + } = data.kind + { if mac_name.as_str() == name { return Some(new_span); } @@ -975,7 +1004,12 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: mac_name, + proc_macro: _, + } = data.kind + { if mac_name.as_str() == name { return Some(new_span); } @@ -994,7 +1028,7 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> /// 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 { @@ -1024,21 +1058,21 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { 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. @@ -1060,9 +1094,9 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { /// 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); } } @@ -1077,7 +1111,7 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { /// 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, @@ -1096,7 +1130,7 @@ pub fn is_self(slf: &Param<'_>) -> bool { 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 @@ -1114,7 +1148,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It 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); @@ -1133,7 +1167,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc } } - 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); @@ -1220,12 +1254,12 @@ pub fn match_function_call<'tcx>( 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 @@ -1282,15 +1316,15 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, 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; @@ -1299,8 +1333,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, // 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); } } @@ -1349,7 +1383,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { // 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 { @@ -1362,7 +1396,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => 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. @@ -1538,14 +1572,16 @@ where 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)) { diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 00df04c0144..4a9c4fd0276 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -26,4 +26,5 @@ msrv_aliases! { 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 } } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 268bc5b3205..546706d51d7 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -52,7 +52,7 @@ impl<'a> NumericLiteral<'a> { 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 { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 8037d670500..b913d1ce8b1 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -116,8 +116,8 @@ pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "os", "imp", "unix", "fs", pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; -pub const PTR_COPY: [&str; 4] = ["core", "intrinsics", "", "copy"]; -pub const PTR_COPY_NONOVERLAPPING: [&str; 4] = ["core", "intrinsics", "", "copy_nonoverlapping"]; +pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; +pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"]; pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"]; diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 5885cc83560..791688cd194 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { 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; @@ -79,5 +79,5 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { } fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> { - get_pat_name(&arg.pat) + get_pat_name(arg.pat) } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index a08dcf19e5b..0e6ead675c2 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -255,7 +255,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t 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() { diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 0633a19391f..efc0ec50fdc 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -2,7 +2,7 @@ #![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; @@ -10,7 +10,7 @@ use rustc_errors::Applicability; 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; @@ -90,6 +90,29 @@ impl<'a> Sugg<'a> { 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 { @@ -289,7 +312,7 @@ fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool { let mut chars = sugg.as_ref().chars(); if let Some('(') = chars.next() { let mut depth = 1; - while let Some(c) = chars.next() { + for c in &mut chars { if c == '(' { depth += 1; } else if c == ')' { @@ -684,7 +707,7 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder 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"))); } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 64a80f2554f..a92d3be5d3c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -2,9 +2,8 @@ #![allow(clippy::module_name_repetitions)] -use std::collections::HashMap; - use rustc_ast::ast::Mutability; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{TyKind, Unsafety}; @@ -143,21 +142,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // 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; } } @@ -167,7 +163,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { 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; } } @@ -184,14 +180,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) + is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } fn is_normalizable_helper<'tcx>( cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, - cache: &mut HashMap<Ty<'tcx>, bool>, + cache: &mut FxHashMap<Ty<'tcx>, bool>, ) -> bool { if let Some(&cached_result) = cache.get(ty) { return cached_result; @@ -306,7 +302,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo /// 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, } } @@ -322,3 +318,27 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { } inner(ty, 0) } + +/// Returns `true` if types `a` and `b` are same types having same `Const` generic args, +/// otherwise returns `false` +pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.kind(), &b.kind()) { + (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { + if did_a != did_b { + return false; + } + + substs_a + .iter() + .zip(substs_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { + same_type_and_consts(type_a, type_b) + }, + _ => true, + }) + }, + _ => a == b, + } +} diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 650b70c63af..2c55021ac88 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -59,7 +59,7 @@ impl<'tcx> MutVarsDelegate { //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; }, _ => {}, } @@ -71,12 +71,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { 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) {} diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index d431bdf34ee..ce00106dd4d 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -1,7 +1,7 @@ use crate::path_to_local_id; use rustc_hir as hir; use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Block, Body, Destination, Expr, ExprKind, HirId, Stmt}; +use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -87,7 +87,7 @@ where } 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<'_>) { @@ -189,35 +189,23 @@ impl<'v> Visitor<'v> for LocalUsedVisitor<'v> { } } +/// 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>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>), @@ -231,7 +219,7 @@ 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); } @@ -239,3 +227,36 @@ pub fn visit_break_exprs<'tcx>( node.visit(&mut V(f)); } + +/// Checks if the given resolved path is used in the given body. +pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { + struct V<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + res: Res, + found: bool, + } + impl Visitor<'tcx> for V<'_, 'tcx> { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.found { + return; + } + + if let ExprKind::Path(p) = &e.kind { + if self.cx.qpath_res(p, e.hir_id) == self.res { + self.found = true; + } + } else { + walk_expr(self, e); + } + } + } + + let mut v = V { cx, res, found: false }; + v.visit_expr(&cx.tcx.hir().body(body).value); + v.found +} diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md index 5226875cc21..e2e307ce4f6 100644 --- a/src/tools/clippy/doc/basics.md +++ b/src/tools/clippy/doc/basics.md @@ -28,6 +28,8 @@ git clone git@github.com:<your-username>/rust-clippy If you've already cloned Clippy in the past, update it to the latest version: ```bash +# If the upstream remote has not been added yet +git remote add upstream https://github.com/rust-lang/rust-clippy # upstream has to be the remote of the rust-lang/rust-clippy repo git fetch upstream # make sure that you are on the master branch diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md index eaa6a9af277..e0af9bf0625 100644 --- a/src/tools/clippy/doc/release.md +++ b/src/tools/clippy/doc/release.md @@ -94,7 +94,7 @@ After finding the Clippy commit, it can be tagged with the release number. # 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]. diff --git a/src/tools/clippy/mini-macro/Cargo.toml b/src/tools/clippy/mini-macro/Cargo.toml deleted file mode 100644 index 0d95c86aef0..00000000000 --- a/src/tools/clippy/mini-macro/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[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] diff --git a/src/tools/clippy/mini-macro/src/lib.rs b/src/tools/clippy/mini-macro/src/lib.rs deleted file mode 100644 index 2b793589049..00000000000 --- a/src/tools/clippy/mini-macro/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![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!()); - } - ) -} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 593162f09a7..e3863c46288 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-05-06" +channel = "nightly-2021-06-03" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs index ff2a7de5725..5f289918a7c 100644 --- a/src/tools/clippy/rustc_tools_util/src/lib.rs +++ b/src/tools/clippy/rustc_tools_util/src/lib.rs @@ -100,9 +100,9 @@ pub fn get_commit_date() -> Option<String> { } #[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") @@ -113,16 +113,16 @@ pub fn get_channel() -> Option<String> { { 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"), } }, } diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml new file mode 100644 index 00000000000..5eb7ac03541 --- /dev/null +++ b/src/tools/clippy/tests/clippy.toml @@ -0,0 +1 @@ +# default config for tests, overrides clippy.toml at the project root diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index e1110721f6e..7d266a36bb6 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -4,8 +4,8 @@ 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}; @@ -88,9 +88,11 @@ fn default_config() -> compiletest::Config { 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); } @@ -114,7 +116,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { 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(); @@ -145,9 +147,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { 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"), @@ -208,7 +208,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { 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(), @@ -236,10 +236,8 @@ fn run_ui_cargo(config: &mut compiletest::Config) { 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) => {}, @@ -260,8 +258,32 @@ fn prepare_env() { 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), + } + } +} diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index 6524fd4706c..7de130c7dbe 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -22,14 +22,12 @@ fn dogfood_clippy() { return; } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let enable_metadata_collection = std::env::var("ENABLE_METADATA_COLLECTION").unwrap_or_else(|_| "0".to_string()); let mut command = Command::new(&*CLIPPY_PATH); command .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") - .env("ENABLE_METADATA_COLLECTION", &enable_metadata_collection) .arg("clippy") .arg("--all-targets") .arg("--all-features") @@ -157,10 +155,9 @@ fn dogfood_subprojects() { if cargo::is_rustc_test_suite() { return; } - let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); // NOTE: `path_dep` crate is omitted on purpose here - for d in &[ + for project in &[ "clippy_workspace_tests", "clippy_workspace_tests/src", "clippy_workspace_tests/subcrate", @@ -170,34 +167,80 @@ fn dogfood_subprojects() { "clippy_utils", "rustc_tools_util", ] { - let mut command = Command::new(&*CLIPPY_PATH); - command - .current_dir(root_dir.join(d)) - .env("CLIPPY_DOGFOOD", "1") - .env("CARGO_INCREMENTAL", "0") - .arg("clippy") - .arg("--all-targets") - .arg("--all-features") - .arg("--") - .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::pedantic"]) - .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + run_clippy_for_project(project); + } - // internal lints only exist if we build with the internal-lints feature - if cfg!(feature = "internal-lints") { - command.args(&["-D", "clippy::internal"]); + // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the + // same time, so we test this immediately after the dogfood for workspaces. + test_no_deps_ignores_path_deps_in_workspaces(); +} + +#[test] +#[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; + } + } } + } - let output = command.output().unwrap(); + // 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(); - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + // Running the collection again + run_clippy_for_project("clippy_lints"); +} - assert!(output.status.success()); +fn run_clippy_for_project(project: &str) { + let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let mut command = Command::new(&*CLIPPY_PATH); + + command + .current_dir(root_dir.join(project)) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy") + .arg("--all-targets") + .arg("--all-features") + .arg("--") + .args(&["-D", "clippy::all"]) + .args(&["-D", "clippy::pedantic"]) + .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + + // internal lints only exist if we build with the internal-lints feature + if cfg!(feature = "internal-lints") { + command.args(&["-D", "clippy::internal"]); } - // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the - // same time, so we test this immediately after the dogfood for workspaces. - test_no_deps_ignores_path_deps_in_workspaces(); + let output = command.output().unwrap(); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); } diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index d83080b69f5..a7be00426c4 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -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 diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index aebeaf34679..4b7b7fec78f 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -53,3 +53,22 @@ pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream { } } } + +#[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!()); + } + ) +} diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs new file mode 100644 index 00000000000..780797e3c6a --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs @@ -0,0 +1,14 @@ +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} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs new file mode 100644 index 00000000000..5595d8d1d62 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs @@ -0,0 +1,10 @@ +// edition:2018 +#![allow(clippy::never_loop)] + +async fn f() { + loop { + break; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs new file mode 100644 index 00000000000..57ab6ca14f8 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs @@ -0,0 +1,12 @@ +// 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!"); + || "}{"; +} diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs deleted file mode 100644 index c7468493380..00000000000 --- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[macro_use] -extern crate clippy_mini_macro_test; - -#[deny(warnings)] -fn main() { - let x = Foo; - println!("{:?}", x); -} - -#[derive(ClippyMiniMacroTest, Debug)] -struct Foo; diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index 2a948d60b10..cba7666c2d8 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } -pub struct A; +struct A; impl A { pub fn as_ref(self) -> &'static str { diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index dbf0b03af76..4ba9f0c1fcf 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -12,5 +12,7 @@ #[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() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index e5de839dbc5..03c9f438891 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -84,5 +84,17 @@ error: lint `clippy::filter_map` has been removed: this lint has been replaced b 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 diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index 4fefc0b43f1..083f5143e6e 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -1,5 +1,4 @@ -#![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 { @@ -97,8 +96,8 @@ pub enum PubSeall { WithOut, } -#[allow(clippy::pub_enum_variant_names)] -mod allowed { +#[allow(clippy::enum_variant_names)] +pub mod allowed { pub enum PubAllowed { SomeThis, SomeThat, diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index ab7fff4507a..447fbb9e1bf 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -1,5 +1,5 @@ error: variant name ends with the enum's name - --> $DIR/enum_variants.rs:16:5 + --> $DIR/enum_variants.rs:15:5 | LL | cFoo, | ^^^^ @@ -7,25 +7,25 @@ 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, @@ -37,7 +37,7 @@ LL | | } = 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, @@ -49,7 +49,7 @@ LL | | } = 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, @@ -61,7 +61,7 @@ LL | | } = 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, @@ -73,7 +73,7 @@ LL | | } = 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的, @@ -84,21 +84,8 @@ LL | | } | = 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), @@ -110,7 +97,7 @@ LL | | } = 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), @@ -121,5 +108,5 @@ LL | | } | = 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 diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index 2be2283e3fd..9e752311c67 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -48,6 +48,9 @@ fn main() { // 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 { diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index f0373f9ccf6..44be4628cbd 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -48,6 +48,9 @@ fn main() { // 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 { diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 57ed6527966..8795d3b42c6 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -33,7 +33,7 @@ LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ 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` @@ -41,43 +41,43 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.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` diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed index 56762400593..85f7c531e39 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed @@ -4,8 +4,6 @@ fn main() { let one = 1; let x = 3f32; - let _ = x * x; - let _ = x * x; let y = 4f32; let _ = x.mul_add(x, y); @@ -13,7 +11,10 @@ fn main() { let _ = x.mul_add(x, y).sqrt(); let _ = y.mul_add(y, x).sqrt(); // Cases where the lint shouldn't be applied + let _ = x.powi(2); + let _ = x.powi(1 + 1); let _ = x.powi(3); + let _ = x.powi(4) + y; let _ = x.powi(one + 1); let _ = (x.powi(2) + y.powi(2)).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs index 1f800e4628d..ece61d1bec4 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.rs +++ b/src/tools/clippy/tests/ui/floating_point_powi.rs @@ -4,8 +4,6 @@ fn main() { let one = 1; let x = 3f32; - let _ = x.powi(2); - let _ = x.powi(1 + 1); let y = 4f32; let _ = x.powi(2) + y; @@ -13,7 +11,10 @@ fn main() { let _ = (x.powi(2) + y).sqrt(); let _ = (x + y.powi(2)).sqrt(); // Cases where the lint shouldn't be applied + let _ = x.powi(2); + let _ = x.powi(1 + 1); let _ = x.powi(3); + let _ = x.powi(4) + y; let _ = x.powi(one + 1); let _ = (x.powi(2) + y.powi(2)).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr index d5a5f1bcca1..37d840988bb 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr @@ -1,40 +1,28 @@ -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:7:13 - | -LL | let _ = x.powi(2); - | ^^^^^^^^^ help: consider using: `x * x` - | - = note: `-D clippy::suboptimal-flops` implied by `-D warnings` - -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:8:13 - | -LL | let _ = x.powi(1 + 1); - | ^^^^^^^^^^^^^ help: consider using: `x * x` - -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:11:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:9:13 | LL | let _ = x.powi(2) + y; | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:12:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:10:13 | LL | let _ = x + y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:13:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:11:13 | LL | let _ = (x.powi(2) + y).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:14:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:12:13 | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed index b5f548810e6..12db43b5343 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -6,6 +6,20 @@ 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<_>>(); diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index b842b5451d1..f5ec190e0cd 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -6,6 +6,20 @@ 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); diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr index 434734c9a21..8f08ac8c3ff 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr @@ -1,88 +1,94 @@ 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 diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr index 0a86568b18d..a2b8c2a384b 100644 --- a/src/tools/clippy/tests/ui/functions.stderr +++ b/src/tools/clippy/tests/ui/functions.stderr @@ -30,7 +30,7 @@ error: this function has too many arguments (8/7) 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 }); @@ -38,49 +38,49 @@ 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) }; diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs index 1c46e3a5337..39443775015 100644 --- a/src/tools/clippy/tests/ui/impl.rs +++ b/src/tools/clippy/tests/ui/impl.rs @@ -33,4 +33,35 @@ impl fmt::Debug for MyStruct { } } +// issue #5772 +struct WithArgs<T>(T); +impl WithArgs<u32> { + fn f1() {} +} +impl WithArgs<u64> { + fn f2() {} +} +impl WithArgs<u64> { + fn f3() {} +} + +// Ok, the struct is allowed to have multiple impls. +#[allow(clippy::multiple_inherent_impl)] +struct Allowed; +impl Allowed {} +impl Allowed {} +impl Allowed {} + +struct AllowedImpl; +#[allow(clippy::multiple_inherent_impl)] +impl AllowedImpl {} +// Ok, the first block is skipped by this lint. +impl AllowedImpl {} + +struct OneAllowedImpl; +impl OneAllowedImpl {} +#[allow(clippy::multiple_inherent_impl)] +impl OneAllowedImpl {} +impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. + fn main() {} diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr index aab688cc2d8..8703ecac93e 100644 --- a/src/tools/clippy/tests/ui/impl.stderr +++ b/src/tools/clippy/tests/ui/impl.stderr @@ -31,5 +31,33 @@ LL | | fn first() {} LL | | } | |_^ -error: aborting due to 2 previous errors +error: multiple implementations of this structure + --> $DIR/impl.rs:44:1 + | +LL | / impl WithArgs<u64> { +LL | | fn f3() {} +LL | | } + | |_^ + | +note: first implementation here + --> $DIR/impl.rs:41:1 + | +LL | / impl WithArgs<u64> { +LL | | fn f2() {} +LL | | } + | |_^ + +error: multiple implementations of this structure + --> $DIR/impl.rs:65:1 + | +LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> $DIR/impl.rs:62:1 + | +LL | impl OneAllowedImpl {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 51c66a46368..70d49d9f2c4 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -1,6 +1,7 @@ // 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 @@ -12,7 +13,7 @@ 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}; diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index 2011129bc94..68370023861 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -1,6 +1,7 @@ // 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 @@ -12,7 +13,7 @@ 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] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index f8c86c8d917..49314b7506d 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,5 +1,5 @@ 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};` @@ -7,22 +7,22 @@ LL | #[macro_use] = 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 diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed new file mode 100644 index 00000000000..dc140257f32 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -0,0 +1,66 @@ +// 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); +} diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs new file mode 100644 index 00000000000..0d69c989b2e --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -0,0 +1,66 @@ +// 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(); +} diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr new file mode 100644 index 00000000000..c6511689716 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr @@ -0,0 +1,64 @@ +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 + diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index e7a29596b73..3717f962745 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -163,4 +163,19 @@ mod issue6965 { } } +use std::rc::Rc; +fn format_name(name: Option<&Rc<str>>) -> &str { + match name { + None => "<anon>", + Some(name) => name, + } +} + +fn implicit_deref_ref() { + let _: &str = match Some(&"bye") { + None => "hi", + Some(s) => s, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index 66006b6c616..989adde1f5b 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -205,4 +205,19 @@ mod issue6965 { } } +use std::rc::Rc; +fn format_name(name: Option<&Rc<str>>) -> &str { + match name { + None => "<anon>", + Some(name) => name, + } +} + +fn implicit_deref_ref() { + let _: &str = match Some(&"bye") { + None => "hi", + Some(s) => s, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index 526e94b10bd..30bf6402253 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed @@ -94,10 +94,7 @@ fn main() { 0 => println!("Disabled branch"), _ => println!("Enabled branch"), } - // Lint - let x = 1; - let y = 1; - println!("Single branch"); + // Ok let x = 1; let y = 1; diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index 6a2ca7c5e93..d8bb80d8b96 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -106,15 +106,7 @@ fn main() { 0 => println!("Disabled branch"), _ => println!("Enabled branch"), } - // Lint - let x = 1; - let y = 1; - match match y { - 0 => 1, - _ => 2, - } { - _ => println!("Single branch"), - } + // Ok let x = 1; let y = 1; diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index cbbf5d29c02..795c8c3e24d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -167,16 +167,5 @@ LL | unwrapped LL | }) | -error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:112:5 - | -LL | / match match y { -LL | | 0 => 1, -LL | | _ => 2, -LL | | } { -LL | | _ => println!("Single branch"), -LL | | } - | |_____^ help: consider using the match body instead: `println!("Single branch");` - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed index e73a85b73d7..a91fcc2125d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -34,4 +34,20 @@ fn main() { }, None => println!("nothing"), } + + fn side_effects() {} + + // Lint (scrutinee has side effects) + // issue #7094 + side_effects(); + println!("Side effects"); + + // Lint (scrutinee has side effects) + // issue #7094 + let x = 1; + match x { + 0 => 1, + _ => 2, + }; + println!("Single branch"); } diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs index 7362cb390e5..476386ebabe 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.rs +++ b/src/tools/clippy/tests/ui/match_single_binding2.rs @@ -34,4 +34,22 @@ fn main() { }, None => println!("nothing"), } + + fn side_effects() {} + + // Lint (scrutinee has side effects) + // issue #7094 + match side_effects() { + _ => println!("Side effects"), + } + + // Lint (scrutinee has side effects) + // issue #7094 + let x = 1; + match match x { + 0 => 1, + _ => 2, + } { + _ => println!("Single branch"), + } } diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr index bc18d191aa3..4372f55af87 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -30,5 +30,39 @@ LL | let (a, b) = get_tup(); LL | println!("a {:?} and b {:?}", a, b); | -error: aborting due to 2 previous errors +error: this match could be replaced by its scrutinee and body + --> $DIR/match_single_binding2.rs:42:5 + | +LL | / match side_effects() { +LL | | _ => println!("Side effects"), +LL | | } + | |_____^ + | +help: consider using the scrutinee and body instead + | +LL | side_effects(); +LL | println!("Side effects"); + | + +error: this match could be replaced by its scrutinee and body + --> $DIR/match_single_binding2.rs:49:5 + | +LL | / match match x { +LL | | 0 => 1, +LL | | _ => 2, +LL | | } { +LL | | _ => println!("Single branch"), +LL | | } + | |_____^ + | +help: consider using the scrutinee and body instead + | +LL | match x { +LL | 0 => 1, +LL | _ => 2, +LL | }; +LL | println!("Single branch"); + | + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing-doc-crate.rs index 04711f86488..e00c7fbfed1 100644 --- a/src/tools/clippy/tests/ui/missing-doc-crate.rs +++ b/src/tools/clippy/tests/ui/missing-doc-crate.rs @@ -1,5 +1,4 @@ #![warn(clippy::missing_docs_in_private_items)] -#![feature(external_doc)] -#![doc(include = "../../README.md")] +#![doc = include_str!("../../README.md")] fn main() {} diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs index 57af84dcdf4..bfa9ef01b0e 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.rs +++ b/src/tools/clippy/tests/ui/missing-doc-impl.rs @@ -67,7 +67,10 @@ impl PubFoo { 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() {} } diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr index 7e10404ca00..d33d512475b 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr +++ b/src/tools/clippy/tests/ui/missing-doc-impl.stderr @@ -94,10 +94,12 @@ LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ 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 diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs index 669bf01a84c..f5908cb5701 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.rs +++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs @@ -15,12 +15,4 @@ mod foo { pub struct Foobar; } -#[cfg(test)] -mod test { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed new file mode 100644 index 00000000000..5e1ea663a10 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -0,0 +1,40 @@ +// run-rustfix + +#![warn(clippy::needless_bitwise_bool)] + +fn returns_bool() -> bool { + true +} + +const fn const_returns_bool() -> bool { + false +} + +fn main() { + let (x, y) = (false, true); + if x & y { + println!("true") + } + if returns_bool() & x { + println!("true") + } + if !returns_bool() & returns_bool() { + println!("true") + } + if y && !x { + println!("true") + } + + // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves. + if y & !const_returns_bool() { + println!("true") // This is a const function, in an UnOp + } + + if y & "abcD".is_empty() { + println!("true") // This is a const method call + } + + if y & (0 < 1) { + println!("true") // This is a BinOp with no side effects + } +} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs new file mode 100644 index 00000000000..f3075fba0a2 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -0,0 +1,40 @@ +// run-rustfix + +#![warn(clippy::needless_bitwise_bool)] + +fn returns_bool() -> bool { + true +} + +const fn const_returns_bool() -> bool { + false +} + +fn main() { + let (x, y) = (false, true); + if x & y { + println!("true") + } + if returns_bool() & x { + println!("true") + } + if !returns_bool() & returns_bool() { + println!("true") + } + if y & !x { + println!("true") + } + + // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves. + if y & !const_returns_bool() { + println!("true") // This is a const function, in an UnOp + } + + if y & "abcD".is_empty() { + println!("true") // This is a const method call + } + + if y & (0 < 1) { + println!("true") // This is a BinOp with no side effects + } +} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr new file mode 100644 index 00000000000..63c88ef63f5 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr @@ -0,0 +1,10 @@ +error: use of bitwise operator instead of lazy operator between booleans + --> $DIR/needless_bitwise_bool.rs:24:8 + | +LL | if y & !x { + | ^^^^^^ help: try: `y && !x` + | + = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 5ae4a0e79b9..a87171dc3f2 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -18,7 +18,6 @@ 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 => { @@ -43,19 +42,3 @@ trait Trait {} 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), -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 1e281316c8a..059dc8ceac3 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -18,7 +18,6 @@ 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(ref cake) = Some(&5) {} let garbl = match 42 { 44 => &a, 45 => { @@ -43,19 +42,3 @@ trait Trait {} 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), -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index bea4b41b803..6eddf26db06 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -6,23 +6,11 @@ LL | let c = x(&&a); | = 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 diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs new file mode 100644 index 00000000000..f0926220755 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -0,0 +1,151 @@ +// 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), +} diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr new file mode 100644 index 00000000000..32913d59f7a --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr @@ -0,0 +1,112 @@ +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 + diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index af6c7bf15ea..6ecbbcb6249 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -2,7 +2,7 @@ #![allow(unused, clippy::suspicious_map, clippy::iter_count)] -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; #[warn(clippy::needless_collect)] #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)] @@ -13,9 +13,24 @@ fn main() { // Empty } sample.iter().cloned().any(|x| x == 1); - sample.iter().map(|x| (x, x)).count(); + // #7164 HashMap's and BTreeMap's `len` usage should not be linted + sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len(); + + sample.iter().map(|x| (x, x)).next().is_none(); + sample.iter().map(|x| (x, x)).next().is_none(); + // Notice the `HashSet`--this should not be linted sample.iter().collect::<HashSet<_>>().len(); // Neither should this sample.iter().collect::<BTreeSet<_>>().len(); + + sample.iter().count(); + sample.iter().next().is_none(); + sample.iter().cloned().any(|x| x == 1); + sample.iter().any(|x| x == &1); + + // `BinaryHeap` doesn't have `contains` method + sample.iter().count(); + sample.iter().next().is_none(); } diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 6ae14f370b1..8dc69bcf5b3 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -2,7 +2,7 @@ #![allow(unused, clippy::suspicious_map, clippy::iter_count)] -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; #[warn(clippy::needless_collect)] #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)] @@ -13,9 +13,24 @@ fn main() { // Empty } sample.iter().cloned().collect::<Vec<_>>().contains(&1); + // #7164 HashMap's and BTreeMap's `len` usage should not be linted sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len(); + + sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty(); + // Notice the `HashSet`--this should not be linted sample.iter().collect::<HashSet<_>>().len(); // Neither should this sample.iter().collect::<BTreeSet<_>>().len(); + + sample.iter().collect::<LinkedList<_>>().len(); + sample.iter().collect::<LinkedList<_>>().is_empty(); + sample.iter().cloned().collect::<LinkedList<_>>().contains(&1); + sample.iter().collect::<LinkedList<_>>().contains(&&1); + + // `BinaryHeap` doesn't have `contains` method + sample.iter().collect::<BinaryHeap<_>>().len(); + sample.iter().collect::<BinaryHeap<_>>().is_empty(); } diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 2a9539d5975..039091627a8 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -19,10 +19,52 @@ LL | sample.iter().cloned().collect::<Vec<_>>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:35 + --> $DIR/needless_collect.rs:20:35 | -LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` +LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` -error: aborting due to 4 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:21:35 + | +LL | sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:28:19 + | +LL | sample.iter().collect::<LinkedList<_>>().len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:29:19 + | +LL | sample.iter().collect::<LinkedList<_>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:30:28 + | +LL | sample.iter().cloned().collect::<LinkedList<_>>().contains(&1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:31:19 + | +LL | sample.iter().collect::<LinkedList<_>>().contains(&&1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:34:19 + | +LL | sample.iter().collect::<BinaryHeap<_>>().len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:35:19 + | +LL | sample.iter().collect::<BinaryHeap<_>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs index 2458bf1e490..2c94235b8f5 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs @@ -1,4 +1,4 @@ -use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque}; +use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; fn main() { let sample = [1; 5]; @@ -75,3 +75,9 @@ mod issue7110 { buffer.len() } } + +fn allow_test() { + #[allow(clippy::needless_collect)] + let v = [1].iter().collect::<Vec<_>>(); + v.into_iter().collect::<HashSet<_>>(); +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 52ddd9d2dc8..f1fc81aa12b 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -94,6 +94,11 @@ where Ok(x?) } +// not quite needless +fn deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + fn main() {} // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index 1ea4ba0d83f..44a0c5f61b5 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -94,6 +94,11 @@ where Ok(x?) } +// not quite needless +fn deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + fn main() {} // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index f1f05d1af3a..02bf50d077a 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -67,7 +67,7 @@ LL | return Ok(t.magic?); | ^^^^^^^^^^^^ help: try: `t.magic` error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:115:27 + --> $DIR/needless_question_mark.rs:120:27 | LL | || -> Option<_> { Some(Some($expr)?) }() | ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)` diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 8fbfcb79860..7ec845adfaa 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -91,6 +91,9 @@ fn main() { let s: String = "foo".into(); FooString { s: s }; + #[allow(clippy::no_effect)] + 0; + // Do not warn get_number(); unsafe { unsafe_fn() }; diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index 47e7460fa7a..769ccc14bc1 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -10,7 +10,11 @@ fn bad1(string: Option<&str>) -> (bool, &str) { fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { if string.is_none() { None - } else { string.map_or(Some((false, "")), |x| Some((true, x))) } + } else if let Some(x) = string { + Some((true, x)) + } else { + Some((false, "")) + } } fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index 7aab068800a..4ebb068d22e 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -11,17 +11,6 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:17:12 - | -LL | } else if let Some(x) = string { - | ____________^ -LL | | Some((true, x)) -LL | | } else { -LL | | Some((false, "")) -LL | | } - | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` - -error: use Option::map_or instead of an if let/else --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; @@ -159,5 +148,5 @@ error: use Option::map_or instead of an if let/else LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs new file mode 100644 index 00000000000..c7235e1c221 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -0,0 +1,76 @@ +// 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; + } +} diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr new file mode 100644 index 00000000000..00aeff4fefa --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -0,0 +1,88 @@ +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 + diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs index 5981980988b..2b1bc1f4859 100644 --- a/src/tools/clippy/tests/ui/similar_names.rs +++ b/src/tools/clippy/tests/ui/similar_names.rs @@ -72,6 +72,10 @@ fn main() { 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() { diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr index 0256f126a94..a7eb2be0778 100644 --- a/src/tools/clippy/tests/ui/similar_names.stderr +++ b/src/tools/clippy/tests/ui/similar_names.stderr @@ -92,13 +92,13 @@ LL | let parsee: i32; | ^^^^^^ 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, | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed index fcbe9af9f56..1abd2b7883d 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.fixed +++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed @@ -25,8 +25,8 @@ fn main() { 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'); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs index b8bc20f4070..e662bf34be2 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.rs +++ b/src/tools/clippy/tests/ui/single_char_pattern.rs @@ -25,8 +25,8 @@ fn main() { 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"); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index 6d94d8a34e3..22d4b2d460f 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -75,13 +75,13 @@ LL | x.rsplit_terminator("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 diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs new file mode 100644 index 00000000000..a21d94cf20b --- /dev/null +++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs @@ -0,0 +1,20 @@ +#![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, ','); +} diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr new file mode 100644 index 00000000000..b6220ae2393 --- /dev/null +++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr @@ -0,0 +1,75 @@ +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 + diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr index ccc3cdb2b74..2b0005bbff1 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr @@ -89,12 +89,6 @@ 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_never(x: &i32) { @@ -106,5 +100,5 @@ error: this argument (N byte) is passed by reference, but would be more efficien 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 diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs index 54f22e3ee6a..63648ef5826 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs @@ -65,7 +65,7 @@ fn func10() -> Option<()> { unimplemented!() } -struct A; +pub struct A; impl A { // should not be linted diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed index 3c422cc4fee..f0c2ba7ccdf 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed @@ -1,10 +1,11 @@ // 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)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs index 09608661e0e..f44880b4147 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs @@ -1,10 +1,11 @@ // 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)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr index a0c0be7a9d1..ab2f75e0c56 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr @@ -1,5 +1,5 @@ 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` @@ -7,43 +7,43 @@ LL | let _fail1 = 1234i32; = 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` @@ -54,7 +54,7 @@ LL | let _ = lit_from_macro!(); = 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` diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs new file mode 100644 index 00000000000..4f4203f5fdb --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -0,0 +1,15 @@ +// edition:2018 +#![warn(clippy::unused_async)] + +async fn foo() -> i32 { + 4 +} + +async fn bar() -> i32 { + foo().await +} + +fn main() { + foo(); + bar(); +} diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr new file mode 100644 index 00000000000..8b834d205b1 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -0,0 +1,13 @@ +error: unused `async` for function with no await statements + --> $DIR/unused_async.rs:4:1 + | +LL | / async fn foo() -> i32 { +LL | | 4 +LL | | } + | |_^ + | + = note: `-D clippy::unused-async` implied by `-D warnings` + = help: consider removing the `async` from this function + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index 1282befdfb3..631da6fe066 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -462,3 +462,33 @@ mod issue6818 { a: i32, } } + +mod issue7206 { + struct MyStruct<const C: char>; + impl From<MyStruct<'a'>> for MyStruct<'b'> { + fn from(_s: MyStruct<'a'>) -> Self { + Self + } + } + + // keep linting non-`Const` generic args + struct S<'a> { + inner: &'a str, + } + + struct S2<T> { + inner: T, + } + + impl<T> S2<T> { + fn new() -> Self { + unimplemented!(); + } + } + + impl<'a> S2<S<'a>> { + fn new_again() -> Self { + Self::new() + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index 7aaac7b2414..7a10d755faa 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -462,3 +462,33 @@ mod issue6818 { a: i32, } } + +mod issue7206 { + struct MyStruct<const C: char>; + impl From<MyStruct<'a'>> for MyStruct<'b'> { + fn from(_s: MyStruct<'a'>) -> Self { + Self + } + } + + // keep linting non-`Const` generic args + struct S<'a> { + inner: &'a str, + } + + struct S2<T> { + inner: T, + } + + impl<T> S2<T> { + fn new() -> Self { + unimplemented!(); + } + } + + impl<'a> S2<S<'a>> { + fn new_again() -> Self { + S2::new() + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index a32a9b9157d..cf6222c9b45 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -162,5 +162,11 @@ error: unnecessary structure name repetition LL | A::new::<submod::B>(submod::B {}) | ^ help: use the applicable keyword: `Self` -error: aborting due to 27 previous errors +error: unnecessary structure name repetition + --> $DIR/use_self.rs:491:13 + | +LL | S2::new() + | ^^ help: use the applicable keyword: `Self` + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 03977de9455..76aa82068d6 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -70,4 +70,23 @@ fn main() { let a: i32 = 1; let b: i32 = 1; let _ = (a + b) * 3; + + // see #7205 + let s: Foo<'a'> = Foo; + let _: Foo<'b'> = s.into(); + let s2: Foo<'a'> = Foo; + let _: Foo<'a'> = s2; + let s3: Foo<'a'> = Foo; + let _ = s3; + let s4: Foo<'a'> = Foo; + let _ = vec![s4, s4, s4].into_iter(); +} + +#[derive(Copy, Clone)] +struct Foo<const C: char>; + +impl From<Foo<'a'>> for Foo<'b'> { + fn from(_s: Foo<'a'>) -> Self { + Foo + } } diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index f6e094c1661..ccee7abb404 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -70,4 +70,23 @@ fn main() { let a: i32 = 1; let b: i32 = 1; let _ = i32::from(a + b) * 3; + + // see #7205 + let s: Foo<'a'> = Foo; + let _: Foo<'b'> = s.into(); + let s2: Foo<'a'> = Foo; + let _: Foo<'a'> = s2.into(); + let s3: Foo<'a'> = Foo; + let _ = Foo::<'a'>::from(s3); + let s4: Foo<'a'> = Foo; + let _ = vec![s4, s4, s4].into_iter().into_iter(); +} + +#[derive(Copy, Clone)] +struct Foo<const C: char>; + +impl From<Foo<'a'>> for Foo<'b'> { + fn from(_s: Foo<'a'>) -> Self { + Foo + } } diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 26a33595031..e6760f700f3 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -70,5 +70,23 @@ error: useless conversion to the same type: `i32` LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` -error: aborting due to 11 previous errors +error: useless conversion to the same type: `Foo<'a'>` + --> $DIR/useless_conversion.rs:78:23 + | +LL | let _: Foo<'a'> = s2.into(); + | ^^^^^^^^^ help: consider removing `.into()`: `s2` + +error: useless conversion to the same type: `Foo<'a'>` + --> $DIR/useless_conversion.rs:80:13 + | +LL | let _ = Foo::<'a'>::from(s3); + | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` + +error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>` + --> $DIR/useless_conversion.rs:82:13 + | +LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index 749393db124..c3e2cf0c4a4 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut)] +#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] fn base() { let mut iter = 1..20; @@ -41,13 +41,6 @@ fn base() { // or this let mut iter = 1u32..20; while let Some(_) = iter.next() { - break; - } - println!("Remaining iter {:?}", iter); - - // or this - let mut iter = 1u32..20; - while let Some(_) = iter.next() { iter = 1..20; } } @@ -135,18 +128,6 @@ fn refutable2() { fn nested_loops() { let a = [42, 1337]; - let mut y = a.iter(); - loop { - // x is reused, so don't lint here - while let Some(_) = y.next() {} - } - - let mut y = a.iter(); - for _ in 0..2 { - while let Some(_) = y.next() { - // y is reused, don't lint - } - } loop { let mut y = a.iter(); @@ -167,10 +148,8 @@ fn issue1121() { } fn issue2965() { - // This should not cause an ICE and suggest: - // - // for _ in values.iter() {} - // + // This should not cause an ICE + use std::collections::HashSet; let mut values = HashSet::new(); values.insert(1); @@ -205,13 +184,145 @@ fn issue1654() { } } +fn issue6491() { + // Used in outer loop, needs &mut + let mut it = 1..40; + while let Some(n) = it.next() { + for m in &mut it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } + + // This is fine, inner loop uses a new iterator. + let mut it = 1..40; + for n in it { + let mut it = 1..40; + for m in it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Weird binding shouldn't change anything. + let (mut it, _) = (1..40, 0); + for m in it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Used after the loop, needs &mut. + let mut it = 1..40; + for m in &mut it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("next item {}", it.next().unwrap()); + + println!("n still is {}", n); + } +} + +fn issue6231() { + // Closure in the outer loop, needs &mut + let mut it = 1..40; + let mut opt = Some(0); + while let Some(n) = opt.take().or_else(|| it.next()) { + for m in &mut it { + if n % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } +} + +fn issue1924() { + struct S<T>(T); + impl<T: Iterator<Item = u32>> S<T> { + fn f(&mut self) -> Option<u32> { + // Used as a field. + for i in &mut self.0 { + if !(3..=7).contains(&i) { + return Some(i); + } + } + None + } + + fn f2(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.next() { + if i == 1 { + return self.f(); + } + } + None + } + } + impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> { + fn f3(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.0.f(); + } + } + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.f3(); + } + } + // This one is fine, a different field is borrowed + for i in &mut self.0.0.0 { + if i == 1 { + return self.0.1.take(); + } else { + self.0.1 = Some(i); + } + } + None + } + } + + struct S2<T>(T, u32); + impl<T: Iterator<Item = u32>> Iterator for S2<T> { + type Item = u32; + fn next(&mut self) -> Option<u32> { + self.0.next() + } + } + + // Don't lint, field of the iterator is accessed in the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == it.1 { + break; + } + } + + // Needs &mut, field of the iterator is accessed after the loop + let mut it = S2(1..40, 0); + for n in &mut it { + if n == 0 { + break; + } + } + println!("iterator field {}", it.1); +} + fn main() { - base(); - refutable(); - refutable2(); - nested_loops(); - issue1121(); - issue2965(); - issue3670(); - issue1654(); + let mut it = 0..20; + for _ in it { + println!("test"); + } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index 30e3b82a7cc..1717006a449 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut)] +#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] fn base() { let mut iter = 1..20; @@ -41,13 +41,6 @@ fn base() { // or this let mut iter = 1u32..20; while let Some(_) = iter.next() { - break; - } - println!("Remaining iter {:?}", iter); - - // or this - let mut iter = 1u32..20; - while let Some(_) = iter.next() { iter = 1..20; } } @@ -135,18 +128,6 @@ fn refutable2() { fn nested_loops() { let a = [42, 1337]; - let mut y = a.iter(); - loop { - // x is reused, so don't lint here - while let Some(_) = y.next() {} - } - - let mut y = a.iter(); - for _ in 0..2 { - while let Some(_) = y.next() { - // y is reused, don't lint - } - } loop { let mut y = a.iter(); @@ -167,10 +148,8 @@ fn issue1121() { } fn issue2965() { - // This should not cause an ICE and suggest: - // - // for _ in values.iter() {} - // + // This should not cause an ICE + use std::collections::HashSet; let mut values = HashSet::new(); values.insert(1); @@ -205,13 +184,145 @@ fn issue1654() { } } +fn issue6491() { + // Used in outer loop, needs &mut + let mut it = 1..40; + while let Some(n) = it.next() { + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } + + // This is fine, inner loop uses a new iterator. + let mut it = 1..40; + while let Some(n) = it.next() { + let mut it = 1..40; + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Weird binding shouldn't change anything. + let (mut it, _) = (1..40, 0); + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Used after the loop, needs &mut. + let mut it = 1..40; + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("next item {}", it.next().unwrap()); + + println!("n still is {}", n); + } +} + +fn issue6231() { + // Closure in the outer loop, needs &mut + let mut it = 1..40; + let mut opt = Some(0); + while let Some(n) = opt.take().or_else(|| it.next()) { + while let Some(m) = it.next() { + if n % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } +} + +fn issue1924() { + struct S<T>(T); + impl<T: Iterator<Item = u32>> S<T> { + fn f(&mut self) -> Option<u32> { + // Used as a field. + while let Some(i) = self.0.next() { + if i < 3 || i > 7 { + return Some(i); + } + } + None + } + + fn f2(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.next() { + if i == 1 { + return self.f(); + } + } + None + } + } + impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> { + fn f3(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.0.f(); + } + } + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.f3(); + } + } + // This one is fine, a different field is borrowed + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.1.take(); + } else { + self.0.1 = Some(i); + } + } + None + } + } + + struct S2<T>(T, u32); + impl<T: Iterator<Item = u32>> Iterator for S2<T> { + type Item = u32; + fn next(&mut self) -> Option<u32> { + self.0.next() + } + } + + // Don't lint, field of the iterator is accessed in the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == it.1 { + break; + } + } + + // Needs &mut, field of the iterator is accessed after the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == 0 { + break; + } + } + println!("iterator field {}", it.1); +} + fn main() { - base(); - refutable(); - refutable2(); - nested_loops(); - issue1121(); - issue2965(); - issue3670(); - issue1654(); + let mut it = 0..20; + while let Some(..) = it.next() { + println!("test"); + } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index 6554977c798..eff559bef7e 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -19,28 +19,96 @@ LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:101:9 + --> $DIR/while_let_on_iterator.rs:94:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:108:9 + --> $DIR/while_let_on_iterator.rs:101:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:121:9 + --> $DIR/while_let_on_iterator.rs:114:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:153:9 + --> $DIR/while_let_on_iterator.rs:134:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` -error: aborting due to 7 previous errors +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:191:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:202:5 + | +LL | while let Some(n) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:204:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:213:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:222:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:239:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:254:13 + | +LL | while let Some(i) = self.0.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0` + +error: manual `!RangeInclusive::contains` implementation + --> $DIR/while_let_on_iterator.rs:255:20 + | +LL | if i < 3 || i > 7 { + | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` + | + = note: `-D clippy::manual-range-contains` implied by `-D warnings` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:286:13 + | +LL | while let Some(i) = self.0.0.0.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0.0.0` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:315:5 + | +LL | while let Some(n) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:325:5 + | +LL | while let Some(..) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index a14e86122ee..cecc2ea9406 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -51,8 +51,8 @@ LL | write!(&mut v, "/n"); | help: use `writeln!()` instead | -LL | writeln!(&mut v, ); - | ^^^^^^^ -- +LL | writeln!(&mut v); + | ^^^^^^^ -- error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:36:5 diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs index cdfbdb8b0db..151dd0c27d5 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index 29f5ba82695..ce23317abf6 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ 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) {} | ^^^^ @@ -8,7 +8,7 @@ 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) {} | ^^^^ @@ -16,7 +16,7 @@ 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) {} | ^^^^ @@ -24,7 +24,7 @@ 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) {} | ^^^^^ @@ -32,7 +32,7 @@ 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) {} | ^^^^ @@ -40,7 +40,7 @@ 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) {} | ^^^^ @@ -48,7 +48,7 @@ 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) {} | ^^^^ @@ -56,7 +56,7 @@ 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) {} | ^^^^ @@ -64,7 +64,7 @@ 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) {} | ^^^^^ @@ -72,7 +72,7 @@ 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) {} | ^^^^ @@ -80,7 +80,7 @@ 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) {} | ^^^^ @@ -88,7 +88,7 @@ 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) {} | ^^^^ @@ -96,7 +96,7 @@ 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) {} | ^^^^ @@ -104,7 +104,7 @@ 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) {} | ^^^^^ @@ -112,7 +112,7 @@ 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) {} | ^^^^ @@ -120,7 +120,7 @@ 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) {} | ^^^^ @@ -128,7 +128,7 @@ 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); | ^^^^ @@ -136,7 +136,7 @@ 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); | ^^^^^ @@ -144,7 +144,7 @@ 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); | ^^^^ @@ -152,7 +152,7 @@ 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); | ^^^^ @@ -160,7 +160,7 @@ 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); | ^^^^^ @@ -168,7 +168,7 @@ 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); | ^^^^ @@ -176,7 +176,7 @@ 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 { | ^^^^^ @@ -184,7 +184,7 @@ 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 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs index ae3a740d405..501bc1e6a85 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} @@ -23,7 +22,7 @@ mod issue6983 { } struct FooNoCopy; - // trigger lint + // don't trigger impl ToU64 for FooNoCopy { fn to_u64(self) -> u64 { 2 @@ -42,3 +41,30 @@ mod issue7032 { } } } + +mod issue7179 { + pub struct S(i32); + + impl S { + // don't trigger (`s` is not `self`) + pub fn from_be(s: Self) -> Self { + S(i32::from_be(s.0)) + } + + // lint + pub fn from_be_self(self) -> Self { + S(i32::from_be(self.0)) + } + } + + trait T { + // don't trigger (`s` is not `self`) + fn from_be(s: Self) -> Self; + // lint + fn from_be_self(self) -> Self; + } + + trait Foo: Sized { + fn as_byte_slice(slice: &[Self]) -> &[u8]; + } +} diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr index 0ca1a390974..0e0d066d656 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr @@ -1,11 +1,19 @@ -error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention2.rs:28:19 +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:55:29 | -LL | fn to_u64(self) -> u64 { - | ^^^^ +LL | pub fn from_be_self(self) -> Self { + | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name -error: aborting due to previous error +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:64:25 + | +LL | fn from_be_self(self) -> Self; + | ^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/util/cov.sh b/src/tools/clippy/util/cov.sh deleted file mode 100755 index 3f9a6b06f72..00000000000 --- a/src/tools/clippy/util/cov.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/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"/* diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 408c0b8da0b..a5b526be86f 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -346,6 +346,9 @@ pub struct Config { /// whether to run `tidy` when a rustdoc test fails pub has_tidy: bool, + /// The current Rust channel + pub channel: String, + // Configuration for various run-make tests frobbing things like C compilers // or querying about various LLVM component information. pub cc: String, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 983934d129a..26c1710be74 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -50,6 +50,15 @@ impl EarlyProps { let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); + // for `-Z gcc-ld=lld` + let has_rust_lld = config + .compile_lib_path + .join("rustlib") + .join(&config.target) + .join("bin") + .join("gcc-ld") + .join(if config.host.contains("windows") { "ld.exe" } else { "ld" }) + .exists(); iter_header(testfile, None, rdr, &mut |ln| { // we should check if any only-<platform> exists and if it exists @@ -136,6 +145,10 @@ impl EarlyProps { if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) { props.ignore = true; } + + if !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld") { + props.ignore = true; + } } if let Some(s) = config.parse_aux_build(ln) { @@ -438,6 +451,9 @@ impl TestProps { if let Some(edition) = config.parse_edition(ln) { self.compile_flags.push(format!("--edition={}", edition)); + if edition == "2021" { + self.compile_flags.push("-Zunstable-options".to_string()); + } } config.parse_and_update_revisions(ln, &mut self.revisions); @@ -876,6 +892,7 @@ impl Config { name == util::get_arch(&self.target) || // architecture name == util::get_pointer_width(&self.target) || // pointer width name == self.stage_id.split('-').next().unwrap() || // stage + name == self.channel || // channel (self.target != self.host && name == "cross-compile") || (name == "endian-big" && util::is_big_endian(&self.target)) || (self.remote_test_client.is_some() && name == "remote") || diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index ca7458d255c..2c607b6a50e 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -55,6 +55,7 @@ fn config() -> Config { "--llvm-components=", "--android-cross-path=", "--target=x86_64-unknown-linux-gnu", + "--channel=nightly", ]; let args = args.iter().map(ToString::to_string).collect(); crate::parse_config(args) @@ -235,6 +236,20 @@ fn asm_support() { } #[test] +fn channel() { + let mut config = config(); + config.channel = "beta".into(); + + assert!(parse_rs(&config, "// ignore-beta").ignore); + assert!(parse_rs(&config, "// only-nightly").ignore); + assert!(parse_rs(&config, "// only-stable").ignore); + + assert!(!parse_rs(&config, "// only-beta").ignore); + assert!(!parse_rs(&config, "// ignore-nightly").ignore); + assert!(!parse_rs(&config, "// ignore-stable").ignore); +} + +#[test] fn test_extract_version_range() { use super::{extract_llvm_version, extract_version_range}; diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index d53e19f2908..c854663706a 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -144,7 +144,8 @@ pub fn parse_config(args: Vec<String>) -> Config { "enable this to generate a Rustfix coverage file, which is saved in \ `./<build_base>/rustfix_missing_coverage.txt`", ) - .optflag("h", "help", "show this message"); + .optflag("h", "help", "show this message") + .reqopt("", "channel", "current Rust channel", "CHANNEL"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -278,6 +279,7 @@ pub fn parse_config(args: Vec<String>) -> Config { compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), rustfix_coverage: matches.opt_present("rustfix-coverage"), has_tidy, + channel: matches.opt_str("channel").unwrap(), cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), @@ -664,6 +666,10 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec<test ignore, should_panic, allow_fail: false, + #[cfg(not(bootstrap))] + compile_fail: false, + #[cfg(not(bootstrap))] + no_run: false, test_type: test::TestType::Unknown, }, testfn: make_test_closure(config, testpaths, revision), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 54b079a3e86..02dffaab7b6 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1785,6 +1785,9 @@ impl<'test> TestCx<'test> { get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib); rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name)); } + if !self.props.aux_crates.is_empty() { + rustc.arg("-Zunstable-options"); + } aux_dir } @@ -1835,6 +1838,7 @@ impl<'test> TestCx<'test> { || self.config.target.contains("nvptx") || self.is_vxworks_pure_static() || self.config.target.contains("sgx") + || self.config.target.contains("bpf") { // We primarily compile all auxiliary libraries as dynamic libraries // to avoid code size bloat and large binaries as much as possible @@ -2487,6 +2491,7 @@ impl<'test> TestCx<'test> { { let mut diff_output = File::create(&diff_filename).unwrap(); + let mut wrote_data = false; for entry in walkdir::WalkDir::new(out_dir) { let entry = entry.expect("failed to read file"); let extension = entry.path().extension().and_then(|p| p.to_str()); @@ -2499,17 +2504,28 @@ impl<'test> TestCx<'test> { if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; let actual_path = entry.path(); let actual = std::fs::read(&actual_path).unwrap(); - diff_output - .write_all(&unified_diff::diff( - &expected, - &expected_path.to_string_lossy(), - &actual, - &actual_path.to_string_lossy(), - 3, - )) - .unwrap(); + let diff = unified_diff::diff( + &expected, + &expected_path.to_string_lossy(), + &actual, + &actual_path.to_string_lossy(), + 3, + ); + wrote_data |= !diff.is_empty(); + diff_output.write_all(&diff).unwrap(); } } + + if !wrote_data { + println!("note: diff is identical to nightly rustdoc"); + assert!(diff_output.metadata().unwrap().len() == 0); + return; + } else if self.config.verbose { + eprintln!("printing diff:"); + let mut buf = Vec::new(); + diff_output.read_to_end(&mut buf).unwrap(); + std::io::stderr().lock().write_all(&mut buf).unwrap(); + } } match self.config.color { @@ -2675,12 +2691,11 @@ impl<'test> TestCx<'test> { let mut tested = 0; for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| { - let tmp: Vec<&str> = s.split(" - ").collect(); - if tmp.len() == 2 { - let path = tmp[0].rsplit("test ").next().unwrap(); + if let Some((left, right)) = s.split_once(" - ") { + let path = left.rsplit("test ").next().unwrap(); if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) { tested += 1; - let mut iter = tmp[1].split("(line "); + let mut iter = right.split("(line "); iter.next(); let line = iter .next() diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 7dbd70948b8..37164c4e575 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -48,6 +48,8 @@ const ARCH_TABLE: &[(&str, &str)] = &[ ("armv7s", "arm"), ("asmjs", "asmjs"), ("avr", "avr"), + ("bpfeb", "bpf"), + ("bpfel", "bpf"), ("hexagon", "hexagon"), ("i386", "x86"), ("i586", "x86"), diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index a6efc4c9a6b..b5f1554dbe4 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" 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" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 216890d59ad..b8ea10f3d22 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,5 +1,5 @@ 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; @@ -94,19 +94,19 @@ impl fmt::Display for CommandKind { } } -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) diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh index b68053c76be..9eeebf444a4 100755 --- a/src/tools/linkchecker/linkcheck.sh +++ b/src/tools/linkchecker/linkcheck.sh @@ -85,11 +85,11 @@ fi 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\"..." @@ -106,7 +106,7 @@ else 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 diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index c677d04917e..47960c3f6cc 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -14,18 +14,18 @@ //! 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 @@ -87,33 +87,64 @@ macro_rules! t { } 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") @@ -130,173 +161,169 @@ fn small_url_encode(s: &str) -> String { .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 @@ -309,85 +336,134 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti 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)..]; @@ -396,9 +472,9 @@ fn maybe_redirect(source: &str) -> Option<String> { }) } -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 @@ -437,3 +513,18 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, } } } + +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); + }); + } +} diff --git a/src/tools/linkchecker/tests/basic_broken/foo.html b/src/tools/linkchecker/tests/basic_broken/foo.html new file mode 100644 index 00000000000..cb27c55c9fe --- /dev/null +++ b/src/tools/linkchecker/tests/basic_broken/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="bar.html">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_local/foo.html b/src/tools/linkchecker/tests/broken_fragment_local/foo.html new file mode 100644 index 00000000000..66c457ad01f --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_local/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="#somefrag">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/bar.html b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html new file mode 100644 index 00000000000..7879e1ce9fd --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html new file mode 100644 index 00000000000..7683060b3a6 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="../bar.html#somefrag">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_redir/foo.html b/src/tools/linkchecker/tests/broken_redir/foo.html new file mode 100644 index 00000000000..bd3e3ad3343 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_redir/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="redir-bad.html">bad redir</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_redir/redir-bad.html b/src/tools/linkchecker/tests/broken_redir/redir-bad.html new file mode 100644 index 00000000000..3e376629f74 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_redir/redir-bad.html @@ -0,0 +1,10 @@ +<!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> diff --git a/src/tools/linkchecker/tests/checks.rs b/src/tools/linkchecker/tests/checks.rs new file mode 100644 index 00000000000..c6ec999e5cf --- /dev/null +++ b/src/tools/linkchecker/tests/checks.rs @@ -0,0 +1,77 @@ +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"); +} diff --git a/src/tools/linkchecker/tests/directory_link/foo.html b/src/tools/linkchecker/tests/directory_link/foo.html new file mode 100644 index 00000000000..40a8461b86c --- /dev/null +++ b/src/tools/linkchecker/tests/directory_link/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="somedir">dir link</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/directory_link/somedir/index.html b/src/tools/linkchecker/tests/directory_link/somedir/index.html new file mode 100644 index 00000000000..7879e1ce9fd --- /dev/null +++ b/src/tools/linkchecker/tests/directory_link/somedir/index.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> diff --git a/src/tools/linkchecker/tests/redirect_loop/foo.html b/src/tools/linkchecker/tests/redirect_loop/foo.html new file mode 100644 index 00000000000..bee58b212b5 --- /dev/null +++ b/src/tools/linkchecker/tests/redirect_loop/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="redir-bad.html">loop link</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/redirect_loop/redir-bad.html b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html new file mode 100644 index 00000000000..fe7780e6739 --- /dev/null +++ b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html @@ -0,0 +1,10 @@ +<!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> diff --git a/src/tools/linkchecker/tests/valid/inner/bar.html b/src/tools/linkchecker/tests/valid/inner/bar.html new file mode 100644 index 00000000000..4b500d78b76 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/bar.html @@ -0,0 +1,7 @@ +<html> +<body> + + <h2 id="barfrag">Bar</h2> + +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/foo.html b/src/tools/linkchecker/tests/valid/inner/foo.html new file mode 100644 index 00000000000..3c6a7483bcd --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/foo.html @@ -0,0 +1,14 @@ +<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> diff --git a/src/tools/linkchecker/tests/valid/inner/redir-bad.html b/src/tools/linkchecker/tests/valid/inner/redir-bad.html new file mode 100644 index 00000000000..d21336e7e73 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir-bad.html @@ -0,0 +1,11 @@ +<!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> diff --git a/src/tools/linkchecker/tests/valid/inner/redir-target.html b/src/tools/linkchecker/tests/valid/inner/redir-target.html new file mode 100644 index 00000000000..bd59884a01e --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir-target.html @@ -0,0 +1,5 @@ +<html> +<body> + <h2 id="redirfrag">Redir</h2> +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/redir.html b/src/tools/linkchecker/tests/valid/inner/redir.html new file mode 100644 index 00000000000..1808b23aed8 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir.html @@ -0,0 +1,10 @@ +<!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> diff --git a/src/tools/linkchecker/tests/valid/outer.html b/src/tools/linkchecker/tests/valid/outer.html new file mode 100644 index 00000000000..35f799f2023 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/outer.html @@ -0,0 +1,5 @@ +<html> +<body> +<a id="somefrag"></a> +</body> +</html> diff --git a/src/tools/miri b/src/tools/miri -Subproject 3a249581280ea0181cf3ae0d2028ee8b88d3d1e +Subproject e5c3af6f516311cc4b1fc017c58d83b7442cbc3 diff --git a/src/tools/rls b/src/tools/rls -Subproject 097d8908339e20435078233a55a1a3335fe7c2e +Subproject 517e9d62c095a04fa497d6b6d3c63b31696a88b diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject fd109fb587904cfecc1149e068814bfd38feb83 +Subproject 13da28cc2bc1b59f7af817eca36927a71edb023 diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 298fc7519fa..c55e014e834 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -63,6 +63,13 @@ async function main(argv) { // 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) { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index ced382c4915..bca9f77f959 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -107,7 +107,9 @@ pub(crate) fn format_expr( } ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape), ast::ExprKind::Struct(ref struct_expr) => { - let ast::StructExpr { fields, path, rest } = &**struct_expr; + let ast::StructExpr { + fields, path, rest, .. + } = &**struct_expr; rewrite_struct_lit(context, path, fields, rest, &expr.attrs, expr.span, shape) } ast::ExprKind::Tup(ref items) => { diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 6824fc661ba..fa0ef260991 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -45,7 +45,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { | ast::PatKind::Path(..) | ast::PatKind::Range(..) => false, ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1, - ast::PatKind::TupleStruct(ref path, ref subpats) => { + ast::PatKind::TupleStruct(_, ref path, ref subpats) => { path.segments.len() <= 1 && subpats.len() <= 1 } ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => { @@ -226,7 +226,7 @@ impl Rewrite for Pat { PatKind::Path(ref q_self, ref path) => { rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape) } - PatKind::TupleStruct(ref path, ref pat_vec) => { + PatKind::TupleStruct(_, ref path, ref pat_vec) => { let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?; rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape) } @@ -244,7 +244,7 @@ impl Rewrite for Pat { .collect(); Some(format!("[{}]", rw.join(", "))) } - PatKind::Struct(ref path, ref fields, ellipsis) => { + PatKind::Struct(_, ref path, ref fields, ellipsis) => { rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape) } PatKind::MacCall(ref mac) => { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index bba689d07a4..06cec1964a0 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -235,7 +235,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "ar", "autocfg", "bitflags", - "byteorder", "cfg-if", "cranelift-bforest", "cranelift-codegen", @@ -248,9 +247,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "cranelift-native", "cranelift-object", "crc32fast", - "errno", - "errno-dragonfly", - "gcc", "gimli", "hashbrown", "indexmap", @@ -259,17 +255,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "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", diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 55f824b63f2..d6e0ebaa541 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -8,15 +8,14 @@ use std::path::Path; // 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, @@ -114,13 +113,18 @@ fn extract_error_codes( .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!( @@ -198,6 +202,11 @@ pub fn check(paths: &[&Path], bad: &mut bool) { 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 + )); } } } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 7b42de0ec43..f61295c8830 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -7,8 +7,8 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 1370; -const ISSUES_ENTRY_LIMIT: usize = 2555; +const ROOT_ENTRY_LIMIT: usize = 1371; +const ISSUES_ENTRY_LIMIT: usize = 2559; fn check_entries(path: &Path, bad: &mut bool) { let dirs = walkdir::WalkDir::new(&path.join("test/ui")) diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs index 6a492bbff4d..a41e2d6e3aa 100644 --- a/src/tools/tier-check/src/main.rs +++ b/src/tools/tier-check/src/main.rs @@ -24,7 +24,7 @@ fn main() { 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(); diff --git a/src/version b/src/version index b7921ae87bc..094d6ad00ce 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.54.0 +1.55.0 diff --git a/triagebot.toml b/triagebot.toml index 8b6157cd4aa..c97f63f1cfd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -79,7 +79,7 @@ trigger_labels = [ "regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly", - "I-unsound 💥", + "I-unsound", ] exclude_labels = [ "P-*", |
