diff --git a/.gitattributes b/.gitattributes index 82599b145038..51a670b5fbef 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 aa9d97ba477b..36362635b154 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/Cargo.lock b/Cargo.lock index 954e2e90f3de..de110c55a4b2 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", @@ -293,7 +294,7 @@ dependencies = [ "rand 0.8.3", "rustc-workspace-hack", "rustfix", - "semver 0.10.0", + "semver 1.0.3", "serde", "serde_ignored", "serde_json", @@ -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", @@ -566,10 +567,6 @@ dependencies = [ "tester", ] -[[package]] -name = "clippy-mini-macro-test" -version = "0.2.0" - [[package]] name = "clippy_dev" version = "0.0.1" @@ -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", @@ -1715,6 +1712,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.6" @@ -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" @@ -2289,6 +2294,7 @@ dependencies = [ "hex 0.4.2", "libc", "log", + "measureme", "rand 0.8.3", "rustc-workspace-hack", "rustc_version", @@ -2353,6 +2359,17 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "object" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", +] + [[package]] name = "once_cell" version = "1.7.2" @@ -2845,9 +2862,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.47" +version = "2.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513c70e67444a0d62fdc581dffa521c6820942a5f08300d0864863f8d0e750e3" +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", @@ -4673,6 +4691,15 @@ dependencies = [ "serde", ] +[[package]] +name = "semver" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe" +dependencies = [ + "serde", +] + [[package]] name = "semver-parser" version = "0.7.0" @@ -4793,12 +4820,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" - [[package]] name = "shlex" version = "1.0.0" @@ -4903,7 +4924,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", - "object", + "object 0.22.0", "panic_abort", "panic_unwind", "profiler_builtins", @@ -5032,9 +5053,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_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b3bac1d7ecde..93d7a5976813 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, /* recovered */ bool), + Struct(Option, Path, Vec, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - TupleStruct(Path, Vec>), + TupleStruct(Option, Path, Vec>), /// 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, pub path: Path, pub fields: Vec, pub rest: StructRest, diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs index 945a44ab6637..d586426d70ef 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 14ecf27813d3..7c79b4aab3cc 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -12,13 +12,11 @@ #![feature(box_patterns)] #![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)] #![feature(min_specialization)] -#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 071d41ea2b2c..0b6099fd330d 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(pat: &mut P, 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(pat: &mut P, 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( } 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 2d463a4588c5..5d994dbad4d1 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 f1a99bc51c96..1ebfcf367110 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 866f2180bb6e..b9dcd083c0b8 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, &'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 6f1772ff8188..0ff1efd8165e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -43,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; @@ -198,7 +198,7 @@ pub trait ResolverAstLowering { fn next_node_id(&mut self) -> NodeId; - fn trait_map(&self) -> &NodeMap>; + fn take_trait_map(&mut self) -> NodeMap>; fn opt_local_def_id(&self, node: NodeId) -> Option; @@ -501,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 2451409aac88..66e623528f3b 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 ba2da7694978..30aa51a121a8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -938,8 +938,11 @@ 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; } @@ -959,7 +962,7 @@ fn validate_generic_param_order( span, &format!( "reorder the parameters: lifetimes, {}", - if sess.features_untracked().const_generics { + if sess.features_untracked().unordered_const_ty_params() { "then consts and types" } else { "then types, then consts" diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 4996c2195efd..3f98944d850e 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 c9e2d202da97..26da18b571cc 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/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b7bb896f3180..93facd255df5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1713,11 +1713,16 @@ impl<'a> State<'a> { fn print_expr_struct( &mut self, + qself: &Option, 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, @@ -1874,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); @@ -2340,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(); @@ -2355,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_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index e845f9ec55ad..99544ddb66e6 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/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index bd54adc53ee2..22897c43e7ef 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -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/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 9cf51d15c8ca..6676d88602c4 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -177,21 +177,6 @@ pub(crate) fn run_aot( metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box<(CodegenResults, FxHashMap)> { - 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() { @@ -307,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), }, diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 4ee887cd5afa..6aadaf8a7cad 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 { - 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 { 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(()) diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index ab238244d68d..db24bf65eb5a 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(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 484a9b699a0a..f86236ef3eaf 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, - flavor: Option, - ) -> 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_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 4999cb3c7ab4..d0eb6913accd 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 0aef77129d8c..ecf62ed213df 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 261affe2c427..64416bced31d 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 = 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::>().join(", "), + ); + + let ffi_exports: Vec = 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 893c909b2041..cc3cbea4def5 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); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index bc9d99ed4a12..c8cf0116c641 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/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f5c54b11c08e..6aa952462fa5 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 0db6659f8e25..1e70664e64d7 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>, 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$; + // + // } variant0; + // + // } + // ``` + // 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; + // enum Discriminant$ { + // + // } 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); - }); + let (size, align) = + cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty); - // 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), - }] + 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` 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>, 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 728f1224dd86..776cb2ee99bc 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -29,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; @@ -248,13 +248,6 @@ impl CodegenBackend for LlvmCodegenBackend { target_features(sess) } - fn metadata_loader(&self) -> Box { - 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>, @@ -304,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 8b1dcea3fa26..91923251018a 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? @@ -582,11 +607,6 @@ pub struct PassManager<'a>(InvariantOpaque<'a>); extern "C" { pub type PassManagerBuilder; } -extern "C" { - pub type ObjectFile; -} -#[repr(C)] -pub struct SectionIterator<'a>(InvariantOpaque<'a>); extern "C" { pub type Pass; } @@ -1703,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. @@ -2038,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 +2227,6 @@ extern "C" { pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>); pub fn LLVMRustDestroyArchive(AR: &'static mut Archive); - #[allow(improper_ctypes)] - pub fn LLVMRustGetSectionName( - SI: &SectionIterator<'_>, - data: &mut Option>, - ) -> size_t; - #[allow(improper_ctypes)] pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString); @@ -2305,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 bb9c6d47373b..38d56f872116 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 { - 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 387062a671d2..0dd3d2ae15bc 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_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3a677a2437c5..9bd5764f0730 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -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 c197d48d4ea6..63f457bb979e 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 32275e9b0734..6c9ec9e7b0da 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; - 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 { + let endianness = match sess.target.options.endian { + Endian::Little => Endianness::Little, + Endian::Big => Endianness::Big, + }; + let architecture = match &sess.target.arch[..] { + "arm" => Architecture::Arm, + "aarch64" => Architecture::Aarch64, + "x86" => Architecture::I386, + "s390x" => Architecture::S390x, + "mips" => Architecture::Mips, + "mips64" => Architecture::Mips64, + "x86_64" => { + if sess.target.pointer_width == 32 { + Architecture::X86_64_X32 + } else { + Architecture::X86_64 + } + } + "powerpc" => Architecture::PowerPc, + "powerpc64" => Architecture::PowerPc64, + "riscv32" => Architecture::Riscv32, + "riscv64" => Architecture::Riscv64, + "sparc64" => Architecture::Sparc64, + + // This is used to handle all "other" targets. This includes targets + // in two categories: + // + // * Some targets don't have support in the `object` crate just yet + // to write an object file. These targets are likely to get filled + // out over time. + // + // * Targets like WebAssembly don't support dylibs, so the purpose + // of putting metadata in object files, to support linking rlibs + // into dylibs, is moot. + // + // In both of these cases it means that linking into dylibs will + // not be supported by rustc. This doesn't matter for targets like + // WebAssembly and for targets not supported by the `object` crate + // yet it means that work will need to be done in the `object` crate + // to add a case above. + _ => return metadata.to_vec(), + }; + + if sess.target.is_like_osx { + let mut file = Object::new(BinaryFormat::MachO, architecture, endianness); + + let section = + file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug); + file.append_section_data(section, metadata, 1); + file.write().unwrap() + } else if sess.target.is_like_windows { + const IMAGE_SCN_LNK_REMOVE: u32 = 0; + let mut file = Object::new(BinaryFormat::Coff, architecture, endianness); + + let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug); + file.section_mut(section).flags = + SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE }; + file.append_section_data(section, metadata, 1); + file.write().unwrap() + } else { + const SHF_EXCLUDE: u64 = 0x80000000; + let mut file = Object::new(BinaryFormat::Elf, architecture, endianness); + + match &sess.target.arch[..] { + // copied from `mipsel-linux-gnu-gcc foo.c -c` and + // inspecting the resulting `e_flags` field. + "mips" => { + let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC; + file.flags = FileFlags::Elf { e_flags }; + } + // copied from `mips64el-linux-gnuabi64-gcc foo.c -c` + "mips64" => { + let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC; + file.flags = FileFlags::Elf { e_flags }; + } + + // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though + // that the `+d` target feature represents whether the double + // float abi is enabled. + "riscv64" if sess.target.options.features.contains("+d") => { + let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE; + file.flags = FileFlags::Elf { e_flags }; + } + + _ => {} + } + + let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug); + file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE }; + file.append_section_data(section, metadata, 1); + file.write().unwrap() + } + } +} + +/// 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)> { + let mut dylib_table: FxHashMap> = 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::>(); + 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::>(); + result.sort_unstable_by(|a: &(String, Vec), b: &(String, Vec)| { + 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 link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { +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 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, @@ -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::(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::(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::( - 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 @@ -1964,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 @@ -1981,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, @@ -2006,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. @@ -2017,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; } @@ -2070,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); }); } @@ -2178,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 => {} } } } @@ -2295,3 +2530,30 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result { 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 4dc9a3f5e41b..43ff664c3e64 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>, } @@ -81,8 +81,10 @@ impl LinkerInfo { Box::new(WasmLd::new(cmd, sess, self)) as Box } - LinkerFlavor::PtxLinker => { - Box::new(PtxLinker { cmd, sess, info: self }) as Box + LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box, + + LinkerFlavor::BpfLinker => { + Box::new(BpfLinker { cmd, sess, info: self }) as Box } } } @@ -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 { pub struct PtxLinker<'a> { cmd: Command, sess: &'a Session, - info: &'a LinkerInfo, } impl<'a> Linker for PtxLinker<'a> { @@ -1374,11 +1374,6 @@ 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") } @@ -1431,3 +1426,117 @@ impl<'a> Linker for PtxLinker<'a> { 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) { + 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) { + 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) {} + + fn group_start(&mut self) {} + + fn group_end(&mut self) {} + + fn linker_plugin_lto(&mut self) {} +} diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 37d1f8ecc832..0fff31958088 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 { - 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 5f21046b05e4..39b0ccd120de 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 { @@ -63,24 +62,13 @@ fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec { // 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 { 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 { 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 35836ae719b9..24c362db1227 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 14d6f0ba147b..b2ecc3b0f324 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 49774dc6d5c7..ff4e64095714 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( 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( OngoingCodegen { backend, - crate_name, metadata, - windows_subsystem, linker_info, crate_info, @@ -1812,9 +1798,7 @@ impl SharedEmitterMain { pub struct OngoingCodegen { pub backend: B, - pub crate_name: Symbol, pub metadata: EncodedMetadata, - pub windows_subsystem: Option, pub linker_info: LinkerInfo, pub crate_info: CrateInfo, pub coordinator_send: Sender>, @@ -1857,9 +1841,7 @@ impl OngoingCodegen { ( 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 b44e74d5ae82..38ab39febe06 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 Drop for AbortCodegenOnDrop { 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 08442c588f87..c1dfe1ef8560 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 d1bbf74307c6..7b4b0821c4be 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>, + ) { + 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 6c4bb021cb3a..b6de12fa35e3 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,15 +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)] #![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 @@ -114,11 +110,18 @@ pub struct NativeLib { pub name: Option, pub cfg: Option, pub verbatim: Option, + pub dll_imports: Vec, } 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(), + } } } @@ -132,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, pub compiler_builtins: Option, pub profiler_runtime: Option, @@ -145,16 +149,15 @@ pub struct CrateInfo { pub lang_item_to_crate: FxHashMap, pub missing_lang_items: FxHashMap>, pub dependency_formats: Lrc, + pub windows_subsystem: Option, } #[derive(Encodable, Decodable)] pub struct CodegenResults { - pub crate_name: Symbol, pub modules: Vec, pub allocator_module: Option, pub metadata_module: Option, pub metadata: rustc_middle::middle::cstore::EncodedMetadata, - pub windows_subsystem: Option, 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 38e928145a81..49b5e8466bef 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> 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> 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 98d550d732fe..c89d42ecc58a 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)] = &[ ]; const WASM_ALLOWED_FEATURES: &[(&str, Option)] = &[ - ("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)] = &[("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 &'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 f28db2fe84b6..dc4146ec7b58 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; - 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 { + 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/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs deleted file mode 100644 index eb6f4e8213ec..000000000000 --- 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 { - generator: Pin, Return = R>>>, -} - -impl PinnedGenerator { - pub fn new, 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(PhantomData); - -impl Marker { - pub unsafe fn new() -> Self { - Marker(PhantomData) - } -} - -pub enum YieldType { - Initial(I), - Accessor(Marker), -} - -#[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 + 'static>( - generator: T - ) -> ($reti, Self) { - let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); - (initial, $name(pinned)) - } - - $v fn access 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/lib.rs b/compiler/rustc_data_structures/src/lib.rs index adbb98fa7504..16151e9dca5e 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 29d685ab530d..05b1a85381f4 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 ObligationForest { 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 ObligationForest { && 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 ObligationForest { 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 ObligationForest { }); } } - -// I need a Clone closure. -#[derive(Clone)] -struct GetObligation<'a, O>(&'a [Node]); - -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 ff28784a1dc4..18b352cf3b0b 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( 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(Vec); - -impl StableVec { - pub fn new(v: Vec) -> Self { - StableVec(v) - } -} - -impl ::std::ops::Deref for StableVec { - type Target = Vec; - - fn deref(&self) -> &Vec { - &self.0 - } -} - -impl HashStable for StableVec -where - T: HashStable + ToStableHashKey, -{ - 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 26706cd2b1b7..722ce6b63672 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(Cell); - - impl AtomicCell { - #[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 AtomicCell { - #[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(&self, f: F) - where F: FnOnce(&SerialScope) - { - f(self) - } - } - - pub fn scope(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 cd1e12ca4501..324a8624dd07 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 Pointer for Box { const BITS: usize = std::mem::align_of::().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 Pointer for Box { unsafe impl Pointer for Rc { const BITS: usize = std::mem::align_of::().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 Pointer for Rc { unsafe impl Pointer for Arc { const BITS: usize = std::mem::align_of::().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 Pointer for Arc { unsafe impl<'a, T: 'a> Pointer for &'a T { const BITS: usize = std::mem::align_of::().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::().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 000000000000..73b04d3329cb --- /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(Vec<(K, V)>); + +impl VecMap +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 { + 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(&self, k: &Q) -> Option<&V> + where + K: Borrow, + 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(&self, k: &Q) -> bool + where + K: Borrow, + 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 Default for VecMap { + #[inline] + fn default() -> Self { + Self(Default::default()) + } +} + +impl From> for VecMap { + fn from(vec: Vec<(K, V)>) -> Self { + Self(vec) + } +} + +impl Into> for VecMap { + fn into(self) -> Vec<(K, V)> { + self.0 + } +} + +impl FromIterator<(K, V)> for VecMap { + fn from_iter>(iter: I) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl<'a, K, V> IntoIterator for &'a VecMap { + 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 { + type Item = &'a mut (K, V); + type IntoIter = IterMut<'a, (K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl IntoIterator for VecMap { + type Item = (K, V); + type IntoIter = IntoIter<(K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Extend<(K, V)> for VecMap { + fn extend>(&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 HashStable for VecMap +where + K: HashStable + Eq, + V: HashStable, +{ + 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 000000000000..9083de85982e --- /dev/null +++ b/compiler/rustc_data_structures/src/vec_map/tests.rs @@ -0,0 +1,48 @@ +use super::*; + +impl VecMap { + fn into_vec(self) -> Vec<(K, V)> { + self.0.into() + } +} + +#[test] +fn test_from_iterator() { + assert_eq!( + std::iter::empty().collect::>().into_vec(), + Vec::<(i32, bool)>::new() + ); + assert_eq!(std::iter::once((42, true)).collect::>().into_vec(), vec![(42, true)]); + assert_eq!( + vec![(1, true), (2, false)].into_iter().collect::>().into_vec(), + vec![(1, true), (2, false)] + ); +} + +#[test] +fn test_into_iterator_owned() { + assert_eq!(VecMap::new().into_iter().collect::>(), Vec::<(i32, bool)>::new()); + assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::>(), vec![(1, true)]); + assert_eq!( + VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::>(), + 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::>(); + 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 c9b36dd0c24c..b943977e4c2b 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 { } // 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 { } 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 c343809179b0..f10efd832361 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 000000000000..4368c321737b --- /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) +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) +where + for<'a, 'b> &'a T: Tr<'a, 'b>, // ok +{ +} +``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md index 2fe5ada257fc..6b16a7d415aa 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 { // 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 { // ok! +fn bar(x: &'static i32) -> Box { // ok! Box::new(x) } ``` diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 5d175a3ade9a..72395bd31eca 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 Encodable 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 65352f0bc6e7..979f2d3b3005 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 e1c218c64085..aab2741c8524 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, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index cb8b9398283e..ef5b97a94690 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -275,7 +275,12 @@ impl<'a> ExtCtxt<'a> { ) -> P { 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 { - 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, ) -> P { - 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 { self.pat(span, PatKind::Tuple(pats)) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f5c6bb3db654..39c0447bd099 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(""), 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 16510b3eb07c..efed41de23a8 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,7 +1,7 @@ -#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] +#![feature(format_args_capture)] #![feature(iter_zip)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 1aed42a24e2b..a7434d73abe6 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 91d4a0f0d658..abad190b072a 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 aca02ef93f8b..fb7479eafc86 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 { // 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, @@ -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/active.rs b/compiler/rustc_feature/src/active.rs index a84737e80a09..56a320c8d3bc 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), @@ -665,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 // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e7e128f8a9b2..259a6328a22f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -568,10 +568,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), - rustc_attr!( - TEST, rustc_dirty, AssumedUsed, - template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - ), rustc_attr!( TEST, rustc_clean, AssumedUsed, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 138398825af5..71c10eb65075 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 647d735fb863..753b8c85670b 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 + '_ { - 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 + '_ { 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 { + 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 91fd97a0d402..577d43b1c8e5 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, - pub trait_map: BTreeMap>, + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap>>, /// Collected attributes from HIR nodes. pub attrs: BTreeMap, @@ -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 7f3c410b1ec6..ad2ecae9233b 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -3,12 +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)] #![feature(min_specialization)] -#![feature(trusted_step)] #![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 0232654aaa52..560607528330 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(&mut self, f: F); - fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash; } impl ToStableHashKey for HirId { @@ -29,7 +28,7 @@ impl ToStableHashKey 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 ToStableHashKey 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 ToStableHashKey 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 ToStableHashKey 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 ToStableHashKey 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_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index e7bd488af8eb..9abd4eae914b 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 @@ -101,6 +99,12 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = /// For generic cases like inline-assembly, modules, etc. const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR]; +/// Impl `DepNode`s. +const LABELS_TRAIT: &[&[&str]] = &[ + BASE_HIR, + &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of], +]; + /// Impl `DepNode`s. const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL]; @@ -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 { - 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 { - 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 Trait for Foo { .. }` HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL), @@ -434,33 +380,21 @@ 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))); + } else if !item.has_name(EXCEPT) { + tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty())); } - if item.has_name(LABEL) { - label = true; - } - if item.has_name(EXCEPT) { - except = true; - } - } - - if label && except { - tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`"); } match cfg { @@ -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) { 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 { diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 303c39a39a92..8539cc693713 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,7 +1,6 @@ //! 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::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::query::OnDiskCache; use rustc_serialize::opaque::Decoder; @@ -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> { +pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option> { 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 9603b102cbc5..a8455854ebb5 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -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 04d62391c021..0093fa5e562a 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,12 +1,10 @@ #![feature(allow_internal_unstable)] #![feature(bench_black_box)] -#![feature(const_panic)] #![feature(extend_one)] #![feature(iter_zip)] #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] -#![feature(trusted_step)] pub mod bit_set; pub mod vec; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 3f759f4023b5..246fa28d986e 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, rustc_attrs)] +#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)] macro_rules! newtype_index { // ---- public rules ---- diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b8ecc949588f..c3c28d700815 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 30214e94203d..3a11b5a21449 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>( &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>( &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 45ba50bb6349..0c93271a1aec 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>( &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 680f6af63f26..e3a79fe26533 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 { - 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 02662043dba7..60f02b84aa34 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>( &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 4fa8f2f1a6a4..a08323535c55 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>( &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 077d2cc20a25..20be06adfd09 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>( &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>( &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 bf5f328233df..b3131936ae06 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>( &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 6b452bca8e70..ee358c52c2f5 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,14 +16,12 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(extend_one)] #![feature(iter_zip)] #![feature(never_type)] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] #![feature(min_specialization)] -#![feature(trusted_step)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index f2b69da3f86b..c7424b9e2a12 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 f99d92902385..9e3e96df3a7f 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, ResolverOutputs) -); +pub use boxed_resolver::BoxedResolver; +mod boxed_resolver { + use super::*; + + pub struct BoxedResolver(Pin>); + + struct BoxedResolverInner { + session: Lrc, + resolver_arenas: Option>, + resolver: Option>, + _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(session: Lrc, 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 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>) -> 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>) -> 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>( @@ -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, ) -> 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, ) }) }); @@ -981,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 969b526235bb..2320f0b47d27 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -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 { - 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, + codegen_backend: Lrc>, + + // compilation outputs dep_graph: DepGraph, prepare_outputs: OutputFilenames, crate_hash: Svh, ongoing_codegen: Box, - codegen_backend: Lrc>, } impl Linker { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index bea7d0fb81f9..5d8a6084f2e0 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 7b1660b501bf..6485fbebd665 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 { } } -pub fn get_codegen_backend(sopts: &config::Options) -> Box { - static INIT: Once = Once::new(); +/// 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, + backend_name: Option<&str>, +) -> Box { + static LOAD: SyncOnceCell Box> = SyncOnceCell::new(); - static mut LOAD: fn() -> Box = || unreachable!(); - - 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 { } } -pub fn get_builtin_codegen_backend( - maybe_sysroot: &Option, - backend_name: &str, -) -> fn() -> Box { - 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, backend_name: &str, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e7275374b891..f6a84966f7a9 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 c1d6a4f1de1f..a8df1b0952c1 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, + ) -> 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 { - 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 91cdef9b089f..0ee434f5fb50 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 45ed6872f188..4f59460aa82a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -36,8 +36,6 @@ #![feature(iter_zip)] #![feature(never_type)] #![feature(nll)] -#![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] #![recursion_limit = "256"] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9c94bab04e98..a3a87a48768d 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> { 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 67946dfb292a..44c2a550c30e 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 15246971bae0..352146d64635 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 70475563a4ab..f1c4e5fb4a36 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/build.rs b/compiler/rustc_llvm/build.rs index 301ed639f3b5..452d1b19a18a 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/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 2e135fbe2bd8..9b757eb40c18 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> 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(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 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(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 555aefb19294..122627eb500a 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 72bd4804e98c..7bc669f2b005 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::() }); + 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 e9ae22f8cedb..d73cfe35dc4a 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, 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, 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 15c9eda9902c..2c9bad7e5ced 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,5 +1,4 @@ #![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)] @@ -7,7 +6,6 @@ #![feature(once_cell)] #![feature(proc_macro_internals)] #![feature(min_specialization)] -#![feature(stmt_expr_attributes)] #![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] @@ -31,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 bc342119efb9..cd4c394ae14e 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 b27eef376c49..52cb1e1996e3 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 e25b22c83317..9a97835d9c00 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: . + /// See 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 { 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 { self.allocator_kind() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0c31430598a9..760073980004 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 04fe5cf5890a..99ea0cc8f2f1 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` 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/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 342cc9a7397b..8ffd98326f1c 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>, + map: IndexVec>>, parenting: FxHashMap, /// 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 d154b7804f05..20bbf9097f42 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 879372c65eaa..087f772c812b 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>, + /// 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>>, + /// 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, } -#[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> 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>>, + /// Content of local bodies. bodies: FxHashMap>, } @@ -65,6 +74,8 @@ impl<'a, 'tcx> HashStable> 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, @@ -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 b2fef731b7e2..91c81c367a16 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 { diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs index abf56832329b..5dfd00bc6d42 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> for DefId { - type KeyType = DefPathHash; - - #[inline] - fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash { - hcx.def_path_hash(*self) - } -} - -impl<'a> HashStable> 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> 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> 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> for hir::ItemLocalId { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 5df2f91f09ff..d764d45ba7e5 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 6f97716e2e0d..e1d7bc4be533 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,6 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] #![feature(never_type)] @@ -50,7 +49,6 @@ #![feature(associated_type_defaults)] #![feature(iter_zip)] #![feature(thread_local_const_init)] -#![feature(trusted_step)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 38d0793a6825..4c7ea937ceb7 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, pub lint_cap: Level, + pub force_warns: FxHashSet, } #[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>, 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> 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 d63116e29c86..a7ab43d106c4 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, pub wasm_import_module: Option, pub verbatim: Option, + pub dll_imports: Vec, +} + +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct DllImport { + pub name: Symbol, + pub ordinal: Option, } #[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; } diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 276e45ce99b2..288dd0394464 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 776a777b1bdb..1ef10241143b 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/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7282e65f3f88..65d9c1dd90ef 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -435,8 +435,12 @@ impl 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)] diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d03a7421ca7f..14bdb0a5a2d5 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 1cc7f235d7d2..7ae7eab6e5a3 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 { 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 0109580a0bba..74650f50a1c8 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -267,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 } } @@ -311,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 0edb79fdbc8e..4fb737f463a8 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>, + pub concrete_opaque_types: VecMap, Ty<'tcx>>, pub closure_requirements: Option>, 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 04aa30170dc6..0860520ef9df 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> { 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) } } @@ -1127,8 +1127,7 @@ rustc_queries! { desc { "computing whether impls specialize one another" } } query in_scope_traits_map(_: LocalDefId) - -> Option<&'tcx FxHashMap>> { - eval_always + -> Option<&'tcx FxHashMap>> { desc { "traits in scope at a block" } } @@ -1252,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" } @@ -1419,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> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 8e2c79701af9..02ff1b9f4d65 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>( &mut self, _: ty::Variance, + _: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cb08d7671bd2..d13cbdd12285 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -31,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}; @@ -47,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}; @@ -286,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 = impl Bar; fn foo() -> Foo { .. }` - /// 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 @@ -424,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>, + pub concrete_opaque_types: VecMap, Ty<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. @@ -966,10 +957,6 @@ pub struct GlobalCtxt<'tcx> { /// Resolutions of `extern crate` items produced by resolver. extern_crate_map: FxHashMap, - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - trait_map: FxHashMap>>, - /// Export map produced by name resolution. export_map: ExportMap, @@ -1009,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, @@ -1139,7 +1126,7 @@ impl<'tcx> TyCtxt<'tcx> { on_disk_cache: Option>, 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); @@ -1150,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, @@ -1169,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, @@ -1190,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, } } @@ -1275,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() { @@ -1314,10 +1288,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn metadata_encoding_version(self) -> Vec { - 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) @@ -2662,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> { - 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 { @@ -2793,7 +2765,7 @@ fn ptr_eq(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 982c8a354b4a..bfb4c0cb538d 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 c8fdbc30d159..4e3f475a915f 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 03a026500d70..28a44b09de2b 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() { diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index e657088a5e46..44dfcbf1866a 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -37,9 +37,11 @@ pub struct List { unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List { const BITS: usize = std::mem::align_of::().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { self as *const List as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { &*(ptr as *const List) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 94e325e9e878..227aa8dc284e 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, 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 { 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 f514278a11c9..25557bdd1000 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)); } _ => {} } diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 3bdb438896bf..297110ee3ecf 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -34,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 a688b816e9af..5c42625306bf 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>, - // 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, // 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, - start_pos: usize, - def_path_table: &DefPathTable, - ) -> Self { + pub fn new(sess: &'sess Session, data: Vec, 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 b6f93c9bd59e..3f426b13688f 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>( &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>( - 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>( 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>( (&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>( } (&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>( (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 f35ecb4d3cd5..1d9ff512288d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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] @@ -1888,11 +1890,6 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize)) } - #[inline] - pub fn is_machine(&self) -> bool { - matches!(self.kind(), Int(..) | Uint(..) | Float(..)) - } - #[inline] pub fn has_concrete_skeleton(&self) -> bool { !matches!(self.kind(), Param(_) | Infer(_) | Error(_)) @@ -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_mir/src/borrow_check/constraints/graph.rs b/compiler/rustc_mir/src/borrow_check/constraints/graph.rs index f3f6b8c10da7..9e4cfb2cc00f 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; /// 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 ConstraintGraph { /// 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 ConstraintGraph { /// 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 ConstraintGraph { } } -crate struct Edges<'s, D: ConstraintGraphDirecton> { +crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> { graph: &'s ConstraintGraph, - constraints: &'s OutlivesConstraintSet, + constraints: &'s OutlivesConstraintSet<'tcx>, pointer: Option, next_static_idx: Option, 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 { 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, 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, 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 { @@ -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) -> >::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 3772b7d8f986..b944479ca456 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, +crate struct OutlivesConstraintSet<'tcx> { + outlives: IndexVec>, } -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 { + crate fn outlives(&self) -> &IndexVec> { &self.outlives } } -impl Index for OutlivesConstraintSet { - type Output = OutlivesConstraint; +impl<'tcx> Index 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/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index 1b0cae51d585..e9f1ecb9bbc8 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) { - 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 d2b156610476..bf5f2c0eec23 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -902,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 8665ef06126a..feb7672f650e 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 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 4c35be39a3d3..36eb8a4baa83 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 a0265b20d127..bfeafa33a91c 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; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: FxHashMap>, + pub opaque_type_values: VecMap, Ty<'tcx>>, pub polonius_output: Option>, pub opt_closure_req: Option>, 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>, - opaque_type_values: &FxHashMap>, + opaque_type_values: &VecMap, Ty<'tcx>>, errors_buffer: &mut Vec, ) { 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 3654b51949e7..d21550a8e1af 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 5892ef37ebac..213ebff12abc 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 7156612f4730..b944d74e6f23 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 = 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 f4d78ac04cb0..dded7a7e3cf9 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, /// The outlives constraints computed by the type-check. - constraints: Frozen, + constraints: Frozen>, /// 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>, placeholder_indices: Rc, universal_region_relations: Frozen>, - 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, RegionVid)> { + ) -> Option<(Vec>, 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> = 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 0d1d25510427..3ec24156f223 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>, + opaque_ty_decls: VecMap, Ty<'tcx>>, span: Span, - ) -> FxHashMap> { + ) -> VecMap, 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 8513e5e531bd..eb11b9371433 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 bddcd34ed3e4..a34ae281b70d 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 { // 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 d27fcb2f26f1..09cafddeeffd 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>, + opaque_type_values: VecMap, 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>, - crate opaque_type_values: FxHashMap>, + crate opaque_type_values: VecMap, 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, - 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 249945f04b7b..f97252a117a6 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 754ed0bea849..fc21047ab72f 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> 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, + mut lint_root: Option, ) -> 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::().expect("invalid MachineStop payload").clone() - } - err => err.to_string(), - }; - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option| { + 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 . - 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 . + 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/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 1bfbb843114d..cea465ea1ed9 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/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 99622fb310aa..4e4166dad50e 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/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 4978cc3606dd..a7012cd63f31 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.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 = 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) diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 11f8d388820e..d0c04b5b414e 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -158,6 +158,8 @@ 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_format!("invalid vtable: alignment {}", e))?; if size >= self.tcx.data_layout.obj_size_bound() { throw_ub_format!( @@ -165,6 +167,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size is bigger than largest supported object" ); } - Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap())) + Ok((Size::from_bytes(size), align)) } } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 647c368d2bb8..1da17bddcb77 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)] @@ -31,7 +29,6 @@ Rust MIR: a lowered representation of Rust. #![feature(option_get_or_insert_default)] #![feature(once_cell)] #![feature(control_flow_enum)] -#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 41d9d0d04b50..4fbd27c89d9c 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -356,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) } @@ -730,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); @@ -753,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 955be8cc81e1..103ddda1a1d2 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 b5c8b4bebc36..ba10b54c5ae2 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/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index 2397d627880f..f6672335cb13 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 c41e71e09a4e..912505c65983 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 29df86ca6cdb..4f5a467a6ee6 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 7934d4ba8499..07127042fa41 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 003003a8abbe..3560b4b1e864 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 b6f80763bc8c..f1c95a84ade8 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 7aaf0224164c..b64189a7f3c1 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 f7a9835353e5..21b208a08c2d 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 4aaa0baa9f46..cd2db1805528 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 f6b1323e1079..78e84419c62c 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 5144d48750de..02e45021a0aa 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 70f7538dd57a..40b1a8a2da9f 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 65e2d096b209..7aebca77e6f2 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>, + 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 89fddc95c98f..dd2ec39c066a 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 658c6b6e9db2..e7fb6b4f6b4a 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 d009b0b1b238..835789069bb2 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 6ce305a48211..770b52a4d4b0 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/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 2185bd3a5c61..69786c14ee8d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -186,25 +186,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` // - // FIXME(RFC2229, rust#85435): Remove feature gate once diagnostics are - // improved and unsafe checking works properly in closure bodies again. - if this.tcx.features().capture_disjoint_fields { - 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])); + 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])); - if let Ok(place_builder_resolved) = - place_builder.try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = - place_builder_resolved.into_place(this.tcx, this.typeck_results); - this.cfg.push_fake_read( - block, - this.source_info(this.tcx.hir().span(*hir_id)), - *cause, - mir_place, - ); - } + if let Ok(place_builder_resolved) = + place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = + place_builder_resolved.into_place(this.tcx, this.typeck_results); + this.cfg.push_fake_read( + block, + this.source_info(this.tcx.hir().span(*hir_id)), + *cause, + mir_place, + ); } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index d1aaabe92eda..2d52577829c7 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -166,13 +166,16 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(expr.span, CallToUnsafeFunction); } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() { // If the called function has target features the calling function hasn't, - // the call requires `unsafe`. - if !self - .tcx - .codegen_fn_attrs(func_did) - .target_features - .iter() - .all(|feature| self.body_target_features.contains(feature)) + // the call requires `unsafe`. Don't check this on wasm + // targets, though. For more information on wasm see the + // is_like_wasm check in typeck/src/collect.rs + if !self.tcx.sess.target.options.is_like_wasm + && !self + .tcx + .codegen_fn_attrs(func_did) + .target_features + .iter() + .all(|feature| self.body_target_features.contains(feature)) { self.requires_unsafe(expr.span, CallToFunctionWith); } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 99b854ff066e..d2992f0bf186 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,17 +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)] #![feature(min_specialization)] -#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index da642bb2d28b..51df06bd9894 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,7 +3,6 @@ #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(iter_order_by)] #![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 ee6ff4dba396..8b050389078a 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 35759a396e87..e1d0b84f4193 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 72fdc78c30cb..b37caaebfb68 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 56c97b594768..c8789abc142d 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> { - // 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> { - 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>> { @@ -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, 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 c64fab0507c9..54e6ff6272c0 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 4c2bc6ebf314..cd9f84db5e55 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 0c43e304f1ee..30a6b61407f6 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 0abefbd6a121..418122202be1 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, 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, 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. `::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 9cc600d9ede0..953c6915068a 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(); + 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() } - - // 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(); - - // 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 b40eed8c5d11..9ef3f61ec346 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 89cf2d7876e1..de5a5632600e 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_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bf574bbfbb5a..b18ef3029623 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 4803148eba91..28633faa205d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,13 +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)] #![feature(min_specialization)] -#![feature(trusted_step)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e64f12ef48f2..5a79a9cc6ecf 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -156,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 ac81c0261e29..4175fb6925ac 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] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 08309d63a45f..b4191c135b4f 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}; @@ -57,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 diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 2517793ecea7..95edc1e93a53 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 cfae65abe838..71e67dfee538 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -44,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 for QueryInvocationId { @@ -108,6 +109,7 @@ where impl DepGraph { pub fn new( + profiler: &SelfProfilerRef, prev_graph: SerializedDepGraph, prev_work_products: FxHashMap, encoder: FileEncoder, @@ -116,16 +118,23 @@ impl DepGraph { ) -> DepGraph { 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, @@ -287,30 +296,47 @@ impl DepGraph { 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; - // 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 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(), + 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()) diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 6a84a28be665..73c00fc49ba3 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -122,21 +122,21 @@ impl<'a, K: DepKind + Decodable>> Decodable = d.read_struct_field("node", 0, Decodable::decode)?; + d.read_struct(|d| { + let dep_node: DepNode = 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(); diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 7df3804c986d..0d4fb34265c5 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,12 +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)] -#![feature(trusted_step)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a1eafd65d643..03d94f43897b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -450,7 +450,7 @@ impl<'a> Resolver<'a> { 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 662d39f6ef39..a21d8197bdbb 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 @@ -1959,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() { @@ -2288,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); } @@ -2435,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 efa5d7e7b113..ca7cdc4caf50 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(&mut self, f: F) - where - F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), - { - f(self) - } - fn with(&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 76d845f782e7..6d5531d33078 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -242,7 +242,7 @@ enum ResolutionError<'a> { 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. @@ -909,7 +909,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, export_map: ExportMap, - trait_map: NodeMap>, + trait_map: Option>>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1138,8 +1138,8 @@ impl ResolverAstLowering for Resolver<'_> { self.next_node_id() } - fn trait_map(&self) -> &NodeMap> { - &self.trait_map + fn take_trait_map(&mut self) -> NodeMap> { + std::mem::replace(&mut self.trait_map, None).unwrap() } fn opt_local_def_id(&self, node: NodeId) -> Option { @@ -1198,7 +1198,7 @@ impl<'a> Resolver<'a> { session: &'a Session, krate: &Crate, crate_name: &str, - metadata_loader: &'a MetadataLoaderDyn, + metadata_loader: Box, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; @@ -1286,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, @@ -2608,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 2bba6500d89c..297383bfed1f 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -823,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 ae6d27e037b2..80a7f6501888 100644 --- a/compiler/rustc_serialize/src/collection_impls.rs +++ b/compiler/rustc_serialize/src/collection_impls.rs @@ -21,8 +21,8 @@ impl>> Decodable for SmallVec { d.read_seq(|d, len| { let mut vec = SmallVec::with_capacity(len); // FIXME(#48994) - could just be collected into a Result - 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> Decodable for LinkedList { fn decode(d: &mut D) -> Result, 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> Decodable for VecDeque { fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut deque: VecDeque = 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, 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, 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 78a102c5c233..b79adb6f7bcd 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(&mut self, _name: &str, f: F) -> EncodeResult + fn emit_enum(&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(&mut self, idx: usize, f: F) -> EncodeResult + fn emit_enum_variant_arg(&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( - &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(&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(&mut self, _: &str, _: usize, f: F) -> EncodeResult + fn emit_struct(&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(&mut self, name: &str, idx: usize, f: F) -> EncodeResult + fn emit_struct_field(&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(&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(&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(&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(&mut self, _idx: usize, f: F) -> EncodeResult + fn emit_map_elt_val(&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(&mut self, _name: &str, f: F) -> EncodeResult + fn emit_enum(&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(&mut self, idx: usize, f: F) -> EncodeResult + fn emit_enum_variant_arg(&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( - &mut self, - name: &str, - id: usize, - cnt: usize, - f: F, - ) -> EncodeResult + fn emit_struct(&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(&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(&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(&mut self, name: &str, idx: usize, f: F) -> EncodeResult + fn emit_struct_field(&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(&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(&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(&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(&mut self, _idx: usize, f: F) -> EncodeResult + fn emit_map_elt_val(&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(&mut self, _name: &str, f: F) -> DecodeResult + fn read_enum(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { @@ -2410,33 +2320,14 @@ impl crate::Decoder for Decoder { f(self, idx) } - fn read_enum_variant_arg(&mut self, _idx: usize, f: F) -> DecodeResult + fn read_enum_variant_arg(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { f(self) } - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodeResult - where - F: FnMut(&mut Decoder, usize) -> DecodeResult, - { - self.read_enum_variant(names, f) - } - - fn read_enum_struct_variant_field( - &mut self, - _name: &str, - idx: usize, - f: F, - ) -> DecodeResult - where - F: FnOnce(&mut Decoder) -> DecodeResult, - { - self.read_enum_variant_arg(idx, f) - } - - fn read_struct(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult + fn read_struct(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { @@ -2445,7 +2336,7 @@ impl crate::Decoder for Decoder { Ok(value) } - fn read_struct_field(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult + fn read_struct_field(&mut self, name: &str, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { @@ -2483,25 +2374,11 @@ impl crate::Decoder for Decoder { }) } - fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult + fn read_tuple_arg(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&mut self, _name: &str, len: usize, f: F) -> DecodeResult - where - F: FnOnce(&mut Decoder) -> DecodeResult, - { - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult - where - F: FnOnce(&mut Decoder) -> DecodeResult, - { - self.read_tuple_arg(idx, f) + self.read_seq_elt(f) } fn read_option(&mut self, mut f: F) -> DecodeResult @@ -2527,7 +2404,7 @@ impl crate::Decoder for Decoder { f(self, len) } - fn read_seq_elt(&mut self, _idx: usize, f: F) -> DecodeResult + fn read_seq_elt(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { @@ -2547,14 +2424,14 @@ impl crate::Decoder for Decoder { f(self, len) } - fn read_map_elt_key(&mut self, _idx: usize, f: F) -> DecodeResult + fn read_map_elt_key(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { f(self) } - fn read_map_elt_val(&mut self, _idx: usize, f: F) -> DecodeResult + fn read_map_elt_val(&mut self, f: F) -> DecodeResult where F: FnOnce(&mut Decoder) -> DecodeResult, { diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index cf5a9118275d..c79786a839fc 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 d3e5f306970c..bb3c537ef194 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(&mut self, _name: &str, f: F) -> Result<(), Self::Error> + fn emit_enum(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -59,40 +59,7 @@ pub trait Encoder { } #[inline] - fn emit_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error> - where - F: FnOnce(&mut Self) -> Result<(), Self::Error>, - { - f(self) - } - - fn emit_enum_struct_variant( - &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( - &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(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> + fn emit_enum_variant_arg(&mut self, _first: bool, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, { @@ -100,12 +67,15 @@ pub trait Encoder { } #[inline] - fn emit_struct_field( - &mut self, - _f_name: &str, - _f_idx: usize, - f: F, - ) -> Result<(), Self::Error> + fn emit_struct(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error> + where + F: FnOnce(&mut Self) -> Result<(), Self::Error>, + { + f(self) + } + + #[inline] + fn emit_struct_field(&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(&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(&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(&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(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + fn emit_map_elt_val(&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(&mut self, _name: &str, f: F) -> Result + fn read_enum(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -246,34 +202,7 @@ pub trait Decoder { } #[inline] - fn read_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - { - f(self) - } - - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result - where - F: FnMut(&mut Self, usize) -> Result, - { - self.read_enum_variant(names, f) - } - - fn read_enum_struct_variant_field( - &mut self, - _f_name: &str, - f_idx: usize, - f: F, - ) -> Result - where - F: FnOnce(&mut Self) -> Result, - { - self.read_enum_variant_arg(f_idx, f) - } - - #[inline] - fn read_struct(&mut self, _s_name: &str, _len: usize, f: F) -> Result + fn read_enum_variant_arg(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -281,12 +210,15 @@ pub trait Decoder { } #[inline] - fn read_struct_field( - &mut self, - _f_name: &str, - _f_idx: usize, - f: F, - ) -> Result + fn read_struct(&mut self, f: F) -> Result + where + F: FnOnce(&mut Self) -> Result, + { + f(self) + } + + #[inline] + fn read_struct_field(&mut self, _f_name: &str, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -302,33 +234,19 @@ pub trait Decoder { } #[inline] - fn read_tuple_arg(&mut self, _a_idx: usize, f: F) -> Result + fn read_tuple_arg(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { f(self) } - fn read_tuple_struct(&mut self, _s_name: &str, len: usize, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - { - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg(&mut self, a_idx: usize, f: F) -> Result - where - F: FnOnce(&mut Self) -> Result, - { - self.read_tuple_arg(a_idx, f) - } - // Specialized types: fn read_option(&mut self, mut f: F) -> Result where F: FnMut(&mut Self, bool) -> Result, { - 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(&mut self, _idx: usize, f: F) -> Result + fn read_seq_elt(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -362,7 +280,7 @@ pub trait Decoder { } #[inline] - fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result + fn read_map_elt_key(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -370,7 +288,7 @@ pub trait Decoder { } #[inline] - fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result + fn read_map_elt_val(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, { @@ -550,8 +468,8 @@ impl> Decodable for Vec { default fn decode(d: &mut D) -> Result, 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 Decodable 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> Decodable for Option { impl, T2: Encodable> Encodable for Result { 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, T2: Encodable> Encodable for Result, T2: Decodable> Decodable for Result { fn decode(d: &mut D) -> Result, 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 1c6fad2ae8e1..2b547f8be922 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 { 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 { pub fn get_cmd_lint_options( matches: &getopts::Matches, error_format: ErrorOutputType, -) -> (Vec<(String, lint::Level)>, bool, Option) { + debugging_opts: &DebuggingOptions, +) -> (Vec<(String, lint::Level)>, bool, Option, Vec) { let mut lint_opts_with_position = vec![]; let mut describe_lints = false; @@ -1189,7 +1198,18 @@ 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"); + + (lint_opts, describe_lints, lint_cap, force_warns) } /// Parses the `--color` flag. @@ -1926,9 +1946,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 { @@ -2100,6 +2121,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { optimize: opt_level, debuginfo, lint_opts, + force_warns, lint_cap, describe_lints, output_types, @@ -2395,6 +2417,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, @@ -2427,46 +2450,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 DepTrackingHash for Option { + 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, - Option, - Option, - Option, - Option, - Option<(String, u64)>, - Option>, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, - Option, + WasiExecModel, + u32, + RelocModel, + CodeModel, + TlsModel, + InstrumentCoverage, CrateType, MergeFunctions, PanicStrategy, @@ -2484,21 +2493,12 @@ crate mod dep_tracking { TargetTriple, Edition, LinkerPluginLto, - Option, + SplitDebuginfo, SwitchWithOptPath, - Option, - Option, + SymbolManglingVersion, + SourceFileHashAlgorithm, TrimmedDefPaths, - ); - - impl_dep_tracking_hash_for_sortable_vec_of!( - String, - PathBuf, - (PathBuf, PathBuf), - CrateType, - NativeLib, - (String, lint::Level), - (String, u64) + Option, ); impl DepTrackingHash for (T1, T2) @@ -2530,6 +2530,16 @@ crate mod dep_tracking { } } + impl DepTrackingHash for Vec { + 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/options.rs b/compiler/rustc_session/src/options.rs index c9f95ed1224d..1946bfd78cc3 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 [TRACKED], + force_warns: Vec [TRACKED], describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec [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, 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 = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), + gcc_ld: Option = (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 777eea3f68d0..cc1e4bb198a3 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 1348b02b8780..86b8389a670e 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 95bb0ad7ba2e..bb4ac22d9c86 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 Decodable 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 Encodable 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 Decodable for DefId { default fn decode(d: &mut D) -> Result { - 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 Decodable for LocalDefId { rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId); impl HashStable for DefId { + #[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 HashStable for LocalDefId { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); } } impl HashStable 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 ToStableHashKey for DefId { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash { + hcx.def_path_hash(*self) + } +} + +impl ToStableHashKey for LocalDefId { + type KeyType = DefPathHash; + + #[inline] + fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash { + hcx.def_path_hash(self.to_def_id()) + } +} + +impl ToStableHashKey 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 8f3b8cc2d0ef..23efaf6f4f33 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 { @@ -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 39b7b36b853f..b4fe7c980de9 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -16,12 +16,10 @@ #![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)] #![feature(thread_local_const_init)] -#![feature(trusted_step)] #[macro_use] extern crate rustc_macros; @@ -42,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}; @@ -148,11 +146,12 @@ impl Hash for RealFileName { // an added assert statement impl Encodable 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))?; }) }) } @@ -163,8 +162,10 @@ impl Encodable 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))?; }) }), }) @@ -829,17 +830,17 @@ impl Default for Span { impl Encodable 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 Decodable for Span { default fn decode(s: &mut D) -> Result { - 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())) }) @@ -1236,12 +1237,12 @@ pub struct SourceFile { impl Encodable 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)?; @@ -1299,25 +1300,24 @@ impl Encodable 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 Decodable for SourceFile { fn decode(d: &mut D) -> Result { - 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 = 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 = d.read_struct_field("lines", |d| { let num_lines: u32 = Decodable::decode(d)?; let mut lines = Vec::with_capacity(num_lines as usize); @@ -1346,13 +1346,13 @@ impl Decodable for SourceFile { Ok(lines) })?; let multibyte_chars: Vec = - 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 = - 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 = - 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, @@ -1928,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; - 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 0dadd4192004..1d45cd172b30 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 46ef308cbf27..fb37c5e9c1ef 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 7d186c330ba3..025eaffcbd32 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.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/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index a70b374fc6d2..828f1ac0a798 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 000000000000..466c525531c1 --- /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(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(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(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 0cf2441d84e0..6e0e14037403 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 dae72e1b2c82..8e71ded3d1de 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 000000000000..ecb6bdc95ce0 --- /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 { + 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, + ) -> 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 c17c2961434e..305ea7d50e66 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 => "", } } @@ -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 a40de5ef18e0..cb8f6b9656c6 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,13 +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)] -#![feature(trusted_step)] 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 2218c6c6da7a..5682039b8651 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 758950bd3442..8a832546d095 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 e594ceec1b78..2187015b627d 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 a83de77dc2a9..cb6c06b37118 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/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 45c5c1a16e9c..8530db179d99 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -27,6 +27,7 @@ pub fn opts(os: &str) -> TargetOptions { 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 538c4ca86974..e7f7bb343d0c 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/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs new file mode 100644 index 000000000000..764cc735d75d --- /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 000000000000..a45da82eb403 --- /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 000000000000..6c9afdf35aef --- /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/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f1bd8ff237d0..0f2aaeb533a9 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 } diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index cc2578aa578e..6e3a241a86e0 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/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index 87e740de08e9..4c954a1e567c 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_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 3f24a33f7d57..ac2e0ebae327 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/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 163df26e9ffa..89ec211f2627 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>; +pub type OpaqueTypeMap<'tcx> = VecMap, 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>( &self, - def_id: DefId, + opaque_type_key: OpaqueTypeKey<'tcx>, opaque_defn: &OpaqueTypeDecl<'tcx>, mode: GenerateMemberConstraints, free_region_relations: &FRR, @@ -136,14 +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, ); 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>; @@ -370,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, ); @@ -383,11 +370,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// See `constrain_opaque_types` for documentation. fn constrain_opaque_type>( &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); @@ -426,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()); @@ -440,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; } @@ -454,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, @@ -484,7 +478,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return self.generate_member_constraint( concrete_ty, opaque_defn, - def_id, + opaque_type_key, first_own_region, ); } @@ -497,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 { @@ -517,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>> = 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), @@ -537,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, @@ -572,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 @@ -1007,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!( @@ -1029,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; } @@ -1078,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 8961cdaebf34..b1a938836b70 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 db396356d671..19c3385dd4cb 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/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8bbd2da53751..5c35b515f3d0 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/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d5e1bd3f9ea2..7ebef7f8883a 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_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 144c7281b67c..ebc7b0d0d99c 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 3f4c8a72f1d4..2d102127dd9d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,5 +1,4 @@ #![feature(min_specialization)] -#![feature(trusted_step)] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 92d7ea260030..70d85796d002 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) 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) 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 e5fcdcfa7431..33bc25accb31 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 de6336b254b3..01276495c185 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>( &mut self, _: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, a: T, b: T, ) -> RelateResult<'tcx, T> { diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 1dacbade1bd3..2e9bef15f900 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>>, + pub(super) opaque_types: RefCell, 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/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index a63aec07ad1c..652b82f1063c 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 71e222c560a0..6baa185406e2 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 e472add6e80f..032cc7ee2334 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 0528f8812f92..ee3ac3b62d9e 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 5197b620f90b..abe5d69a3b3c 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/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index aed36b12f3a2..bccc19774e0d 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 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_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 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 df2fb448b7d4..7fa5353d09b8 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 diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index c9bdcaa78f39..91eec10d5759 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::>()); + b.iter(|| data.iter().cloned().chain([1]).collect::>()); } #[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::>() - }); + b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::>()); } #[bench] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index eb91af8c61cb..13b42442dcf0 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1209,7 +1209,7 @@ impl Hasher for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl From for Box { - /// Converts a generic type `T` into a `Box` + /// Converts a `T` into a `Box` /// /// 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 5dda8c47688a..1a58ad51f78d 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 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 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, head: Option>>, tail: Option>>, len: usize, + marker: PhantomData<&'a mut Node>, } #[stable(feature = "collection_debug", since = "1.17.0")] impl 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() } } @@ -493,7 +506,7 @@ impl LinkedList { #[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 7d6fbf1c438b..5d03be35e466 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2416,7 +2416,6 @@ impl VecDeque { /// 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 VecDeque { /// 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 VecDeque { /// 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 where @@ -2476,7 +2474,6 @@ impl VecDeque { /// 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 VecDeque { /// 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 where F: FnMut(&'a T) -> Ordering, @@ -2530,7 +2527,6 @@ impl VecDeque { /// 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 VecDeque { /// 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 where @@ -2574,7 +2570,6 @@ impl VecDeque { /// # 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 VecDeque { /// 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\ - - \ + \ + \ \"Change\ @@ -119,7 +119,7 @@ crate fn render( {after_content}\
+ data-search-js=\"{static_root_path}search{suffix}.js\">\ \ {extra_scripts}\ \ @@ -161,7 +161,7 @@ crate fn render( } }, 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 { + Redirection

Redirecting to {url}...

diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 8676efd9fa8b..d80b2db00ac8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -200,8 +200,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, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 29b10fb8457b..2e940a31c2af 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, "

{}

(&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 812765d0b0de..7b87090fb071 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 { - 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 97765c36d930..a04e7c8a498d 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))) @@ -144,6 +143,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/string.rs b/library/alloc/src/string.rs index ec09595e357a..93f5fe45cd6a 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(&mut self, src: R) + where + R: RangeBounds, + { + 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(); - // 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; + 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); + } } - self.vec.set_len(len - shrunk_by); + len += count; + } + + unsafe { + 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> 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> for String { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_str", since = "1.20.0")] impl From for Box { - /// 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 for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_from_cow_str", since = "1.14.0")] impl<'a> From> 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 = 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> 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 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 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 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 for Cow<'a, str> { #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] impl From for Vec { - /// 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 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/vec/cow.rs b/library/alloc/src/vec/cow.rs index 73d15d306478..64943a273c9a 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> 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) -> Cow<'a, [T]> { Cow::Owned(v) } @@ -19,6 +31,12 @@ impl<'a, T: Clone> From> for Cow<'a, [T]> { #[stable(feature = "cow_from_vec_ref", since = "1.28.0")] impl<'a, T: Clone> From<&'a Vec> 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) -> 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 6fade636df9e..0efc4893c3c4 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -73,7 +73,7 @@ unsafe impl IsZero for Option> { // `Option` 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` works. -// While the documentation officially makes in UB to transmute from `None`, +// 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. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 105c60e7bf08..4a1d564e2ab8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -921,7 +921,7 @@ impl Vec { /// /// ``` /// 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 Vec { /// ``` /// #![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 Vec { /// /// ``` /// 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(); @@ -2586,7 +2586,7 @@ impl Vec { /// ``` /// 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 bbfcc68daeff..efa6868473e4 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 | +---------------------+ +/// | SourceIterMarker---fallback-+ | +---------------------+ /// +---------------------------------+ /// ``` pub(super) trait SpecFromIter { @@ -65,33 +62,3 @@ impl SpecFromIter> for Vec { vec } } - -impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec -where - I: Iterator, - 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 { - #[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 0a27b5b62ecf..bad765c7f51f 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/lib.rs b/library/alloc/tests/lib.rs index 25a83a0b0143..3143afa269dd 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/vec.rs b/library/alloc/tests/vec.rs index 36c81b497097..c203cdafecb0 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]); } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index e25d006d213c..37af3557fdd5 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -416,7 +416,7 @@ impl [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. @@ -437,7 +437,7 @@ impl [T; N] { /// ``` #[unstable(feature = "array_zip", issue = "80094")] pub fn zip(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 dcab2cd2d9db..80d0890551fd 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![ @@ -82,7 +81,7 @@ impl char { /// ]; /// /// assert_eq!( - /// decode_utf16(v.iter().cloned()) + /// decode_utf16(v) /// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) /// .collect::(), /// "𝄞mus�ic�" @@ -332,21 +331,16 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { 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/intrinsics.rs b/library/core/src/intrinsics.rs index 0034de9ad1bf..70ab27cbfac5 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::()` 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::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// * The region of memory beginning at `src` with a size of `count * - /// size_of::()` 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::()`) 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(dst: &mut Vec, src: &mut Vec) { - /// 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(src: *const T, dst: *mut T, count: usize); - - /// Copies `count * size_of::()` 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::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` 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::()`) 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(ptr: *const T, elts: usize) -> Vec { - /// 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(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(ptr: *const T) -> bool { !ptr.is_null() && ptr as usize % mem::align_of::() == 0 } +/// Copies `count * size_of::()` 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::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::()` 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::()`) 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(dst: &mut Vec, src: &mut Vec) { +/// 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(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + pub fn copy_nonoverlapping(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::()` 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::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` 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::()`) 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(ptr: *const T, elts: usize) -> Vec { +/// 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(src: *const T, dst: *mut T, count: usize) { + extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")] + fn copy(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::()` 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 92f82ae23250..beda8c32c6bd 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) -> ::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 FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Take {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Take -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 2f8f504d8fca..c95324c80ba6 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -434,7 +434,7 @@ impl ZipFmt() -> T { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_swap", issue = "83163")] -pub const fn swap(x: &mut T, y: &mut T) { +pub fn swap(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(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(dest: &mut T, src: T) -> T { +pub fn replace(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 77132cddca27..c47a2e8b05c4 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::(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. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 4c3f1fd16a0d..cfcc08b9adde 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::(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. diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6b9b435d47fe..dd9b9330aee2 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/ops/range.rs b/library/core/src/ops/range.rs index dbeb39121300..bb948376bc7c 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -674,10 +674,10 @@ pub enum Bound { Unbounded, } -#[unstable(feature = "bound_as_ref", issue = "80996")] impl Bound { /// Converts from `&Bound` 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 Bound { } } - /// Converts from `&mut Bound` to `Bound<&T>`. + /// Converts from `&mut Bound` 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 Bound { Unbounded => Unbounded, } } + + /// Maps a `Bound` to a `Bound` 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 = Unbounded; + /// + /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded); + /// ``` + #[inline] + #[unstable(feature = "bound_map", issue = "86026")] + pub fn map U>(self, f: F) -> Bound { + match self { + Unbounded => Unbounded, + Included(x) => Included(f(x)), + Excluded(x) => Excluded(f(x)), + } + } } impl Bound<&T> { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index cfb73ed0395e..4e7afca6a493 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -83,6 +83,8 @@ //! * [`ptr::NonNull`] //! * `#[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` and //! from `Some::(_)` to `T` (but transmuting `None::` to `T` diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 8f57db49496c..79753c1fb668 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 214d7c8bc156..6a6cee0911fe 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(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(x: *mut T, y: *mut T) { +pub(crate) unsafe fn swap_nonoverlapping_one(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(dst: *mut T, mut src: T) -> T { +pub unsafe fn replace(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(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(dst: *mut T, src: T) { +pub unsafe fn write(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(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 750279ac0dbd..a6424041542d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1002,9 +1002,8 @@ impl *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/slice/mod.rs b/library/core/src/slice/mod.rs index 3bcea4e6d25e..0e5c5ee726e5 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2100,9 +2100,11 @@ impl [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] { /// /// 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] { /// /// 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`]. /// diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs index b0dc99034644..b36d6f0d4040 100644 --- a/library/core/tests/any.rs +++ b/library/core/tests/any.rs @@ -114,3 +114,16 @@ fn any_unsized() { fn is_any() {} 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) -> &'static str { + type_name::() + } + + 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 ce7480ce2ee8..0ae625bdb68c 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 c16f54081ce0..51eca1e05d34 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 152fed803ecd..4acd059ab03d 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 000c15f72c88..797bfd957f90 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/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 5dcd1e6af365..d95ea6530c20 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 99a0c67fc11b..d32a3f1f8322 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/lib.rs b/library/proc_macro/src/lib.rs index 04a165e09f1e..26fbf50e2dfd 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))), @@ -32,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")] @@ -44,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}; @@ -1163,16 +1163,7 @@ impl Literal { // was 'c' or whether it was '\u{63}'. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn subspan>(&self, range: R) -> Option { - // HACK(eddyb) something akin to `Option::cloned`, but for `Bound<&T>`. - fn cloned_bound(bound: Bound<&T>) -> Bound { - 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/std/Cargo.toml b/library/std/Cargo.toml index 922c2c2bb8c4..415d874c7faa 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/io/impls.rs b/library/std/src/io/impls.rs index 6891bd8a6643..7a2a49ba7d70 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -87,6 +87,11 @@ impl Seek for &mut S { fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for &mut B { @@ -186,6 +191,11 @@ impl Seek for Box { fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } + + #[inline] + fn stream_position(&mut self) -> io::Result { + (**self).stream_position() + } } #[stable(feature = "rust1", since = "1.0.0")] impl BufRead for Box { diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index ba2b8b6955d6..5b8e83766f0e 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(); /// ``` /// /// `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 8e4c63762fd3..c4f21587457c 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))), diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index a8261709cea9..2b6d0d7d5daa 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -314,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 /// @@ -327,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. /// @@ -343,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 /// @@ -374,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]. @@ -396,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]. /// @@ -421,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 /// @@ -452,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]. /// @@ -485,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 @@ -682,9 +682,9 @@ impl Ipv4Addr { 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]. /// @@ -1267,22 +1267,59 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). + /// 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. /// - /// 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: + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [multicast address]: Ipv6Addr::is_multicast /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// // The unspecified and loopback addresses are unicast. + /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true); + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true); + /// + /// // 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); + /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] + #[inline] + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. + /// + /// 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: + /// + /// ```text + /// | 10 bits | 54 bits | 64 bits | /// +----------+-------------------------+----------------------------+ /// |1111111010| 0 | interface ID | /// +----------+-------------------------+----------------------------+ /// ``` + /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, + /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, + /// and those addresses will have link-local scope. /// - /// This method validates the format defined in the RFC and won't recognize addresses - /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses. - /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead. + /// 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 /// @@ -1291,86 +1328,17 @@ 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 loopback address (`::1`) does not actually have link-local scope. + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local_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(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()); + /// // 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.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, ..]) - } - - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). - /// - /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], - /// i.e. addresses with the following format: - /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111010| arbitratry value | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// - /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be - /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not. - /// If you need a strict validation fully compliant with the RFC, use - /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// ``` - /// - /// # 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] @@ -1378,7 +1346,7 @@ impl Ipv6Addr { (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 @@ -1407,7 +1375,7 @@ 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. /// @@ -1477,7 +1445,7 @@ impl Ipv6Addr { #[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() @@ -1520,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]. /// @@ -1577,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 ef0d4edc4347..05f8dea0b7cb 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/panicking.rs b/library/std/src/panicking.rs index 02957e75a740..0b9c9fb479f5 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) + '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) + '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::() { Some(s) => &s[..], - None => "Box", + None => "Box", }, }; 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 9c5615f58c43..ede147aca12e 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 { + /// Creates a boxed [`Path`] from a reference. + /// + /// This will allocate and clone `path` to it. fn from(path: &Path) -> Box { let boxed: Box = path.inner.into(); let rw = Box::into_raw(boxed) as *mut Path; @@ -1429,6 +1432,9 @@ impl From<&Path> for Box { #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { + /// 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 { match cow { @@ -1471,6 +1477,9 @@ impl Clone for Box { #[stable(feature = "rust1", since = "1.0.0")] impl> 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 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 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> 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 1b4facdd049b..12d52cc8e0b2 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/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 9d521ab14cbf..0d00f74eaa1e 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 { - inner: Box, + inner: sys::MovableRWLock, poison: poison::Flag, data: UnsafeCell, } @@ -130,7 +128,7 @@ impl RwLock { #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> RwLock { RwLock { - inner: box sys::RWLock::new(), + inner: sys::MovableRWLock::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), } @@ -376,24 +374,8 @@ impl RwLock { 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. @@ -424,14 +406,6 @@ impl RwLock { } } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock { - 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 fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 06442e925f4c..d2058180121d 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, } +pub type MovableRWLock = Box; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 0c96e3fcddcd..2d038b518965 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>, } +pub type MovableRWLock = Box; + // 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/mod.rs b/library/std/src/sys/unix/mod.rs index 57d91441b6fc..ca9cc8ca7ba3 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/os.rs b/library/std/src/sys/unix/os.rs index bbc4691d963c..41ca9762390c 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/rwlock.rs b/library/std/src/sys/unix/rwlock.rs index d97d9d712fc9..b1faf12c2261 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; + 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 6982b2b155fa..8438adeb5b53 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, } +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 06442e925f4c..64eaa2fc482d 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, } +pub type MovableRWLock = RWLock; + enum State { Unlocked, Reading(usize), diff --git a/library/std/src/sys/windows/rwlock.rs b/library/std/src/sys/windows/rwlock.rs index a769326352c4..b7a5b1e7accd 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, } +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 3705d641a1be..07ec20f4dc61 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. +/// An OS-based reader-writer lock, meant for use in static variables. /// -/// 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 implement poisoning. +/// +/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not +/// implement `Drop` to cleanup resources. +pub struct StaticRWLock(imp::RWLock); -impl RWLock { - /// 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()) +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. /// - /// Behavior is undefined if the rwlock has been moved between this and any - /// previous method call. + /// The lock is automatically unlocked when the returned guard is dropped. #[inline] - pub unsafe fn read(&self) { - self.0.read() + 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 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` 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 MovableRWLock { + /// Creates a new reader-writer lock for use. + 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. + #[inline] + 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 89addae07894..899cf6841ee1 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 index 37d6e1886369..1e05dffbeeb8 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 37d6e1886369ea0176356286dc7fbd42ee5aa79c +Subproject commit 1e05dffbeeb80ba61bf59cc63b222d538d7825ed diff --git a/library/term/src/lib.rs b/library/term/src/lib.rs index 2116b433fce3..943b276a220c 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/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 5e41d6d96923..e17fc08a9ae9 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -169,7 +169,11 @@ impl PrettyFormatter { 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 6f46f7255a47..a2c223c494c2 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -158,7 +158,11 @@ impl TerseFormatter { 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 bda5ed888d7e..3da4d434f48f 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/tests.rs b/library/test/src/tests.rs index 6a3f31b74ea5..5a4a540b04eb 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -61,6 +61,10 @@ fn one_ignored_one_unignored_test() -> Vec { 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 { 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 { 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 c5d91f653b35..63907c71ea7c 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/build.rs b/library/unwind/build.rs index 96df3fc5ac4c..0529d24a2740 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -20,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"); diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 4b98abfb308b..ac8bbfe102df 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") { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index cba17c8e6085..e4396d53016e 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 149a899cef7a..7c7f162b82c0 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 f39e89a9d01f..bc499fdba599 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 2676b3bf8e00..112a6ea93986 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 aee3c8324bc1..71ed0af4a7c0 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/lib.rs b/src/bootstrap/lib.rs index 2960dd3df6bf..347236c655a0 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 { + 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 { 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/native.rs b/src/bootstrap/native.rs index bde0a96f0301..449fdb87b022 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 16b3c6419e83..fe4666effe62 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; @@ -1131,19 +1131,6 @@ struct Compiletest { compare_mode: Option<&'static str>, } -impl Compiletest { - fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec) { - 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 = (); @@ -1280,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) { @@ -1289,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()); @@ -1486,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) { @@ -1516,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 64e4be6863a6..9d75ad0918a7 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -263,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 b4421a82714f..112979b0bebc 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, 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 1f8f9fc518ac..cd0f01faa1bf 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/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index fd6dc563a0ec..66afe84be4a2 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/run.sh b/src/ci/docker/run.sh index c2ff62e74816..3a47076722c3 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 343091cb779f..e704071e401b 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 35f80a935c69..c5e225c7cd17 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/doc/reference b/src/doc/reference index 9c68af3ce6cc..8f598e2af6c2 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 9c68af3ce6ccca2395e1868addef26a0542e9ddd +Subproject commit 8f598e2af6c25b4a7ee88ef6a8196d9b8ea50ca8 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 50de7f0682ad..c8da5bfd1c7c 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 50de7f0682adc5d95ce858fe6318d19b4b951553 +Subproject commit c8da5bfd1c7c71d90ef1646f5e0a9f6609d5c78a diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b269aab98142..bc1873b6836b 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 077c322bd773..05384117ac17 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 9236cb10e2f2..3225e95941cf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -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 000000000000..9aa5db26f917 --- /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 8e3c62281895..cb7b85655b5a 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/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 28b81a40265d..e9b15666bb31 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 000000000000..0a205be096c0 --- /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 effae5d29994..000000000000 --- 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/more-qualified-paths.md b/src/doc/unstable-book/src/language-features/more-qualified-paths.md new file mode 100644 index 000000000000..857af577a6cf --- /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 ::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 5503b3b4b32f..03dbf4fb617f 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 2f7233685db5..8647db5a45dc 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 030892a432b3..89280149a035 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,4 +149,57 @@ ... + + + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + {tag(),en} + + + variant0 + variant1 + variant2 + variant3 + variant4 + variant5 + variant6 + variant7 + variant8 + variant9 + variant10 + variant11 + variant12 + variant13 + variant14 + variant15 + + + + + + + + {"$T4",sb}({dataful_variant}) + {discriminant,en} + + dataful_variant + + {"$T4",sb} + + + diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 9c3c26f59783..17667770520c 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -14,14 +14,6 @@ - - None - Some({__0}) - - __0 - - - None Some({($T1 *)this}) @@ -30,15 +22,6 @@ - - Ok({__0}) - Err({(*($T2*) &__0)}) - - __0 - (*($T2*) &__0) - - - {(void*) pointer} diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 35ff57f85a56..a3f63ea1046e 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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` + default.take(); + } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index a14eefaf5714..111827aacdff 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 = if let ast::ItemKind::MacroDef(ref def) = def.kind { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 231f13adeb68..d1c18821ea64 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -445,11 +445,15 @@ impl Clean 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, + }, }, ), }; @@ -487,12 +491,15 @@ impl Clean 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() + }), }, ), }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index de88e249b67f..6a7c3f8caa49 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, { - let mut prev_kind: Option = 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 = None; - let mut contents: Option = 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 = vec![]; let mut doc_line = 0; - fn update_need_backline(doc_strings: &mut Vec, frag: &DocFragment) { + fn update_need_backline(doc_strings: &mut Vec) { 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, }, } @@ -1768,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 { Self::all_impls(tcx).get(self).expect("missing impl for primitive type") } @@ -1861,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 2c31a502565a..706a56fbcbfe 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; @@ -451,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; @@ -543,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 6e1fdf67a652..1b5a00dde59b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -349,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); @@ -635,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 3dd13a8f1707..c3d9c4ea7f25 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 3a4d39e1d7f7..88e2f6048e9c 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 3c1d03a78f1c..918a5cb50943 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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, "", "../".repeat(len), - prim.to_url_str() + prim.as_sym() )?; needs_termination = true; } @@ -603,7 +613,7 @@ fn primitive_link( f, "", 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!( diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ec04c94dc11f..d2d1757b9009 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -87,7 +87,7 @@ crate fn render( {sidebar}\ \