diff options
436 files changed, 5754 insertions, 3787 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md index ffab883987c..c0e90824a71 100644 --- a/.github/ISSUE_TEMPLATE/regression.md +++ b/.github/ISSUE_TEMPLATE/regression.md @@ -1,7 +1,7 @@ --- name: Regression about: Report something that unexpectedly changed between Rust versions. -labels: C-bug regression-untriaged +labels: C-bug, regression-untriaged --- <!-- Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to. diff --git a/Cargo.lock b/Cargo.lock index b3fa511839b..a55ef7b6143 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -583,6 +583,19 @@ name = "clippy-mini-macro-test" version = "0.2.0" [[package]] +name = "clippy_dev" +version = "0.0.1" +dependencies = [ + "bytecount", + "clap", + "itertools 0.9.0", + "opener", + "regex", + "shell-escape", + "walkdir", +] + +[[package]] name = "clippy_lints" version = "0.1.53" dependencies = [ diff --git a/Cargo.toml b/Cargo.toml index 02011357eac..327afe35c2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "src/rustdoc-json-types", "src/tools/cargotest", "src/tools/clippy", + "src/tools/clippy/clippy_dev", "src/tools/compiletest", "src/tools/error_index_generator", "src/tools/linkchecker", diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 10d48a55bb5..15f46ef5d7f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -688,16 +688,12 @@ pub enum NonterminalKind { Item, Block, Stmt, - Pat2015 { - /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the - /// edition of the span. This is used for diagnostics. - inferred: bool, - }, - Pat2021 { - /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the + PatParam { + /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the /// edition of the span. This is used for diagnostics. inferred: bool, }, + PatWithOr, Expr, Ty, Ident, @@ -722,12 +718,11 @@ impl NonterminalKind { sym::stmt => NonterminalKind::Stmt, sym::pat => match edition() { Edition::Edition2015 | Edition::Edition2018 => { - NonterminalKind::Pat2015 { inferred: true } + NonterminalKind::PatParam { inferred: true } } - Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true }, + Edition::Edition2021 => NonterminalKind::PatWithOr, }, - sym::pat2015 => NonterminalKind::Pat2015 { inferred: false }, - sym::pat2021 => NonterminalKind::Pat2021 { inferred: false }, + sym::pat_param => NonterminalKind::PatParam { inferred: false }, sym::expr => NonterminalKind::Expr, sym::ty => NonterminalKind::Ty, sym::ident => NonterminalKind::Ident, @@ -745,10 +740,8 @@ impl NonterminalKind { NonterminalKind::Item => sym::item, NonterminalKind::Block => sym::block, NonterminalKind::Stmt => sym::stmt, - NonterminalKind::Pat2015 { inferred: false } => sym::pat2015, - NonterminalKind::Pat2021 { inferred: false } => sym::pat2021, - NonterminalKind::Pat2015 { inferred: true } - | NonterminalKind::Pat2021 { inferred: true } => sym::pat, + NonterminalKind::PatParam { inferred: false } => sym::pat_param, + NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat, NonterminalKind::Expr => sym::expr, NonterminalKind::Ty => sym::ty, NonterminalKind::Ident => sym::ident, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 75dfe951c94..bf70a41fd79 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -338,7 +338,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut generic_args = vec![]; for (idx, arg) in args.into_iter().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_hir_id_owner.last().unwrap().0; + let parent_def_id = self.current_hir_id_owner.0; let node_id = self.resolver.next_node_id(); // Add a definition for the in-band const def. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 44056df4ab9..e7c566e586c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -165,7 +165,7 @@ struct LoweringContext<'a, 'hir: 'a> { type_def_lifetime_params: DefIdMap<usize>, - current_hir_id_owner: Vec<(LocalDefId, u32)>, + current_hir_id_owner: (LocalDefId, u32), item_local_id_counters: NodeMap<u32>, node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>, @@ -321,7 +321,7 @@ pub fn lower_crate<'a, 'hir>( anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, type_def_lifetime_params: Default::default(), current_module: CRATE_DEF_ID, - current_hir_id_owner: vec![(CRATE_DEF_ID, 0)], + current_hir_id_owner: (CRATE_DEF_ID, 0), item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), generator_kind: None, @@ -594,9 +594,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .insert(owner, HIR_ID_COUNTER_LOCKED) .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner)); let def_id = self.resolver.local_def_id(owner); - self.current_hir_id_owner.push((def_id, counter)); + let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter)); let ret = f(self); - let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap(); + let (new_def_id, new_counter) = + std::mem::replace(&mut self.current_hir_id_owner, old_owner); debug_assert!(def_id == new_def_id); debug_assert!(new_counter >= counter); @@ -614,8 +615,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// properly. Calling the method twice with the same `NodeId` is fine though. fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { self.lower_node_id_generic(ast_node_id, |this| { - let &mut (owner, ref mut local_id_counter) = - this.current_hir_id_owner.last_mut().unwrap(); + let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner; let local_id = *local_id_counter; *local_id_counter += 1; hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) } @@ -868,10 +868,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // wouldn't have been added yet. let generics = this.lower_generics_mut( generics, - ImplTraitContext::Universal( - &mut params, - this.current_hir_id_owner.last().unwrap().0, - ), + ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0), ); let res = f(this, &mut params); (params, (generics, res)) @@ -1077,7 +1074,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } AssocTyConstraintKind::Bound { ref bounds } => { let mut capturable_lifetimes; - let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0; + let mut parent_def_id = self.current_hir_id_owner.0; // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { // We are in the return position: @@ -1198,7 +1195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Construct a AnonConst where the expr is the "ty"'s path. - let parent_def_id = self.current_hir_id_owner.last().unwrap().0; + let parent_def_id = self.current_hir_id_owner.0; let node_id = self.resolver.next_node_id(); // Add a definition for the in-band const def. @@ -1814,10 +1811,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some((_, ibty)) = &mut in_band_ty_params { this.lower_ty_direct( ¶m.ty, - ImplTraitContext::Universal( - ibty, - this.current_hir_id_owner.last().unwrap().0, - ), + ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0), ) } else { this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 79f35ad5819..5a4e7fd9d07 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -16,9 +16,19 @@ pub fn expand_deriving_eq( push: &mut dyn FnMut(Annotatable), ) { let inline = cx.meta_word(span, sym::inline); + let no_coverage_ident = + rustc_ast::attr::mk_nested_word_item(Ident::new(sym::no_coverage, span)); + let no_coverage_feature = + rustc_ast::attr::mk_list_item(Ident::new(sym::feature, span), vec![no_coverage_ident]); + let no_coverage = cx.meta_word(span, sym::no_coverage); let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); - let attrs = vec![cx.attribute(inline), cx.attribute(doc)]; + let attrs = vec![ + cx.attribute(inline), + cx.attribute(no_coverage_feature), + cx.attribute(no_coverage), + cx.attribute(doc), + ]; let trait_def = TraitDef { span, attributes: Vec::new(), diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 2ac516381cf..4d45e36c956 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -80,3 +80,10 @@ jobs: with: name: cg_clif-${{ runner.os }} path: cg_clif.tar.xz + + - name: Upload prebuilt cg_clif (cross compile) + if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + uses: actions/upload-artifact@v2 + with: + name: cg_clif-${{ runner.os }}-cross-x86_64-mingw + path: cg_clif.tar.xz diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index 0cd576e160f..9009a532c54 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,6 +1,6 @@ { // source for rustc_* is not included in the rust-src component; disable the errors about this - "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "macro-error"], + "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"], "rust-analyzer.assist.importMergeBehavior": "last", "rust-analyzer.cargo.runBuildScripts": true, "rust-analyzer.linkedProjects": [ diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index dc1cd336e15..e6792def567 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -39,16 +39,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "byteorder", "cranelift-bforest", @@ -65,8 +65,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -74,18 +74,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" [[package]] name = "cranelift-entity" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" [[package]] name = "cranelift-frontend" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "cranelift-codegen", "log", @@ -95,8 +95,8 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "anyhow", "cranelift-codegen", @@ -113,8 +113,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "anyhow", "cranelift-codegen", @@ -125,8 +125,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "cranelift-codegen", "target-lexicon", @@ -134,8 +134,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.72.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" +version = "0.73.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" dependencies = [ "anyhow", "cranelift-codegen", @@ -306,6 +306,7 @@ dependencies = [ "cranelift-frontend", "cranelift-jit", "cranelift-module", + "cranelift-native", "cranelift-object", "gimli", "indexmap", @@ -334,9 +335,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95" +checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834" [[package]] name = "thiserror" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 60946ab2808..2789207c655 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -9,12 +9,13 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x64"] } +cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] } cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } +cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } -target-lexicon = "0.11.0" +target-lexicon = "0.12.0" gimli = { version = "0.23.0", default-features = false, features = ["write"]} object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -28,6 +29,7 @@ smallvec = "1.6.1" #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" } #cranelift-module = { path = "../wasmtime/cranelift/module" } +#cranelift-native = { path = ../wasmtime/cranelift/native" } #cranelift-jit = { path = "../wasmtime/cranelift/jit" } #cranelift-object = { path = "../wasmtime/cranelift/object" } diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index ffe1d9a1e65..08f9373be62 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -44,9 +44,10 @@ This will build your project with rustc_codegen_cranelift instead of the usual L For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md). -## Env vars +## Configuration -See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift. +See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all +configuration options. ## Not yet supported diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 09c5d7590ab..e058a972ead 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.39" +version = "0.1.40" dependencies = [ "rustc-std-workspace-core", ] @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.91" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" dependencies = [ "rustc-std-workspace-core", ] @@ -167,6 +167,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ + "alloc", "cfg-if", "compiler_builtins", "core", @@ -242,11 +243,23 @@ dependencies = [ "panic_abort", "panic_unwind", "rustc-demangle", + "std_detect", "unwind", "wasi", ] [[package]] +name = "std_detect" +version = "0.1.5" +dependencies = [ + "cfg-if", + "compiler_builtins", + "libc", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] name = "sysroot" version = "0.0.0" dependencies = [ diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index c90205db0fb..f7fcef10774 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -32,7 +32,7 @@ popd git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned" pushd compiler-builtins git checkout -- . -git checkout 0.1.39 +git checkout 0.1.40 git apply ../../crate_patches/000*-compiler-builtins-*.patch popd diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch index e14768910a9..b4acc4f5b73 100644 --- a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch +++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch @@ -17,8 +17,8 @@ index 06054c8..3bea17b 100644 fn wrapping_shr(self, other: u32) -> Self; - fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); - fn aborting_div(self, other: Self) -> Self; - fn aborting_rem(self, other: Self) -> Self; + fn leading_zeros(self) -> u32; + } @@ -209,10 +208,6 @@ macro_rules! int_impl_common { <Self>::wrapping_shr(self, other) } diff --git a/compiler/rustc_codegen_cranelift/docs/env_vars.md b/compiler/rustc_codegen_cranelift/docs/env_vars.md deleted file mode 100644 index f7fde1b4f3a..00000000000 --- a/compiler/rustc_codegen_cranelift/docs/env_vars.md +++ /dev/null @@ -1,15 +0,0 @@ -# List of env vars recognized by cg_clif - -<dl> - <dt>CG_CLIF_JIT_ARGS</dt> - <dd>When JIT mode is enable pass these arguments to the program.</dd> - <dt>CG_CLIF_INCR_CACHE_DISABLED</dt> - <dd>Don't cache object files in the incremental cache. Useful during development of cg_clif - to make it possible to use incremental mode for all analyses performed by rustc without caching - object files when their content should have been changed by a change to cg_clif.</dd> - <dt>CG_CLIF_DISPLAY_CG_TIME</dt> - <dd>If "1", display the time it took to perform codegen for a crate.</dd> - <dt>CG_CLIF_ENABLE_VERIFIER</dt> - <dd>Enable the Cranelift ir verifier for all compilation passes. If not set it will only run once - before passing the clif ir to Cranelift for compilation.</dt> -</dl> diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index ea37ca98b59..6570f2bf9f2 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -11,6 +11,22 @@ unsafe extern "C" fn my_puts(s: *const i8) { puts(s); } +macro_rules! assert { + ($e:expr) => { + if !$e { + panic(stringify!(! $e)); + } + }; +} + +macro_rules! assert_eq { + ($l:expr, $r: expr) => { + if $l != $r { + panic(stringify!($l != $r)); + } + } +} + #[lang = "termination"] trait Termination { fn report(self) -> i32; @@ -20,8 +36,9 @@ impl Termination for () { fn report(self) -> i32 { unsafe { NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44 - *NUM_REF as i32 + assert_eq!(*NUM_REF as i32, 44); } + 0 } } @@ -82,29 +99,12 @@ fn start<T: Termination + 'static>( unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); } } - main().report(); - 0 + main().report() as isize } static mut NUM: u8 = 6 * 7; static NUM_REF: &'static u8 = unsafe { &NUM }; -macro_rules! assert { - ($e:expr) => { - if !$e { - panic(stringify!(! $e)); - } - }; -} - -macro_rules! assert_eq { - ($l:expr, $r: expr) => { - if $l != $r { - panic(stringify!($l != $r)); - } - } -} - struct Unique<T: ?Sized> { pointer: *const T, _marker: PhantomData<T>, @@ -296,6 +296,11 @@ fn main() { unsafe { global_asm_test(); } + + // Both statics have a reference that points to the same anonymous allocation. + static REF1: &u8 = &42; + static REF2: &u8 = REF1; + assert_eq!(*REF1, *REF2); } #[cfg(all(not(jit), target_os = "linux"))] diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 015bbdfed46..77ba72df8ef 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -48,6 +48,8 @@ fn main() { assert_eq!(2.3f32.copysign(-1.0), -2.3f32); println!("{}", 2.3f32.powf(2.0)); + assert_eq!(i64::MAX.checked_mul(2), None); + assert_eq!(-128i8, (-128i8).saturating_sub(1)); assert_eq!(127i8, 127i8.saturating_sub(-128)); assert_eq!(-128i8, (-128i8).saturating_add(-128)); @@ -84,6 +86,7 @@ fn main() { assert_eq!(houndred_i128 as f64, 100.0); assert_eq!(houndred_f32 as i128, 100); assert_eq!(houndred_f64 as i128, 100); + assert_eq!(1u128.rotate_left(2), 4); // Test signed 128bit comparing let max = usize::MAX as i128; diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 2917fc7ee39..5442e3345aa 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-03-29" +channel = "nightly-2021-04-28" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh index 7971f620df1..3f98d77d76c 100644 --- a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh +++ b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh @@ -5,7 +5,7 @@ set -e export CG_CLIF_DISPLAY_CG_TIME=1 -export CG_CLIF_INCR_CACHE_DISABLED=1 +export CG_CLIF_DISABLE_INCR_CACHE=1 export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE} diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index e8bedf625f7..4821a07ac5d 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -45,7 +45,7 @@ index d95b5b7f17f..00b6f0e3635 100644 [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] } ++compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] } [dev-dependencies] rand = "0.7" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index fbc3feceec7..347fb40e6f9 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -38,6 +38,7 @@ rm src/test/ui/threads-sendsync/task-stderr.rs rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs rm src/test/ui/drop/drop-trait-enum.rs rm src/test/ui/numbers-arithmetic/issue-8460.rs +rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations rm src/test/ui/init-large-type.rs # same @@ -47,6 +48,7 @@ rm src/test/ui/issues/issue-51947.rs # same rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants rm src/test/ui/mir/mir_raw_fat_ptr.rs # same +rm src/test/ui/consts/issue-33537.rs # same rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same rm src/test/ui/generator/size-moved-locals.rs # same @@ -56,11 +58,13 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n rm src/test/incremental/hashes/inline_asm.rs # inline asm rm src/test/incremental/issue-72386.rs # same -rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind rm src/test/incremental/issue-49482.rs # same rm src/test/incremental/issue-54059.rs # same rm src/test/incremental/lto.rs # requires lto +rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/ +rm -r src/test/run-make/unstable-flag-required # same + rm src/test/pretty/asm.rs # inline asm rm src/test/pretty/raw-str-nonexpr.rs # same @@ -68,6 +72,7 @@ rm -r src/test/run-pass-valgrind/unsized-locals rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning rm src/test/ui/json-bom-plus-crlf.rs # same +rm src/test/ui/match/issue-82392.rs # differing error rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 0e7829eaa26..54c8fb0e7b8 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -63,16 +63,16 @@ pub(crate) fn import_function<'tcx>( module: &mut dyn Module, inst: Instance<'tcx>, ) -> FuncId { - let name = tcx.symbol_name(inst).name.to_string(); + let name = tcx.symbol_name(inst).name; let sig = get_function_sig(tcx, module.isa().triple(), inst); - module.declare_function(&name, Linkage::Import, &sig).unwrap() + module.declare_function(name, Linkage::Import, &sig).unwrap() } impl<'tcx> FunctionCx<'_, '_, 'tcx> { /// Instance must be monomorphized pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef { - let func_id = import_function(self.tcx, self.cx.module, inst); - let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func); + let func_id = import_function(self.tcx, self.module, inst); + let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); if self.clif_comments.enabled() { self.add_comment(func_ref, format!("{:?}", inst)); @@ -89,8 +89,8 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { args: &[Value], ) -> &[Value] { let sig = Signature { params, returns, call_conv: CallConv::triple_default(self.triple()) }; - let func_id = self.cx.module.declare_function(&name, Linkage::Import, &sig).unwrap(); - let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func); + let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap(); + let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); let call_inst = self.bcx.ins().call(func_ref, args); if self.clif_comments.enabled() { self.add_comment(call_inst, format!("easy_call {}", name)); @@ -295,7 +295,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ pub(crate) fn codegen_terminator_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span, - current_block: Block, func: &Operand<'tcx>, args: &[Operand<'tcx>], destination: Option<(Place<'tcx>, BasicBlock)>, @@ -357,7 +356,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)) .unwrap_or(false); if is_cold { - fx.cold_blocks.insert(current_block); + // FIXME Mark current_block block as cold once Cranelift supports it } // Unpack arguments tuple for closures diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index f60645a9f97..a09e3257786 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::sym; pub(crate) fn codegen( tcx: TyCtxt<'_>, module: &mut impl Module, - unwind_context: &mut UnwindContext<'_>, + unwind_context: &mut UnwindContext, ) -> bool { let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| { use rustc_middle::middle::dependency_format::Linkage; @@ -29,7 +29,7 @@ pub(crate) fn codegen( fn codegen_inner( module: &mut impl Module, - unwind_context: &mut UnwindContext<'_>, + unwind_context: &mut UnwindContext, kind: AllocatorKind, ) { let usize_ty = module.target_config().pointer_type(); diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs index eb7927fc4ad..05c06bac27d 100644 --- a/compiler/rustc_codegen_cranelift/src/backend.rs +++ b/compiler/rustc_codegen_cranelift/src/backend.rs @@ -5,23 +5,23 @@ use std::convert::{TryFrom, TryInto}; use rustc_data_structures::fx::FxHashMap; use rustc_session::Session; +use cranelift_codegen::isa::TargetIsa; use cranelift_module::FuncId; +use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct}; use object::write::*; use object::{RelocationEncoding, SectionKind, SymbolFlags}; -use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct}; - use gimli::SectionId; use crate::debuginfo::{DebugReloc, DebugRelocName}; pub(crate) trait WriteMetadata { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool); + fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>); } impl WriteMetadata for object::write::Object { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) { + fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) { let segment = self.segment_name(object::write::StandardSegment::Data).to_vec(); let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data); let offset = self.append_section_data(section_id, &data, 1); @@ -113,7 +113,7 @@ impl WriteDebugInfo for ObjectProduct { } pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> { - let triple = crate::build_isa(sess).triple().clone(); + let triple = crate::target_triple(sess); let binary_format = match triple.binary_format { target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, @@ -141,13 +141,9 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object metadata_object.write().unwrap() } -pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule { - let mut builder = ObjectBuilder::new( - crate::build_isa(sess), - name + ".o", - cranelift_module::default_libcall_names(), - ) - .unwrap(); +pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule { + let mut builder = + ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections // can easily double the amount of time necessary to perform linking. diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index b34a29c25b9..3ec5c14ff17 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -6,9 +6,14 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::FnAbiExt; use rustc_target::abi::call::FnAbi; +use crate::constant::ConstantCx; use crate::prelude::*; -pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) { +pub(crate) fn codegen_fn<'tcx>( + cx: &mut crate::CodegenCx<'tcx>, + module: &mut dyn Module, + instance: Instance<'tcx>, +) { let tcx = cx.tcx; let _inst_guard = @@ -18,9 +23,9 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In let mir = tcx.instance_mir(instance.def); // Declare function - let name = tcx.symbol_name(instance).name.to_string(); - let sig = get_function_sig(tcx, cx.module.isa().triple(), instance); - let func_id = cx.module.declare_function(&name, Linkage::Local, &sig).unwrap(); + let symbol_name = tcx.symbol_name(instance); + let sig = get_function_sig(tcx, module.isa().triple(), instance); + let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap(); cx.cached_context.clear(); @@ -39,15 +44,19 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect(); // Make FunctionCx - let pointer_type = cx.module.target_config().pointer_type(); + let pointer_type = module.target_config().pointer_type(); let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance); let mut fx = FunctionCx { cx, + module, tcx, pointer_type, + vtables: FxHashMap::default(), + constants_cx: ConstantCx::new(), instance, + symbol_name, mir, fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])), @@ -55,7 +64,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In block_map, local_map: IndexVec::with_capacity(mir.local_decls.len()), caller_location: None, // set by `codegen_fn_prelude` - cold_blocks: EntitySet::new(), clif_comments, source_info_set: indexmap::IndexSet::new(), @@ -90,7 +98,8 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In let mut clif_comments = fx.clif_comments; let source_info_set = fx.source_info_set; let local_map = fx.local_map; - let cold_blocks = fx.cold_blocks; + + fx.constants_cx.finalize(fx.tcx, &mut *fx.module); // Store function in context let context = &mut cx.cached_context; @@ -103,21 +112,15 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In // Perform rust specific optimizations tcx.sess.time("optimize clif ir", || { - crate::optimize::optimize_function( - tcx, - instance, - context, - &cold_blocks, - &mut clif_comments, - ); + crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments); }); // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128` // instruction, which doesn't have an encoding. context.compute_cfg(); context.compute_domtree(); - context.eliminate_unreachable_code(cx.module.isa()).unwrap(); - context.dce(cx.module.isa()).unwrap(); + context.eliminate_unreachable_code(module.isa()).unwrap(); + context.dce(module.isa()).unwrap(); // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't // invalidate it when it would change. context.domtree.clear(); @@ -125,7 +128,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In context.want_disasm = crate::pretty_clif::should_write_ir(tcx); // Define function - let module = &mut cx.module; tcx.sess.time("define function", || { module .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {}) @@ -136,7 +138,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In crate::pretty_clif::write_clif_file( tcx, "opt", - Some(cx.module.isa()), + Some(module.isa()), instance, &context, &clif_comments, @@ -145,13 +147,13 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm { crate::pretty_clif::write_ir_file( tcx, - &format!("{}.vcode", tcx.symbol_name(instance).name), + || format!("{}.vcode", tcx.symbol_name(instance).name), |file| file.write_all(disasm.as_bytes()), ) } // Define debuginfo for function - let isa = cx.module.isa(); + let isa = module.isa(); let debug_context = &mut cx.debug_context; let unwind_context = &mut cx.unwind_context; tcx.sess.time("generate debug info", || { @@ -159,7 +161,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In debug_context.define_function( instance, func_id, - &name, + symbol_name.name, isa, context, &source_info_set, @@ -205,9 +207,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { // Unwinding after panicking is not supported continue; - // FIXME once unwinding is supported uncomment next lines - // // Unwinding is unlikely to happen, so mark cleanup block's as cold. - // fx.cold_blocks.insert(block); + // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do + // so for cleanup blocks. } fx.bcx.ins().nop(); @@ -262,7 +263,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { let target = fx.get_block(*target); let failure = fx.bcx.create_block(); - fx.cold_blocks.insert(failure); + // FIXME Mark failure block as cold once Cranelift supports it if *expected { fx.bcx.ins().brz(cond, failure, &[]); @@ -355,14 +356,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { from_hir_call: _, } => { fx.tcx.sess.time("codegen call", || { - crate::abi::codegen_terminator_call( - fx, - *fn_span, - block, - func, - args, - *destination, - ) + crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination) }); } TerminatorKind::InlineAsm { @@ -664,7 +658,7 @@ fn codegen_stmt<'tcx>( // FIXME use emit_small_memset where possible let addr = lval.to_ptr().get_addr(fx); let val = operand.load_scalar(fx); - fx.bcx.call_memset(fx.cx.module.target_config(), addr, val, times); + fx.bcx.call_memset(fx.module.target_config(), addr, val, times); } else { let loop_block = fx.bcx.create_block(); let loop_block2 = fx.bcx.create_block(); @@ -750,85 +744,15 @@ fn codegen_stmt<'tcx>( | StatementKind::AscribeUserType(..) => {} StatementKind::LlvmInlineAsm(asm) => { - use rustc_span::symbol::Symbol; - let LlvmInlineAsm { asm, outputs, inputs } = &**asm; - let rustc_hir::LlvmInlineAsmInner { - asm: asm_code, // Name - outputs: output_names, // Vec<LlvmInlineAsmOutput> - inputs: input_names, // Vec<Name> - clobbers, // Vec<Name> - volatile, // bool - alignstack, // bool - dialect: _, - asm_str_style: _, - } = asm; - match asm_code.as_str().trim() { + match asm.asm.asm.as_str().trim() { "" => { // Black box } - "mov %rbx, %rsi\n cpuid\n xchg %rbx, %rsi" => { - assert_eq!(input_names, &[Symbol::intern("{eax}"), Symbol::intern("{ecx}")]); - assert_eq!(output_names.len(), 4); - for (i, c) in (&["={eax}", "={esi}", "={ecx}", "={edx}"]).iter().enumerate() { - assert_eq!(&output_names[i].constraint.as_str(), c); - assert!(!output_names[i].is_rw); - assert!(!output_names[i].is_indirect); - } - - assert_eq!(clobbers, &[]); - - assert!(!volatile); - assert!(!alignstack); - - assert_eq!(inputs.len(), 2); - let leaf = codegen_operand(fx, &inputs[0].1).load_scalar(fx); // %eax - let subleaf = codegen_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx - - let (eax, ebx, ecx, edx) = - crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf); - - assert_eq!(outputs.len(), 4); - codegen_place(fx, outputs[0]) - .write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32))); - codegen_place(fx, outputs[1]) - .write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); - codegen_place(fx, outputs[2]) - .write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); - codegen_place(fx, outputs[3]) - .write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); - } - "xgetbv" => { - assert_eq!(input_names, &[Symbol::intern("{ecx}")]); - - assert_eq!(output_names.len(), 2); - for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() { - assert_eq!(&output_names[i].constraint.as_str(), c); - assert!(!output_names[i].is_rw); - assert!(!output_names[i].is_indirect); - } - - assert_eq!(clobbers, &[]); - - assert!(!volatile); - assert!(!alignstack); - - crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported"); - } - // ___chkstk, ___chkstk_ms and __alloca are only used on Windows - _ if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") => { - crate::trap::trap_unimplemented(fx, "Stack probes are not supported"); - } - _ if fx.tcx.symbol_name(fx.instance).name == "__alloca" => { - crate::trap::trap_unimplemented(fx, "Alloca is not supported"); - } - // Used in sys::windows::abort_internal - "int $$0x29" => { - crate::trap::trap_unimplemented(fx, "Windows abort"); - } - _ => fx - .tcx - .sess - .span_fatal(stmt.source_info.span, "Inline assembly is not supported"), + _ => fx.tcx.sess.span_fatal( + stmt.source_info.span, + "Legacy `llvm_asm!` inline assembly is not supported. \ + Try using the new `asm!` instead.", + ), } } StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), @@ -844,7 +768,7 @@ fn codegen_stmt<'tcx>( let elem_size: u64 = pointee.size.bytes(); let bytes = if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; - fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes); + fx.bcx.call_memcpy(fx.module.target_config(), dst, src, bytes); } } } diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index b5874f62535..92e4435565e 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,8 +1,10 @@ use rustc_index::vec::IndexVec; +use rustc_middle::ty::SymbolName; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; use rustc_target::spec::{HasTargetSpec, Target}; +use crate::constant::ConstantCx; use crate::prelude::*; pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type { @@ -226,12 +228,16 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool { } } -pub(crate) struct FunctionCx<'m, 'clif, 'tcx> { - pub(crate) cx: &'clif mut crate::CodegenCx<'m, 'tcx>, +pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { + pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>, + pub(crate) module: &'m mut dyn Module, pub(crate) tcx: TyCtxt<'tcx>, pub(crate) pointer_type: Type, // Cached from module + pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>, + pub(crate) constants_cx: ConstantCx, pub(crate) instance: Instance<'tcx>, + pub(crate) symbol_name: SymbolName<'tcx>, pub(crate) mir: &'tcx Body<'tcx>, pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>, @@ -242,9 +248,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx> { /// When `#[track_caller]` is used, the implicit caller location is stored in this variable. pub(crate) caller_location: Option<CValue<'tcx>>, - /// See [`crate::optimize::code_layout`] for more information. - pub(crate) cold_blocks: EntitySet<Block>, - pub(crate) clif_comments: crate::pretty_clif::CommentWriter, pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>, @@ -339,7 +342,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { } pub(crate) fn triple(&self) -> &target_lexicon::Triple { - self.cx.module.isa().triple() + self.module.isa().triple() } pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value { @@ -352,15 +355,14 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let mut data_ctx = DataContext::new(); data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice()); let msg_id = self - .cx .module .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false) .unwrap(); // Ignore DuplicateDefinition error, as the data will be the same - let _ = self.cx.module.define_data(msg_id, &data_ctx); + let _ = self.module.define_data(msg_id, &data_ctx); - let local_msg_id = self.cx.module.declare_data_in_func(msg_id, self.bcx.func); + let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func); if self.clif_comments.enabled() { self.add_comment(local_msg_id, msg); } diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs new file mode 100644 index 00000000000..e59a0cb0a23 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/config.rs @@ -0,0 +1,107 @@ +use std::env; +use std::str::FromStr; + +fn bool_env_var(key: &str) -> bool { + env::var(key).as_ref().map(|val| &**val) == Ok("1") +} + +/// The mode to use for compilation. +#[derive(Copy, Clone, Debug)] +pub enum CodegenMode { + /// AOT compile the crate. This is the default. + Aot, + /// JIT compile and execute the crate. + Jit, + /// JIT compile and execute the crate, but only compile functions the first time they are used. + JitLazy, +} + +impl FromStr for CodegenMode { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "aot" => Ok(CodegenMode::Aot), + "jit" => Ok(CodegenMode::Jit), + "jit-lazy" => Ok(CodegenMode::JitLazy), + _ => Err(format!("Unknown codegen mode `{}`", s)), + } + } +} + +/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. +#[derive(Clone, Debug)] +pub struct BackendConfig { + /// Should the crate be AOT compiled or JIT executed. + /// + /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`. + pub codegen_mode: CodegenMode, + + /// When JIT mode is enable pass these arguments to the program. + /// + /// Defaults to the value of `CG_CLIF_JIT_ARGS`. + pub jit_args: Vec<String>, + + /// Display the time it took to perform codegen for a crate. + /// + /// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise. + /// Can be set using `-Cllvm-args=display_cg_time=...`. + pub display_cg_time: bool, + + /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run + /// once before passing the clif ir to Cranelift for compilation. + /// + /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is + /// compiled with debug assertions enabled or false otherwise. Can be set using + /// `-Cllvm-args=enable_verifier=...`. + pub enable_verifier: bool, + + /// Don't cache object files in the incremental cache. Useful during development of cg_clif + /// to make it possible to use incremental mode for all analyses performed by rustc without + /// caching object files when their content should have been changed by a change to cg_clif. + /// + /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false + /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`. + pub disable_incr_cache: bool, +} + +impl Default for BackendConfig { + fn default() -> Self { + BackendConfig { + codegen_mode: CodegenMode::Aot, + jit_args: { + let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new()); + args.split(' ').map(|arg| arg.to_string()).collect() + }, + display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"), + enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"), + disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"), + } + } +} + +impl BackendConfig { + /// Parse the configuration passed in using `-Cllvm-args`. + pub fn from_opts(opts: &[String]) -> Result<Self, String> { + fn parse_bool(name: &str, value: &str) -> Result<bool, String> { + value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name)) + } + + let mut config = BackendConfig::default(); + for opt in opts { + if let Some((name, value)) = opt.split_once('=') { + match name { + "mode" => config.codegen_mode = value.parse()?, + "display_cg_time" => config.display_cg_time = parse_bool(name, value)?, + "enable_verifier" => config.enable_verifier = parse_bool(name, value)?, + "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?, + _ => return Err(format!("Unknown option `{}`", name)), + } + } else { + return Err(format!("Invalid option `{}`", opt)); + } + } + + Ok(config) + } +} diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index fcd41c84465..0a0e02d2639 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -2,7 +2,7 @@ use rustc_span::DUMMY_SP; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorReported; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ @@ -15,10 +15,10 @@ use cranelift_module::*; use crate::prelude::*; -#[derive(Default)] pub(crate) struct ConstantCx { todo: Vec<TodoItem>, done: FxHashSet<DataId>, + anon_allocs: FxHashMap<AllocId, DataId>, } #[derive(Copy, Clone, Debug)] @@ -28,6 +28,10 @@ enum TodoItem { } impl ConstantCx { + pub(crate) fn new() -> Self { + ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() } + } + pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) { //println!("todo {:?}", self.todo); define_all_allocs(tcx, module, &mut self); @@ -74,8 +78,10 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { all_constants_ok } -pub(crate) fn codegen_static(constants_cx: &mut ConstantCx, def_id: DefId) { +pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) { + let mut constants_cx = ConstantCx::new(); constants_cx.todo.push(TodoItem::Static(def_id)); + constants_cx.finalize(tcx, module); } pub(crate) fn codegen_tls_ref<'tcx>( @@ -83,8 +89,8 @@ pub(crate) fn codegen_tls_ref<'tcx>( def_id: DefId, layout: TyAndLayout<'tcx>, ) -> CValue<'tcx> { - let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); - let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("tls {:?}", def_id)); } @@ -97,8 +103,8 @@ fn codegen_static_ref<'tcx>( def_id: DefId, layout: TyAndLayout<'tcx>, ) -> CPlace<'tcx> { - let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); - let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", def_id)); } @@ -182,28 +188,31 @@ pub(crate) fn codegen_const_value<'tcx>( let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id); let base_addr = match alloc_kind { Some(GlobalAlloc::Memory(alloc)) => { - fx.cx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id)); - let data_id = - data_id_for_alloc_id(fx.cx.module, ptr.alloc_id, alloc.mutability); + fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id)); + let data_id = data_id_for_alloc_id( + &mut fx.constants_cx, + fx.module, + ptr.alloc_id, + alloc.mutability, + ); let local_data_id = - fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id)); } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } Some(GlobalAlloc::Function(instance)) => { - let func_id = - crate::abi::import_function(fx.tcx, fx.cx.module, instance); + let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = - fx.cx.module.declare_func_in_func(func_id, &mut fx.bcx.func); + fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } Some(GlobalAlloc::Static(def_id)) => { assert!(fx.tcx.is_static(def_id)); - let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); + let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false); let local_data_id = - fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", def_id)); } @@ -243,10 +252,11 @@ fn pointer_for_allocation<'tcx>( alloc: &'tcx Allocation, ) -> crate::pointer::Pointer { let alloc_id = fx.tcx.create_memory_alloc(alloc); - fx.cx.constants_cx.todo.push(TodoItem::Alloc(alloc_id)); - let data_id = data_id_for_alloc_id(fx.cx.module, alloc_id, alloc.mutability); + fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id)); + let data_id = + data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability); - let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(local_data_id, format!("{:?}", alloc_id)); } @@ -255,18 +265,14 @@ fn pointer_for_allocation<'tcx>( } fn data_id_for_alloc_id( + cx: &mut ConstantCx, module: &mut dyn Module, alloc_id: AllocId, mutability: rustc_hir::Mutability, ) -> DataId { - module - .declare_data( - &format!(".L__alloc_{:x}", alloc_id.0), - Linkage::Local, - mutability == rustc_hir::Mutability::Mut, - false, - ) - .unwrap() + *cx.anon_allocs.entry(alloc_id).or_insert_with(|| { + module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap() + }) } fn data_id_for_static( @@ -344,7 +350,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(alloc) => alloc, GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(), }; - let data_id = data_id_for_alloc_id(module, alloc_id, alloc.mutability); + let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability); (data_id, alloc, None) } TodoItem::Static(def_id) => { @@ -397,7 +403,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } GlobalAlloc::Memory(target_alloc) => { cx.todo.push(TodoItem::Alloc(reloc)); - data_id_for_alloc_id(module, reloc, target_alloc.mutability) + data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability) } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) @@ -419,8 +425,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64); } - // FIXME don't duplicate definitions in lazy jit mode - let _ = module.define_data(data_id, &data_ctx); + module.define_data(data_id, &data_ctx).unwrap(); cx.done.insert(data_id); } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 357c9fe6ed8..d1251e749f3 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -5,17 +5,19 @@ use crate::prelude::*; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; +use gimli::RunTimeEndian; use crate::backend::WriteDebugInfo; -pub(crate) struct UnwindContext<'tcx> { - tcx: TyCtxt<'tcx>, +pub(crate) struct UnwindContext { + endian: RunTimeEndian, frame_table: FrameTable, cie_id: Option<CieId>, } -impl<'tcx> UnwindContext<'tcx> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { +impl UnwindContext { + pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { + let endian = super::target_endian(tcx); let mut frame_table = FrameTable::default(); let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { @@ -28,7 +30,7 @@ impl<'tcx> UnwindContext<'tcx> { None }; - UnwindContext { tcx, frame_table, cie_id } + UnwindContext { endian, frame_table, cie_id } } pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) { @@ -54,8 +56,7 @@ impl<'tcx> UnwindContext<'tcx> { } pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) { - let mut eh_frame = - EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx))); + let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); if !eh_frame.0.writer.slice().is_empty() { @@ -70,17 +71,16 @@ impl<'tcx> UnwindContext<'tcx> { } } - #[cfg(feature = "jit")] - pub(crate) unsafe fn register_jit( - self, - jit_module: &cranelift_jit::JITModule, - ) -> Option<UnwindRegistry> { - let mut eh_frame = - EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx))); + #[cfg(all(feature = "jit", windows))] + pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {} + + #[cfg(all(feature = "jit", not(windows)))] + pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) { + let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); if eh_frame.0.writer.slice().is_empty() { - return None; + return; } let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module); @@ -88,7 +88,10 @@ impl<'tcx> UnwindContext<'tcx> { // GCC expects a terminating "empty" length, so write a 0 length at the end of the table. eh_frame.extend(&[0, 0, 0, 0]); - let mut registrations = Vec::new(); + // FIXME support unregistering unwind tables once cranelift-jit supports deallocating + // individual functions + #[allow(unused_variables)] + let (eh_frame, eh_frame_len, _) = Vec::into_raw_parts(eh_frame); // ======================================================================= // Everything after this line up to the end of the file is loosly based on @@ -96,8 +99,8 @@ impl<'tcx> UnwindContext<'tcx> { #[cfg(target_os = "macos")] { // On macOS, `__register_frame` takes a pointer to a single FDE - let start = eh_frame.as_ptr(); - let end = start.add(eh_frame.len()); + let start = eh_frame; + let end = start.add(eh_frame_len); let mut current = start; // Walk all of the entries in the frame table and register them @@ -107,7 +110,6 @@ impl<'tcx> UnwindContext<'tcx> { // Skip over the CIE if current != start { __register_frame(current); - registrations.push(current as usize); } // Move to the next table entry (+4 because the length itself is not inclusive) @@ -117,41 +119,12 @@ impl<'tcx> UnwindContext<'tcx> { #[cfg(not(target_os = "macos"))] { // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0 - let ptr = eh_frame.as_ptr(); - __register_frame(ptr); - registrations.push(ptr as usize); + __register_frame(eh_frame); } - - Some(UnwindRegistry { _frame_table: eh_frame, registrations }) } } -/// Represents a registry of function unwind information for System V ABI. -pub(crate) struct UnwindRegistry { - _frame_table: Vec<u8>, - registrations: Vec<usize>, -} - extern "C" { // libunwind import fn __register_frame(fde: *const u8); - fn __deregister_frame(fde: *const u8); -} - -impl Drop for UnwindRegistry { - fn drop(&mut self) { - unsafe { - // libgcc stores the frame entries as a linked list in decreasing sort order - // based on the PC value of the registered entry. - // - // As we store the registrations in increasing order, it would be O(N^2) to - // deregister in that order. - // - // To ensure that we just pop off the first element in the list upon every - // deregistration, walk our list of registrations backwards. - for fde in self.registrations.iter().rev() { - __deregister_frame(*fde as *const _); - } - } - } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index ed3bdedddce..9c5cd53d866 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -16,12 +16,6 @@ use cranelift_object::ObjectModule; use crate::{prelude::*, BackendConfig}; -fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule { - let module = crate::backend::make_module(tcx.sess, name); - assert_eq!(pointer_ty(tcx), module.target_config().pointer_type()); - module -} - struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>); impl<HCX> HashStable<HCX> for ModuleCodegenResult { @@ -32,11 +26,12 @@ impl<HCX> HashStable<HCX> for ModuleCodegenResult { fn emit_module( tcx: TyCtxt<'_>, + backend_config: &BackendConfig, name: String, kind: ModuleKind, module: ObjectModule, debug: Option<DebugContext<'_>>, - unwind_context: UnwindContext<'_>, + unwind_context: UnwindContext, ) -> ModuleCodegenResult { let mut product = module.finish(); @@ -52,7 +47,7 @@ fn emit_module( tcx.sess.fatal(&format!("error writing object file: {}", err)); } - let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() { + let work_product = if backend_config.disable_incr_cache { None } else { rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( @@ -110,23 +105,24 @@ fn module_codegen( let cgu = tcx.codegen_unit(cgu_name); let mono_items = cgu.items_in_deterministic_order(tcx); - let mut module = new_module(tcx, cgu_name.as_str().to_string()); + let isa = crate::build_isa(tcx.sess, &backend_config); + let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string()); let mut cx = crate::CodegenCx::new( tcx, - backend_config, - &mut module, + backend_config.clone(), + module.isa(), tcx.sess.opts.debuginfo != DebugInfo::None, ); - super::predefine_mono_items(&mut cx, &mono_items); + super::predefine_mono_items(tcx, &mut module, &mono_items); for (mono_item, _) in mono_items { match mono_item { MonoItem::Fn(inst) => { - cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst)); - } - MonoItem::Static(def_id) => { - crate::constant::codegen_static(&mut cx.constants_cx, def_id) + cx.tcx + .sess + .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst)); } + MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id), MonoItem::GlobalAsm(item_id) => { let item = cx.tcx.hir().item(item_id); if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind { @@ -138,25 +134,28 @@ fn module_codegen( } } } - let (global_asm, debug, mut unwind_context) = - tcx.sess.time("finalize CodegenCx", || cx.finalize()); - crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context); + crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false); - let codegen_result = emit_module( - tcx, - cgu.name().as_str().to_string(), - ModuleKind::Regular, - module, - debug, - unwind_context, - ); + let debug_context = cx.debug_context; + let unwind_context = cx.unwind_context; + let codegen_result = tcx.sess.time("write object file", || { + emit_module( + tcx, + &backend_config, + cgu.name().as_str().to_string(), + ModuleKind::Regular, + module, + debug_context, + unwind_context, + ) + }); - codegen_global_asm(tcx, &cgu.name().as_str(), &global_asm); + codegen_global_asm(tcx, &cgu.name().as_str(), &cx.global_asm); codegen_result } -pub(super) fn run_aot( +pub(crate) fn run_aot( tcx: TyCtxt<'_>, backend_config: BackendConfig, metadata: EncodedMetadata, @@ -193,14 +192,14 @@ pub(super) fn run_aot( } } - let modules = super::time(tcx, "codegen mono items", || { + let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || { cgus.iter() .map(|cgu| { let cgu_reuse = determine_cgu_reuse(tcx, cgu); tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse); match cgu_reuse { - _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {} + _ if backend_config.disable_incr_cache => {} CguReuse::No => {} CguReuse::PreLto => { return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products); @@ -212,7 +211,7 @@ pub(super) fn run_aot( let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task( dep_node, tcx, - (backend_config, cgu.name()), + (backend_config.clone(), cgu.name()), module_codegen, rustc_middle::dep_graph::hash_result, ); @@ -228,7 +227,10 @@ pub(super) fn run_aot( tcx.sess.abort_if_errors(); - let mut allocator_module = new_module(tcx, "allocator_shim".to_string()); + let isa = crate::build_isa(tcx.sess, &backend_config); + let mut allocator_module = + crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string()); + assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); @@ -236,6 +238,7 @@ pub(super) fn run_aot( let allocator_module = if created_alloc_shim { let ModuleCodegenResult(module, work_product) = emit_module( tcx, + &backend_config, "allocator_shim".to_string(), ModuleKind::Allocator, allocator_module, diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index dbe1ff083f0..53c93f6a9dd 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -1,4 +1,4 @@ -//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object +//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object //! files. use std::cell::RefCell; @@ -15,25 +15,56 @@ use cranelift_jit::{JITBuilder, JITModule}; use crate::{prelude::*, BackendConfig}; use crate::{CodegenCx, CodegenMode}; -thread_local! { - pub static BACKEND_CONFIG: RefCell<Option<BackendConfig>> = RefCell::new(None); - pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None); +struct JitState { + backend_config: BackendConfig, + jit_module: JITModule, } -pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { - if !tcx.sess.opts.output_types.should_codegen() { - tcx.sess.fatal("JIT mode doesn't work with `cargo check`."); - } +thread_local! { + static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None); +} +fn create_jit_module<'tcx>( + tcx: TyCtxt<'tcx>, + backend_config: &BackendConfig, + hotswap: bool, +) -> (JITModule, CodegenCx<'tcx>) { let imported_symbols = load_imported_symbols_for_jit(tcx); - let mut jit_builder = - JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names()); - jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy)); + let isa = crate::build_isa(tcx.sess, backend_config); + let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); + jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbols(imported_symbols); let mut jit_module = JITModule::new(jit_builder); - assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); + + let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), jit_module.isa(), false); + + crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context); + crate::main_shim::maybe_create_entry_wrapper( + tcx, + &mut jit_module, + &mut cx.unwind_context, + true, + ); + + (jit_module, cx) +} + +pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { + if !tcx.sess.opts.output_types.should_codegen() { + tcx.sess.fatal("JIT mode doesn't work with `cargo check`"); + } + + if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) { + tcx.sess.fatal("can't jit non-executable crate"); + } + + let (mut jit_module, mut cx) = create_jit_module( + tcx, + &backend_config, + matches!(backend_config.codegen_mode, CodegenMode::JitLazy), + ); let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); let mono_items = cgus @@ -44,52 +75,45 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { .into_iter() .collect::<Vec<(_, (_, _))>>(); - let mut cx = crate::CodegenCx::new(tcx, backend_config, &mut jit_module, false); - - super::time(tcx, "codegen mono items", || { - super::predefine_mono_items(&mut cx, &mono_items); + super::time(tcx, backend_config.display_cg_time, "codegen mono items", || { + super::predefine_mono_items(tcx, &mut jit_module, &mono_items); for (mono_item, _) in mono_items { match mono_item { MonoItem::Fn(inst) => match backend_config.codegen_mode { CodegenMode::Aot => unreachable!(), CodegenMode::Jit => { - cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst)); + cx.tcx.sess.time("codegen fn", || { + crate::base::codegen_fn(&mut cx, &mut jit_module, inst) + }); } - CodegenMode::JitLazy => codegen_shim(&mut cx, inst), + CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst), }, MonoItem::Static(def_id) => { - crate::constant::codegen_static(&mut cx.constants_cx, def_id); + crate::constant::codegen_static(tcx, &mut jit_module, def_id); } MonoItem::GlobalAsm(item_id) => { - let item = cx.tcx.hir().item(item_id); + let item = tcx.hir().item(item_id); tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode"); } } } }); - let (global_asm, _debug, mut unwind_context) = - tcx.sess.time("finalize CodegenCx", || cx.finalize()); - jit_module.finalize_definitions(); - - if !global_asm.is_empty() { + if !cx.global_asm.is_empty() { tcx.sess.fatal("Inline asm is not supported in JIT mode"); } - crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context); - tcx.sess.abort_if_errors(); jit_module.finalize_definitions(); - let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) }; + unsafe { cx.unwind_context.register_jit(&jit_module) }; println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" ); - let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new()); let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()) - .chain(args.split(' ')) + .chain(backend_config.jit_args.iter().map(|arg| &**arg)) .map(|arg| CString::new(arg).unwrap()) .collect::<Vec<_>>(); let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>(); @@ -98,61 +122,27 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { // useful as some dynamic linkers use it as a marker to jump over. argv.push(std::ptr::null()); - BACKEND_CONFIG.with(|tls_backend_config| { - assert!(tls_backend_config.borrow_mut().replace(backend_config).is_none()) + let start_sig = Signature { + params: vec![ + AbiParam::new(jit_module.target_config().pointer_type()), + AbiParam::new(jit_module.target_config().pointer_type()), + ], + returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)], + call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), + }; + let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); + let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); + + LAZY_JIT_STATE.with(|lazy_jit_state| { + let mut lazy_jit_state = lazy_jit_state.borrow_mut(); + assert!(lazy_jit_state.is_none()); + *lazy_jit_state = Some(JitState { backend_config, jit_module }); }); - let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap(); - let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx); - - match entry_ty { - EntryFnType::Main => { - // FIXME set program arguments somehow - - let main_sig = Signature { - params: vec![], - returns: vec![], - call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), - }; - let main_func_id = jit_module - .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &main_sig) - .unwrap(); - let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); - - CURRENT_MODULE.with(|current_module| { - assert!(current_module.borrow_mut().replace(jit_module).is_none()) - }); - - let f: extern "C" fn() = unsafe { ::std::mem::transmute(finalized_main) }; - f(); - std::process::exit(0); - } - EntryFnType::Start => { - let start_sig = Signature { - params: vec![ - AbiParam::new(jit_module.target_config().pointer_type()), - AbiParam::new(jit_module.target_config().pointer_type()), - ], - returns: vec![AbiParam::new( - jit_module.target_config().pointer_type(), /*isize*/ - )], - call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), - }; - let start_func_id = jit_module - .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &start_sig) - .unwrap(); - let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); - - CURRENT_MODULE.with(|current_module| { - assert!(current_module.borrow_mut().replace(jit_module).is_none()) - }); - - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = - unsafe { ::std::mem::transmute(finalized_start) }; - let ret = f(args.len() as c_int, argv.as_ptr()); - std::process::exit(ret); - } - } + let f: extern "C" fn(c_int, *const *const c_char) -> c_int = + unsafe { ::std::mem::transmute(finalized_start) }; + let ret = f(args.len() as c_int, argv.as_ptr()); + std::process::exit(ret); } #[no_mangle] @@ -161,24 +151,23 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 // lift is used to ensure the correct lifetime for instance. let instance = tcx.lift(unsafe { *instance_ptr }).unwrap(); - CURRENT_MODULE.with(|jit_module| { - let mut jit_module = jit_module.borrow_mut(); - let jit_module = jit_module.as_mut().unwrap(); - let backend_config = - BACKEND_CONFIG.with(|backend_config| backend_config.borrow().clone().unwrap()); + LAZY_JIT_STATE.with(|lazy_jit_state| { + let mut lazy_jit_state = lazy_jit_state.borrow_mut(); + let lazy_jit_state = lazy_jit_state.as_mut().unwrap(); + let jit_module = &mut lazy_jit_state.jit_module; + let backend_config = lazy_jit_state.backend_config.clone(); - let name = tcx.symbol_name(instance).name.to_string(); + let name = tcx.symbol_name(instance).name; let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance); - let func_id = jit_module.declare_function(&name, Linkage::Export, &sig).unwrap(); + let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap(); jit_module.prepare_for_function_redefine(func_id).unwrap(); - let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module, false); - tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, instance)); + let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false); + tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance)); - let (global_asm, _debug_context, unwind_context) = cx.finalize(); - assert!(global_asm.is_empty()); + assert!(cx.global_asm.is_empty()); jit_module.finalize_definitions(); - std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) }); + unsafe { cx.unwind_context.register_jit(&jit_module) }; jit_module.get_finalized_function(func_id) }) }) @@ -248,35 +237,37 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { imported_symbols } -fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) { +fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) { let tcx = cx.tcx; - let pointer_type = cx.module.target_config().pointer_type(); + let pointer_type = module.target_config().pointer_type(); - let name = tcx.symbol_name(inst).name.to_string(); - let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst); - let func_id = cx.module.declare_function(&name, Linkage::Export, &sig).unwrap(); + let name = tcx.symbol_name(inst).name; + let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst); + let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap(); let instance_ptr = Box::into_raw(Box::new(inst)); - let jit_fn = cx - .module + let jit_fn = module .declare_function( "__clif_jit_fn", Linkage::Import, &Signature { - call_conv: cx.module.target_config().default_call_conv, + call_conv: module.target_config().default_call_conv, params: vec![AbiParam::new(pointer_type)], returns: vec![AbiParam::new(pointer_type)], }, ) .unwrap(); - let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone()); + cx.cached_context.clear(); + let trampoline = &mut cx.cached_context.func; + trampoline.signature = sig.clone(); + let mut builder_ctx = FunctionBuilderContext::new(); - let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx); + let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx); - let jit_fn = cx.module.declare_func_in_func(jit_fn, trampoline_builder.func); + let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func); let sig_ref = trampoline_builder.func.import_signature(sig); let entry_block = trampoline_builder.create_block(); @@ -291,10 +282,10 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) { let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec(); trampoline_builder.ins().return_(&ret_vals); - cx.module + module .define_function( func_id, - &mut Context::for_function(trampoline), + &mut cx.cached_context, &mut NullTrapSink {}, &mut NullStackMapSink {}, ) diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index d49182a07b7..8f5714ecb41 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -1,63 +1,37 @@ -//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions -//! like JIT executing or writing object files. +//! Drivers are responsible for calling [`codegen_fn`] or [`codegen_static`] for each mono item and +//! performing any further actions like JIT executing or writing object files. +//! +//! [`codegen_fn`]: crate::base::codegen_fn +//! [`codegen_static`]: crate::constant::codegen_static -use std::any::Any; - -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; use crate::prelude::*; -use crate::CodegenMode; -mod aot; +pub(crate) mod aot; #[cfg(feature = "jit")] -mod jit; - -pub(crate) fn codegen_crate( - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, - backend_config: crate::BackendConfig, -) -> Box<dyn Any> { - tcx.sess.abort_if_errors(); - - match backend_config.codegen_mode { - CodegenMode::Aot => aot::run_aot(tcx, backend_config, metadata, need_metadata_module), - CodegenMode::Jit | CodegenMode::JitLazy => { - let is_executable = - tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable); - if !is_executable { - tcx.sess.fatal("can't jit non-executable crate"); - } - - #[cfg(feature = "jit")] - let _: ! = jit::run_jit(tcx, backend_config); - - #[cfg(not(feature = "jit"))] - tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift"); - } - } -} +pub(crate) mod jit; fn predefine_mono_items<'tcx>( - cx: &mut crate::CodegenCx<'_, 'tcx>, + tcx: TyCtxt<'tcx>, + module: &mut dyn Module, mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))], ) { - cx.tcx.sess.time("predefine functions", || { - let is_compiler_builtins = cx.tcx.is_compiler_builtins(LOCAL_CRATE); + tcx.sess.time("predefine functions", || { + let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE); for &(mono_item, (linkage, visibility)) in mono_items { match mono_item { MonoItem::Fn(instance) => { - let name = cx.tcx.symbol_name(instance).name.to_string(); + let name = tcx.symbol_name(instance).name; let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name)); - let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance); + let sig = get_function_sig(tcx, module.isa().triple(), instance); let linkage = crate::linkage::get_clif_linkage( mono_item, linkage, visibility, is_compiler_builtins, ); - cx.module.declare_function(&name, linkage, &sig).unwrap(); + module.declare_function(name, linkage, &sig).unwrap(); } MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {} } @@ -65,8 +39,8 @@ fn predefine_mono_items<'tcx>( }); } -fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R { - if std::env::var("CG_CLIF_DISPLAY_CG_TIME").as_ref().map(|val| &**val) == Ok("1") { +fn time<R>(tcx: TyCtxt<'_>, display: bool, name: &'static str, f: impl FnOnce() -> R) -> R { + if display { println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name); let before = std::time::Instant::now(); let res = tcx.sess.time(name, f); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 1fb5e86aed7..4ab4c2957ca 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -24,6 +24,64 @@ pub(crate) fn codegen_inline_asm<'tcx>( let true_ = fx.bcx.ins().iconst(types::I32, 1); fx.bcx.ins().trapnz(true_, TrapCode::User(1)); return; + } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string()) + && template[1] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string()) + && template[3] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string()) + { + assert_eq!(operands.len(), 4); + let (leaf, eax_place) = match operands[0] { + InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { + let reg = expect_reg(reg); + assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax)); + ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place.unwrap()), + ) + } + _ => unreachable!(), + }; + let ebx_place = match operands[1] { + InlineAsmOperand::Out { reg, late: true, place } => { + let reg = expect_reg(reg); + assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si)); + crate::base::codegen_place(fx, place.unwrap()) + } + _ => unreachable!(), + }; + let (sub_leaf, ecx_place) = match operands[2] { + InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { + let reg = expect_reg(reg); + assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::cx)); + ( + crate::base::codegen_operand(fx, in_value).load_scalar(fx), + crate::base::codegen_place(fx, out_place.unwrap()), + ) + } + _ => unreachable!(), + }; + let edx_place = match operands[3] { + InlineAsmOperand::Out { reg, late: true, place } => { + let reg = expect_reg(reg); + assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::dx)); + crate::base::codegen_place(fx, place.unwrap()) + } + _ => unreachable!(), + }; + + let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf); + + eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32))); + ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32))); + ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32))); + edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32))); + return; + } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") { + // ___chkstk, ___chkstk_ms and __alloca are only used on Windows + crate::trap::trap_unimplemented(fx, "Stack probes are not supported"); + } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" { + crate::trap::trap_unimplemented(fx, "Alloca is not supported"); } let mut slot_size = Size::from_bytes(0); @@ -92,8 +150,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( let inline_asm_index = fx.inline_asm_index; fx.inline_asm_index += 1; - let asm_name = - format!("{}__inline_asm_{}", fx.tcx.symbol_name(fx.instance).name, inline_asm_index); + let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index); let generated_asm = generate_asm_wrapper( &asm_name, @@ -202,7 +259,6 @@ fn call_inline_asm<'tcx>( } let inline_asm_func = fx - .cx .module .declare_function( asm_name, @@ -214,7 +270,7 @@ fn call_inline_asm<'tcx>( }, ) .unwrap(); - let inline_asm_func = fx.cx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); + let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(inline_asm_func, asm_name); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs index b27b0eddfba..9de12e759bc 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs @@ -8,7 +8,7 @@ use crate::prelude::*; pub(crate) fn codegen_cpuid_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, leaf: Value, - _subleaf: Value, + _sub_leaf: Value, ) -> (Value, Value, Value, Value) { let leaf_0 = fx.bcx.create_block(); let leaf_1 = fx.bcx.create_block(); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 83c91f789cd..ba4ed2162cd 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -22,7 +22,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }; // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8` - llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) { + "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) { let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); let lane_ty = fx.clif_type(lane_ty).unwrap(); assert!(lane_count <= 32); @@ -51,7 +51,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32)); ret.write_cvalue(fx, res); }; - llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) { + "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) { let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const"); let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) { 0 => FloatCC::Equal, @@ -81,7 +81,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane) }); }; - llvm.x86.sse2.psrli.d, (c a, o imm8) { + "llvm.x86.sse2.psrli.d", (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { @@ -91,7 +91,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( CValue::by_val(res_lane, res_lane_layout) }); }; - llvm.x86.sse2.pslli.d, (c a, o imm8) { + "llvm.x86.sse2.pslli.d", (c a, o imm8) { let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const"); simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| { let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) { @@ -101,7 +101,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( CValue::by_val(res_lane, res_lane_layout) }); }; - llvm.x86.sse2.storeu.dq, (v mem_addr, c a) { + "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) { // FIXME correctly handle the unalignment let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout()); dest.write_cvalue(fx, a); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 39e047a98f9..435737f3a51 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -8,23 +8,25 @@ mod simd; pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; +use rustc_span::symbol::{sym, kw}; +use rustc_middle::ty::print::with_no_trimmed_paths; + use crate::prelude::*; use cranelift_codegen::ir::AtomicRmwOp; -use rustc_middle::ty::print::with_no_trimmed_paths; macro intrinsic_pat { (_) => { _ }, ($name:ident) => { - stringify!($name) + sym::$name + }, + (kw.$name:ident) => { + kw::$name }, ($name:literal) => { - stringify!($name) + $name }, - ($x:ident . $($xs:tt).*) => { - concat!(stringify!($x), ".", intrinsic_pat!($($xs).*)) - } } macro intrinsic_arg { @@ -87,7 +89,7 @@ macro call_intrinsic_match { )*) => { match $intrinsic { $( - stringify!($name) => { + sym::$name => { assert!($substs.is_noop()); if let [$(ref $arg),*] = *$args { let ($($arg,)*) = ( @@ -400,18 +402,17 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let def_id = instance.def_id(); let substs = instance.substs; - let intrinsic = fx.tcx.item_name(def_id).as_str(); - let intrinsic = &intrinsic[..]; + let intrinsic = fx.tcx.item_name(def_id); let ret = match destination { Some((place, _)) => place, None => { // Insert non returning intrinsics here match intrinsic { - "abort" => { + sym::abort => { trap_abort(fx, "Called intrinsic::abort."); } - "transmute" => { + sym::transmute => { crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span); } _ => unimplemented!("unsupported instrinsic {}", intrinsic), @@ -420,7 +421,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( } }; - if intrinsic.starts_with("simd_") { + if intrinsic.as_str().starts_with("simd_") { self::simd::codegen_simd_intrinsic_call(fx, instance, args, ret, span); let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1); fx.bcx.ins().jump(ret_block, &[]); @@ -470,8 +471,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( sinf64(flt) -> f64 => sin, cosf32(flt) -> f32 => cosf, cosf64(flt) -> f64 => cos, - tanf32(flt) -> f32 => tanf, - tanf64(flt) -> f64 => tan, } intrinsic_match! { @@ -496,12 +495,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( count }; - if intrinsic.contains("nonoverlapping") { + if intrinsic == sym::copy_nonoverlapping { // FIXME emit_small_memcpy - fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount); + fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount); } else { // FIXME emit_small_memmove - fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount); + fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount); } }; // NOTE: the volatile variants have src and dst swapped @@ -515,12 +514,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; // FIXME make the copy actually volatile when using emit_small_mem{cpy,move} - if intrinsic.contains("nonoverlapping") { + if intrinsic == sym::volatile_copy_nonoverlapping_memory { // FIXME emit_small_memcpy - fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount); + fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount); } else { // FIXME emit_small_memmove - fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount); + fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount); } }; size_of_val, <T> (c ptr) { @@ -552,27 +551,28 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); }; - _ if intrinsic.starts_with("unchecked_") || intrinsic == "exact_div", (c x, c y) { + unchecked_add | unchecked_sub | unchecked_div | exact_div | unchecked_rem + | unchecked_shl | unchecked_shr, (c x, c y) { // FIXME trap on overflow let bin_op = match intrinsic { - "unchecked_add" => BinOp::Add, - "unchecked_sub" => BinOp::Sub, - "unchecked_div" | "exact_div" => BinOp::Div, - "unchecked_rem" => BinOp::Rem, - "unchecked_shl" => BinOp::Shl, - "unchecked_shr" => BinOp::Shr, - _ => unreachable!("intrinsic {}", intrinsic), + sym::unchecked_add => BinOp::Add, + sym::unchecked_sub => BinOp::Sub, + sym::unchecked_div | sym::exact_div => BinOp::Div, + sym::unchecked_rem => BinOp::Rem, + sym::unchecked_shl => BinOp::Shl, + sym::unchecked_shr => BinOp::Shr, + _ => unreachable!(), }; let res = crate::num::codegen_int_binop(fx, bin_op, x, y); ret.write_cvalue(fx, res); }; - _ if intrinsic.ends_with("_with_overflow"), (c x, c y) { + add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) { assert_eq!(x.layout().ty, y.layout().ty); let bin_op = match intrinsic { - "add_with_overflow" => BinOp::Add, - "sub_with_overflow" => BinOp::Sub, - "mul_with_overflow" => BinOp::Mul, - _ => unreachable!("intrinsic {}", intrinsic), + sym::add_with_overflow => BinOp::Add, + sym::sub_with_overflow => BinOp::Sub, + sym::mul_with_overflow => BinOp::Mul, + _ => unreachable!(), }; let res = crate::num::codegen_checked_int_binop( @@ -583,12 +583,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ); ret.write_cvalue(fx, res); }; - _ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) { + saturating_add | saturating_sub, <T> (c lhs, c rhs) { assert_eq!(lhs.layout().ty, rhs.layout().ty); let bin_op = match intrinsic { - "saturating_add" => BinOp::Add, - "saturating_sub" => BinOp::Sub, - _ => unreachable!("intrinsic {}", intrinsic), + sym::saturating_add => BinOp::Add, + sym::saturating_sub => BinOp::Sub, + _ => unreachable!(), }; let signed = type_sign(T); @@ -609,15 +609,15 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed); let val = match (intrinsic, signed) { - ("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val), - ("saturating_sub", false) => fx.bcx.ins().select(has_overflow, min, val), - ("saturating_add", true) => { + (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val), + (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val), + (sym::saturating_add, true) => { let rhs = rhs.load_scalar(fx); let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min); fx.bcx.ins().select(has_overflow, sat_val, val) } - ("saturating_sub", true) => { + (sym::saturating_sub, true) => { let rhs = rhs.load_scalar(fx); let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0); let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max); @@ -632,11 +632,21 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; rotate_left, <T>(v x, v y) { let layout = fx.layout_of(T); + let y = if fx.bcx.func.dfg.value_type(y) == types::I128 { + fx.bcx.ins().ireduce(types::I64, y) + } else { + y + }; let res = fx.bcx.ins().rotl(x, y); ret.write_cvalue(fx, CValue::by_val(res, layout)); }; rotate_right, <T>(v x, v y) { let layout = fx.layout_of(T); + let y = if fx.bcx.func.dfg.value_type(y) == types::I128 { + fx.bcx.ins().ireduce(types::I64, y) + } else { + y + }; let res = fx.bcx.ins().rotr(x, y); ret.write_cvalue(fx, CValue::by_val(res, layout)); }; @@ -670,7 +680,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let dst_ptr = dst.load_scalar(fx); // FIXME make the memset actually volatile when switching to emit_small_memset // FIXME use emit_small_memset - fx.bcx.call_memset(fx.cx.module.target_config(), dst_ptr, val, count); + fx.bcx.call_memset(fx.module.target_config(), dst_ptr, val, count); }; ctlz | ctlz_nonzero, <T> (v arg) { // FIXME trap on `ctlz_nonzero` with zero arg. @@ -806,7 +816,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( return; } - if intrinsic == "assert_zero_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() { + if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() { with_no_trimmed_paths(|| crate::base::codegen_panic( fx, &format!("attempted to zero-initialize type `{}`, which is invalid", T), @@ -815,7 +825,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( return; } - if intrinsic == "assert_uninit_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() { + if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() { with_no_trimmed_paths(|| crate::base::codegen_panic( fx, &format!("attempted to leave type `{}` uninitialized, which is invalid", T), @@ -827,7 +837,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( volatile_load | unaligned_volatile_load, (c ptr) { // Cranelift treats loads as volatile by default - // FIXME ignore during stack2reg optimization // FIXME correctly handle unaligned_volatile_load let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); @@ -836,7 +845,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; volatile_store | unaligned_volatile_store, (v ptr, c val) { // Cranelift treats stores as volatile by default - // FIXME ignore during stack2reg optimization // FIXME correctly handle unaligned_volatile_store let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout()); dest.write_cvalue(fx, val); @@ -878,14 +886,14 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ret.write_cvalue(fx, caller_location); }; - _ if intrinsic.starts_with("atomic_fence"), () { + _ if intrinsic.as_str().starts_with("atomic_fence"), () { fx.bcx.ins().fence(); }; - _ if intrinsic.starts_with("atomic_singlethreadfence"), () { + _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () { // FIXME use a compiler fence once Cranelift supports it fx.bcx.ins().fence(); }; - _ if intrinsic.starts_with("atomic_load"), <T> (v ptr) { + _ if intrinsic.as_str().starts_with("atomic_load"), <T> (v ptr) { validate_atomic_type!(fx, intrinsic, span, T); let ty = fx.clif_type(T).unwrap(); @@ -894,14 +902,14 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(T)); ret.write_cvalue(fx, val); }; - _ if intrinsic.starts_with("atomic_store"), (v ptr, c val) { + _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) { validate_atomic_type!(fx, intrinsic, span, val.layout().ty); let val = val.load_scalar(fx); fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr); }; - _ if intrinsic.starts_with("atomic_xchg"), (v ptr, c new) { + _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) { let layout = new.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -913,7 +921,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_* + _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_* let layout = new.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); @@ -927,7 +935,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_val) }; - _ if intrinsic.starts_with("atomic_xadd"), (v ptr, c amount) { + _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) { let layout = amount.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -939,7 +947,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_xsub"), (v ptr, c amount) { + _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) { let layout = amount.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -951,7 +959,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_and"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -963,7 +971,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_or"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -975,7 +983,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_xor"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -989,7 +997,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( }; // FIXME https://github.com/bytecodealliance/wasmtime/issues/2647 - _ if intrinsic.starts_with("atomic_nand"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -1001,7 +1009,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_max"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -1013,7 +1021,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_umax"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -1025,7 +1033,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_min"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -1037,7 +1045,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); }; - _ if intrinsic.starts_with("atomic_umin"), (v ptr, c src) { + _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) { let layout = src.layout(); validate_atomic_type!(fx, intrinsic, span, layout.ty); let ty = fx.clif_type(layout.ty).unwrap(); @@ -1071,7 +1079,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); }; - try, (v f, v data, v _catch_fn) { + kw.Try, (v f, v data, v _catch_fn) { // FIXME once unwinding is supported, change this to actually catch panics let f_sig = fx.bcx.func.import_signature(Signature { call_conv: CallConv::triple_default(fx.triple()), @@ -1088,11 +1096,11 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) { let res = crate::num::codegen_float_binop(fx, match intrinsic { - "fadd_fast" => BinOp::Add, - "fsub_fast" => BinOp::Sub, - "fmul_fast" => BinOp::Mul, - "fdiv_fast" => BinOp::Div, - "frem_fast" => BinOp::Rem, + sym::fadd_fast => BinOp::Add, + sym::fsub_fast => BinOp::Sub, + sym::fmul_fast => BinOp::Mul, + sym::fdiv_fast => BinOp::Div, + sym::frem_fast => BinOp::Rem, _ => unreachable!(), }, x, y); ret.write_cvalue(fx, res); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 27fc2abedc7..940d2514f74 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -13,8 +13,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let def_id = instance.def_id(); let substs = instance.substs; - let intrinsic = fx.tcx.item_name(def_id).as_str(); - let intrinsic = &intrinsic[..]; + let intrinsic = fx.tcx.item_name(def_id); intrinsic_match! { fx, intrinsic, substs, args, @@ -65,10 +64,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U - _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) { + _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) { validate_simd_type!(fx, intrinsic, span, x.layout().ty); - let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap(); + let n: u16 = intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 720d2a12534..32f40395702 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, decl_macro, never_type, hash_drain_filter)] +#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] @@ -23,7 +23,6 @@ extern crate rustc_target; extern crate rustc_driver; use std::any::Any; -use std::str::FromStr; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; @@ -34,9 +33,10 @@ use rustc_middle::ty::query::Providers; use rustc_session::config::OutputFilenames; use rustc_session::Session; +use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; -use crate::constant::ConstantCx; +pub use crate::config::*; use crate::prelude::*; mod abi; @@ -49,6 +49,7 @@ mod cast; mod codegen_i128; mod common; mod compiler_builtins; +mod config; mod constant; mod debuginfo; mod discriminant; @@ -87,7 +88,6 @@ mod prelude { pub(crate) use rustc_index::vec::Idx; - pub(crate) use cranelift_codegen::entity::EntitySet; pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC}; pub(crate) use cranelift_codegen::ir::function::Function; pub(crate) use cranelift_codegen::ir::types; @@ -119,95 +119,36 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> { } } -struct CodegenCx<'m, 'tcx: 'm> { +/// The codegen context holds any information shared between the codegen of individual functions +/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). +struct CodegenCx<'tcx> { tcx: TyCtxt<'tcx>, - module: &'m mut dyn Module, global_asm: String, - constants_cx: ConstantCx, cached_context: Context, - vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>, debug_context: Option<DebugContext<'tcx>>, - unwind_context: UnwindContext<'tcx>, + unwind_context: UnwindContext, } -impl<'m, 'tcx> CodegenCx<'m, 'tcx> { +impl<'tcx> CodegenCx<'tcx> { fn new( tcx: TyCtxt<'tcx>, backend_config: BackendConfig, - module: &'m mut dyn Module, + isa: &dyn TargetIsa, debug_info: bool, ) -> Self { - let unwind_context = UnwindContext::new( - tcx, - module.isa(), - matches!(backend_config.codegen_mode, CodegenMode::Aot), - ); - let debug_context = - if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None }; + assert_eq!(pointer_ty(tcx), isa.pointer_type()); + + let unwind_context = + UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); + let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None }; CodegenCx { tcx, - module, global_asm: String::new(), - constants_cx: ConstantCx::default(), cached_context: Context::new(), - vtables: FxHashMap::default(), debug_context, unwind_context, } } - - fn finalize(self) -> (String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) { - self.constants_cx.finalize(self.tcx, self.module); - (self.global_asm, self.debug_context, self.unwind_context) - } -} - -#[derive(Copy, Clone, Debug)] -pub enum CodegenMode { - Aot, - Jit, - JitLazy, -} - -impl Default for CodegenMode { - fn default() -> Self { - CodegenMode::Aot - } -} - -impl FromStr for CodegenMode { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "aot" => Ok(CodegenMode::Aot), - "jit" => Ok(CodegenMode::Jit), - "jit-lazy" => Ok(CodegenMode::JitLazy), - _ => Err(format!("Unknown codegen mode `{}`", s)), - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct BackendConfig { - pub codegen_mode: CodegenMode, -} - -impl BackendConfig { - fn from_opts(opts: &[String]) -> Result<Self, String> { - let mut config = BackendConfig::default(); - for opt in opts { - if let Some((name, value)) = opt.split_once('=') { - match name { - "mode" => config.codegen_mode = value.parse()?, - _ => return Err(format!("Unknown option `{}`", name)), - } - } else { - return Err(format!("Invalid option `{}`", opt)); - } - } - Ok(config) - } } pub struct CraneliftCodegenBackend { @@ -240,13 +181,23 @@ impl CodegenBackend for CraneliftCodegenBackend { metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box<dyn Any> { - let config = if let Some(config) = self.config { + tcx.sess.abort_if_errors(); + let config = if let Some(config) = self.config.clone() { config } else { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.fatal(&err)) }; - driver::codegen_crate(tcx, metadata, need_metadata_module, config) + match config.codegen_mode { + CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module), + CodegenMode::Jit | CodegenMode::JitLazy => { + #[cfg(feature = "jit")] + let _: ! = driver::jit::run_jit(tcx, config); + + #[cfg(not(feature = "jit"))] + tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift"); + } + } } fn join_codegen( @@ -284,7 +235,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple { sess.target.llvm_target.parse().unwrap() } -fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> { +fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); @@ -292,9 +243,8 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> { let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided - let enable_verifier = - cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok(); - flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap(); + let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" }; + flags_builder.set("enable_verifier", enable_verifier).unwrap(); let tls_model = match target_triple.binary_format { BinaryFormat::Elf => "elf_gd", @@ -322,10 +272,28 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> { let flags = settings::Flags::new(flags_builder); let variant = cranelift_codegen::isa::BackendVariant::MachInst; - let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); - // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt` - // is interpreted as `bsr`. - isa_builder.enable("nehalem").unwrap(); + + let isa_builder = match sess.opts.cg.target_cpu.as_deref() { + Some("native") => { + let builder = cranelift_native::builder_with_options(variant, true).unwrap(); + builder + } + Some(value) => { + let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); + if let Err(_) = builder.enable(value) { + sess.fatal("The specified target cpu isn't currently supported by Cranelift."); + } + builder + } + None => { + let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); + // Don't use "haswell" as the default, as it implies `has_lzcnt`. + // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`. + builder.enable("nehalem").unwrap(); + builder + } + }; + isa_builder.finish(flags) } diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs index a564a59f725..ca853aac158 100644 --- a/compiler/rustc_codegen_cranelift/src/linkage.rs +++ b/compiler/rustc_codegen_cranelift/src/linkage.rs @@ -13,6 +13,7 @@ pub(crate) fn get_clif_linkage( (RLinkage::External, Visibility::Default) => Linkage::Export, (RLinkage::Internal, Visibility::Default) => Linkage::Local, (RLinkage::External, Visibility::Hidden) => Linkage::Hidden, + (RLinkage::WeakAny, Visibility::Default) => Linkage::Preemptible, _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility), } } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index a6266f50776..d504024a335 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,6 +1,9 @@ use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_hir::LangItem; +use rustc_middle::ty::subst::GenericArg; +use rustc_middle::ty::AssocKind; use rustc_session::config::EntryFnType; +use rustc_span::symbol::Ident; use crate::prelude::*; @@ -9,11 +12,12 @@ use crate::prelude::*; pub(crate) fn maybe_create_entry_wrapper( tcx: TyCtxt<'_>, module: &mut impl Module, - unwind_context: &mut UnwindContext<'_>, + unwind_context: &mut UnwindContext, + is_jit: bool, ) { - let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) { + let (main_def_id, is_main_fn) = match tcx.entry_fn(LOCAL_CRATE) { Some((def_id, entry_ty)) => ( - def_id.to_def_id(), + def_id, match entry_ty { EntryFnType::Main => true, EntryFnType::Start => false, @@ -23,18 +27,19 @@ pub(crate) fn maybe_create_entry_wrapper( }; let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx); - if module.get_name(&*tcx.symbol_name(instance).name).is_none() { + if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() { return; } - create_entry_fn(tcx, module, unwind_context, main_def_id, use_start_lang_item); + create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn); fn create_entry_fn( tcx: TyCtxt<'_>, m: &mut impl Module, - unwind_context: &mut UnwindContext<'_>, + unwind_context: &mut UnwindContext, rust_main_def_id: DefId, - use_start_lang_item: bool, + ignore_lang_start_wrapper: bool, + is_main_fn: bool, ) { let main_ret_ty = tcx.fn_sig(rust_main_def_id).output(); // Given that `main()` has no arguments, @@ -57,9 +62,9 @@ pub(crate) fn maybe_create_entry_wrapper( let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx); - let main_name = tcx.symbol_name(instance).name.to_string(); + let main_name = tcx.symbol_name(instance).name; let main_sig = get_function_sig(tcx, m.isa().triple(), instance); - let main_func_id = m.declare_function(&main_name, Linkage::Import, &main_sig).unwrap(); + let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap(); let mut ctx = Context::new(); ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig); @@ -74,7 +79,47 @@ pub(crate) fn maybe_create_entry_wrapper( let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); - let call_inst = if use_start_lang_item { + let result = if is_main_fn && ignore_lang_start_wrapper { + // regular main fn, but ignoring #[lang = "start"] as we are running in the jit + // FIXME set program arguments somehow + let call_inst = bcx.ins().call(main_func_ref, &[]); + let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); + + let termination_trait = tcx.require_lang_item(LangItem::Termination, None); + let report = tcx + .associated_items(termination_trait) + .find_by_name_and_kind( + tcx, + Ident::from_str("report"), + AssocKind::Fn, + termination_trait, + ) + .unwrap(); + let report = Instance::resolve( + tcx, + ParamEnv::reveal_all(), + report.def_id, + tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()), + ) + .unwrap() + .unwrap(); + + let report_name = tcx.symbol_name(report).name; + let report_sig = get_function_sig(tcx, m.isa().triple(), report); + let report_func_id = + m.declare_function(report_name, Linkage::Import, &report_sig).unwrap(); + let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func); + + // FIXME do proper abi handling instead of expecting the pass mode to be identical + // for returns and arguments. + let report_call_inst = bcx.ins().call(report_func_ref, &call_results); + let res = bcx.func.dfg.inst_results(report_call_inst)[0]; + match m.target_config().pointer_type() { + types::I32 => res, + types::I64 => bcx.ins().sextend(types::I64, res), + _ => unimplemented!("16bit systems are not yet supported"), + } + } else if is_main_fn { let start_def_id = tcx.require_lang_item(LangItem::Start, None); let start_instance = Instance::resolve( tcx, @@ -90,13 +135,14 @@ pub(crate) fn maybe_create_entry_wrapper( let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref); let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func); - bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]) + let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]); + bcx.inst_results(call_inst)[0] } else { // using user-defined start fn - bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]) + let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]); + bcx.inst_results(call_inst)[0] }; - let result = bcx.inst_results(call_inst)[0]; bcx.ins().return_(&[result]); bcx.seal_all_blocks(); bcx.finalize(); diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index dbdc8cbad44..882232fde09 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -8,13 +8,24 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader}; +use rustc_middle::middle::cstore::MetadataLoader; use rustc_middle::ty::TyCtxt; -use rustc_session::config; use rustc_target::spec::Target; use crate::backend::WriteMetadata; +/// The metadata loader used by cg_clif. +/// +/// The metadata is stored in the same format as cg_llvm. +/// +/// # Metadata location +/// +/// <dl> +/// <dt>rlib</dt> +/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd> +/// <dt>dylib</dt> +/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd> +/// </dl> pub(crate) struct CraneliftMetadataLoader; fn load_metadata_with( @@ -58,54 +69,16 @@ impl MetadataLoader for CraneliftMetadataLoader { } // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 -pub(crate) fn write_metadata<P: WriteMetadata>( - tcx: TyCtxt<'_>, - product: &mut P, -) -> EncodedMetadata { +pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) { use snap::write::FrameEncoder; use std::io::Write; - #[derive(PartialEq, Eq, PartialOrd, Ord)] - enum MetadataKind { - None, - Uncompressed, - Compressed, - } - - let kind = tcx - .sess - .crate_types() - .iter() - .map(|ty| match *ty { - config::CrateType::Executable - | config::CrateType::Staticlib - | config::CrateType::Cdylib => MetadataKind::None, - - config::CrateType::Rlib => MetadataKind::Uncompressed, - - config::CrateType::Dylib | config::CrateType::ProcMacro => MetadataKind::Compressed, - }) - .max() - .unwrap_or(MetadataKind::None); - - if kind == MetadataKind::None { - return EncodedMetadata::new(); - } - let metadata = tcx.encode_metadata(); - if kind == MetadataKind::Uncompressed { - return metadata; - } - - assert!(kind == MetadataKind::Compressed); let mut compressed = tcx.metadata_encoding_version(); FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); - product.add_rustc_section( + object.add_rustc_section( rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), compressed, - tcx.sess.target.is_like_osx, ); - - metadata } diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 2ebf30da2d8..b6d378a5fe1 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -271,14 +271,17 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( let val_hi = fx.bcx.ins().umulhi(lhs, rhs); fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0) } else { + // Based on LLVM's instruction sequence for compiling + // a.checked_mul(b).is_some() to riscv64gc: + // mulh a2, a0, a1 + // mul a0, a0, a1 + // srai a0, a0, 63 + // xor a0, a0, a2 + // snez a0, a0 let val_hi = fx.bcx.ins().smulhi(lhs, rhs); - let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0); - let not_all_ones = fx.bcx.ins().icmp_imm( - IntCC::NotEqual, - val_hi, - u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64, - ); - fx.bcx.ins().band(not_all_zero, not_all_ones) + let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1)); + let xor = fx.bcx.ins().bxor(val_hi, val_sign); + fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0) }; (val, has_overflow) } diff --git a/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs b/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs deleted file mode 100644 index ca9ff15ec10..00000000000 --- a/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! This optimization moves cold code to the end of the function. -//! -//! Some code is executed much less often than other code. For example panicking or the -//! landingpads for unwinding. By moving this cold code to the end of the function the average -//! amount of jumps is reduced and the code locality is improved. -//! -//! # Undefined behaviour -//! -//! This optimization doesn't assume anything that isn't already assumed by Cranelift itself. - -use crate::prelude::*; - -pub(super) fn optimize_function(ctx: &mut Context, cold_blocks: &EntitySet<Block>) { - // FIXME Move the block in place instead of remove and append once - // bytecodealliance/cranelift#1339 is implemented. - - let mut block_insts = FxHashMap::default(); - for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) { - let insts = ctx.func.layout.block_insts(block).collect::<Vec<_>>(); - for &inst in &insts { - ctx.func.layout.remove_inst(inst); - } - block_insts.insert(block, insts); - ctx.func.layout.remove_block(block); - } - - // And then append them at the back again. - for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) { - ctx.func.layout.append_block(block); - for inst in block_insts.remove(&block).unwrap() { - ctx.func.layout.append_inst(inst, block); - } - } -} diff --git a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs index 389f50e797e..137fb5f7731 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/mod.rs @@ -2,29 +2,16 @@ use crate::prelude::*; -mod code_layout; pub(crate) mod peephole; -mod stack2reg; pub(crate) fn optimize_function<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, ctx: &mut Context, - cold_blocks: &EntitySet<Block>, clif_comments: &mut crate::pretty_clif::CommentWriter, ) { - // The code_layout optimization is very cheap. - self::code_layout::optimize_function(ctx, cold_blocks); + // FIXME classify optimizations over opt levels once we have more - if tcx.sess.opts.optimize == rustc_session::config::OptLevel::No { - return; // FIXME classify optimizations over opt levels - } - - // FIXME(#1142) stack2reg miscompiles lewton - if false { - self::stack2reg::optimize_function(ctx, clif_comments); - } - - crate::pretty_clif::write_clif_file(tcx, "stack2reg", None, instance, &ctx, &*clif_comments); + crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments); crate::base::verify_func(tcx, &*clif_comments, &ctx.func); } diff --git a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs deleted file mode 100644 index 8bb02a3e558..00000000000 --- a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs +++ /dev/null @@ -1,486 +0,0 @@ -//! This optimization replaces stack accesses with SSA variables and removes dead stores when possible. -//! -//! # Undefined behaviour -//! -//! This optimization is based on the assumption that stack slots which don't have their address -//! leaked through `stack_addr` are only accessed using `stack_load` and `stack_store` in the -//! function which has the stack slots. This optimization also assumes that stack slot accesses -//! are never out of bounds. If these assumptions are not correct, then this optimization may remove -//! `stack_store` instruction incorrectly, or incorrectly use a previously stored value as the value -//! being loaded by a `stack_load`. - -use std::collections::BTreeMap; -use std::fmt; -use std::ops::Not; - -use rustc_data_structures::fx::FxHashSet; - -use cranelift_codegen::cursor::{Cursor, FuncCursor}; -use cranelift_codegen::ir::immediates::Offset32; -use cranelift_codegen::ir::{InstructionData, Opcode, ValueDef}; - -use crate::prelude::*; - -/// Workaround for `StackSlot` not implementing `Ord`. -#[derive(Copy, Clone, PartialEq, Eq)] -struct OrdStackSlot(StackSlot); - -impl fmt::Debug for OrdStackSlot { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - -impl PartialOrd for OrdStackSlot { - fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> { - self.0.as_u32().partial_cmp(&rhs.0.as_u32()) - } -} - -impl Ord for OrdStackSlot { - fn cmp(&self, rhs: &Self) -> std::cmp::Ordering { - self.0.as_u32().cmp(&rhs.0.as_u32()) - } -} - -#[derive(Debug, Default)] -struct StackSlotUsage { - stack_addr: FxHashSet<Inst>, - stack_load: FxHashSet<Inst>, - stack_store: FxHashSet<Inst>, -} - -impl StackSlotUsage { - fn potential_stores_for_load(&self, ctx: &Context, load: Inst) -> Vec<Inst> { - self.stack_store - .iter() - .cloned() - .filter(|&store| { - match spatial_overlap(&ctx.func, store, load) { - SpatialOverlap::No => false, // Can never be the source of the loaded value. - SpatialOverlap::Partial | SpatialOverlap::Full => true, - } - }) - .filter(|&store| { - match temporal_order(ctx, store, load) { - TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value. - TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true, - } - }) - .collect::<Vec<Inst>>() - } - - fn potential_loads_of_store(&self, ctx: &Context, store: Inst) -> Vec<Inst> { - self.stack_load - .iter() - .cloned() - .filter(|&load| { - match spatial_overlap(&ctx.func, store, load) { - SpatialOverlap::No => false, // Can never be the source of the loaded value. - SpatialOverlap::Partial | SpatialOverlap::Full => true, - } - }) - .filter(|&load| { - match temporal_order(ctx, store, load) { - TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value. - TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true, - } - }) - .collect::<Vec<Inst>>() - } - - fn remove_unused_stack_addr(func: &mut Function, inst: Inst) { - func.dfg.detach_results(inst); - func.dfg.replace(inst).nop(); - } - - fn remove_unused_load(func: &mut Function, load: Inst) { - func.dfg.detach_results(load); - func.dfg.replace(load).nop(); - } - - fn remove_dead_store(&mut self, func: &mut Function, store: Inst) { - func.dfg.replace(store).nop(); - self.stack_store.remove(&store); - } - - fn change_load_to_alias(&mut self, func: &mut Function, load: Inst, value: Value) { - let loaded_value = func.dfg.inst_results(load)[0]; - let loaded_type = func.dfg.value_type(loaded_value); - - if func.dfg.value_type(value) == loaded_type { - func.dfg.detach_results(load); - func.dfg.replace(load).nop(); - func.dfg.change_to_alias(loaded_value, value); - } else { - func.dfg.replace(load).bitcast(loaded_type, value); - } - - self.stack_load.remove(&load); - } -} - -struct OptimizeContext<'a> { - ctx: &'a mut Context, - stack_slot_usage_map: BTreeMap<OrdStackSlot, StackSlotUsage>, -} - -impl<'a> OptimizeContext<'a> { - fn for_context(ctx: &'a mut Context) -> Self { - ctx.flowgraph(); // Compute cfg and domtree. - - // Record all stack_addr, stack_load and stack_store instructions. - let mut stack_slot_usage_map = BTreeMap::<OrdStackSlot, StackSlotUsage>::new(); - - let mut cursor = FuncCursor::new(&mut ctx.func); - while let Some(_block) = cursor.next_block() { - while let Some(inst) = cursor.next_inst() { - match cursor.func.dfg[inst] { - InstructionData::StackLoad { - opcode: Opcode::StackAddr, - stack_slot, - offset: _, - } => { - stack_slot_usage_map - .entry(OrdStackSlot(stack_slot)) - .or_insert_with(StackSlotUsage::default) - .stack_addr - .insert(inst); - } - InstructionData::StackLoad { - opcode: Opcode::StackLoad, - stack_slot, - offset: _, - } => { - stack_slot_usage_map - .entry(OrdStackSlot(stack_slot)) - .or_insert_with(StackSlotUsage::default) - .stack_load - .insert(inst); - } - InstructionData::StackStore { - opcode: Opcode::StackStore, - arg: _, - stack_slot, - offset: _, - } => { - stack_slot_usage_map - .entry(OrdStackSlot(stack_slot)) - .or_insert_with(StackSlotUsage::default) - .stack_store - .insert(inst); - } - _ => {} - } - } - } - - OptimizeContext { ctx, stack_slot_usage_map } - } -} - -pub(super) fn optimize_function( - ctx: &mut Context, - clif_comments: &mut crate::pretty_clif::CommentWriter, -) { - combine_stack_addr_with_load_store(&mut ctx.func); - - let mut opt_ctx = OptimizeContext::for_context(ctx); - - // FIXME Repeat following instructions until fixpoint. - - remove_unused_stack_addr_and_stack_load(&mut opt_ctx); - - if clif_comments.enabled() { - for (&OrdStackSlot(stack_slot), usage) in &opt_ctx.stack_slot_usage_map { - clif_comments.add_comment(stack_slot, format!("used by: {:?}", usage)); - } - } - - for (stack_slot, users) in opt_ctx.stack_slot_usage_map.iter_mut() { - if users.stack_addr.is_empty().not() { - // Stack addr leaked; there may be unknown loads and stores. - // FIXME use stacked borrows to optimize - continue; - } - - for load in users.stack_load.clone().into_iter() { - let potential_stores = users.potential_stores_for_load(&opt_ctx.ctx, load); - - if clif_comments.enabled() { - for &store in &potential_stores { - clif_comments.add_comment( - load, - format!( - "Potential store -> load forwarding {} -> {} ({:?}, {:?})", - opt_ctx.ctx.func.dfg.display_inst(store, None), - opt_ctx.ctx.func.dfg.display_inst(load, None), - spatial_overlap(&opt_ctx.ctx.func, store, load), - temporal_order(&opt_ctx.ctx, store, load), - ), - ); - } - } - - match *potential_stores { - [] => { - if clif_comments.enabled() { - clif_comments - .add_comment(load, "[BUG?] Reading uninitialized memory".to_string()); - } - } - [store] - if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full - && temporal_order(&opt_ctx.ctx, store, load) - == TemporalOrder::DefinitivelyBefore => - { - // Only one store could have been the origin of the value. - let stored_value = opt_ctx.ctx.func.dfg.inst_args(store)[0]; - - if clif_comments.enabled() { - clif_comments.add_comment( - load, - format!("Store to load forward {} -> {}", store, load), - ); - } - - users.change_load_to_alias(&mut opt_ctx.ctx.func, load, stored_value); - } - _ => {} // FIXME implement this - } - } - - for store in users.stack_store.clone().into_iter() { - let potential_loads = users.potential_loads_of_store(&opt_ctx.ctx, store); - - if clif_comments.enabled() { - for &load in &potential_loads { - clif_comments.add_comment( - store, - format!( - "Potential load from store {} <- {} ({:?}, {:?})", - opt_ctx.ctx.func.dfg.display_inst(load, None), - opt_ctx.ctx.func.dfg.display_inst(store, None), - spatial_overlap(&opt_ctx.ctx.func, store, load), - temporal_order(&opt_ctx.ctx, store, load), - ), - ); - } - } - - if potential_loads.is_empty() { - // Never loaded; can safely remove all stores and the stack slot. - // FIXME also remove stores when there is always a next store before a load. - - if clif_comments.enabled() { - clif_comments.add_comment( - store, - format!( - "Remove dead stack store {} of {}", - opt_ctx.ctx.func.dfg.display_inst(store, None), - stack_slot.0 - ), - ); - } - - users.remove_dead_store(&mut opt_ctx.ctx.func, store); - } - } - - if users.stack_store.is_empty() && users.stack_load.is_empty() { - opt_ctx.ctx.func.stack_slots[stack_slot.0].size = 0; - } - } -} - -fn combine_stack_addr_with_load_store(func: &mut Function) { - // Turn load and store into stack_load and stack_store when possible. - let mut cursor = FuncCursor::new(func); - while let Some(_block) = cursor.next_block() { - while let Some(inst) = cursor.next_inst() { - match cursor.func.dfg[inst] { - InstructionData::Load { opcode: Opcode::Load, arg: addr, flags: _, offset } => { - if cursor.func.dfg.ctrl_typevar(inst) == types::I128 - || cursor.func.dfg.ctrl_typevar(inst).is_vector() - { - continue; // WORKAROUD: stack_load.i128 not yet implemented - } - if let Some((stack_slot, stack_addr_offset)) = - try_get_stack_slot_and_offset_for_addr(cursor.func, addr) - { - if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into()) - { - let ty = cursor.func.dfg.ctrl_typevar(inst); - cursor.func.dfg.replace(inst).stack_load( - ty, - stack_slot, - combined_offset, - ); - } - } - } - InstructionData::Store { - opcode: Opcode::Store, - args: [value, addr], - flags: _, - offset, - } => { - if cursor.func.dfg.ctrl_typevar(inst) == types::I128 - || cursor.func.dfg.ctrl_typevar(inst).is_vector() - { - continue; // WORKAROUND: stack_store.i128 not yet implemented - } - if let Some((stack_slot, stack_addr_offset)) = - try_get_stack_slot_and_offset_for_addr(cursor.func, addr) - { - if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into()) - { - cursor.func.dfg.replace(inst).stack_store( - value, - stack_slot, - combined_offset, - ); - } - } - } - _ => {} - } - } - } -} - -fn remove_unused_stack_addr_and_stack_load(opt_ctx: &mut OptimizeContext<'_>) { - // FIXME incrementally rebuild on each call? - let mut stack_addr_load_insts_users = FxHashMap::<Inst, FxHashSet<Inst>>::default(); - - let mut cursor = FuncCursor::new(&mut opt_ctx.ctx.func); - while let Some(_block) = cursor.next_block() { - while let Some(inst) = cursor.next_inst() { - for &arg in cursor.func.dfg.inst_args(inst) { - if let ValueDef::Result(arg_origin, 0) = cursor.func.dfg.value_def(arg) { - match cursor.func.dfg[arg_origin].opcode() { - Opcode::StackAddr | Opcode::StackLoad => { - stack_addr_load_insts_users - .entry(arg_origin) - .or_insert_with(FxHashSet::default) - .insert(inst); - } - _ => {} - } - } - } - } - } - - #[cfg(debug_assertions)] - for inst in stack_addr_load_insts_users.keys() { - let mut is_recorded_stack_addr_or_stack_load = false; - for stack_slot_users in opt_ctx.stack_slot_usage_map.values() { - is_recorded_stack_addr_or_stack_load |= stack_slot_users.stack_addr.contains(inst) - || stack_slot_users.stack_load.contains(inst); - } - assert!(is_recorded_stack_addr_or_stack_load); - } - - // Replace all unused stack_addr and stack_load instructions with nop. - let mut func = &mut opt_ctx.ctx.func; - - for stack_slot_users in opt_ctx.stack_slot_usage_map.values_mut() { - stack_slot_users - .stack_addr - .drain_filter(|inst| { - stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true) - }) - .for_each(|inst| StackSlotUsage::remove_unused_stack_addr(&mut func, inst)); - - stack_slot_users - .stack_load - .drain_filter(|inst| { - stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true) - }) - .for_each(|inst| StackSlotUsage::remove_unused_load(&mut func, inst)); - } -} - -fn try_get_stack_slot_and_offset_for_addr( - func: &Function, - addr: Value, -) -> Option<(StackSlot, Offset32)> { - if let ValueDef::Result(addr_inst, 0) = func.dfg.value_def(addr) { - if let InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset } = - func.dfg[addr_inst] - { - return Some((stack_slot, offset)); - } - } - None -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum SpatialOverlap { - No, - Partial, - Full, -} - -fn spatial_overlap(func: &Function, src: Inst, dest: Inst) -> SpatialOverlap { - fn inst_info(func: &Function, inst: Inst) -> (StackSlot, Offset32, u32) { - match func.dfg[inst] { - InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset } - | InstructionData::StackLoad { opcode: Opcode::StackLoad, stack_slot, offset } - | InstructionData::StackStore { - opcode: Opcode::StackStore, - stack_slot, - offset, - arg: _, - } => (stack_slot, offset, func.dfg.ctrl_typevar(inst).bytes()), - _ => unreachable!("{:?}", func.dfg[inst]), - } - } - - debug_assert_ne!(src, dest); - - let (src_ss, src_offset, src_size) = inst_info(func, src); - let (dest_ss, dest_offset, dest_size) = inst_info(func, dest); - - if src_ss != dest_ss { - return SpatialOverlap::No; - } - - if src_offset == dest_offset && src_size == dest_size { - return SpatialOverlap::Full; - } - - let src_end: i64 = src_offset.try_add_i64(i64::from(src_size)).unwrap().into(); - let dest_end: i64 = dest_offset.try_add_i64(i64::from(dest_size)).unwrap().into(); - if src_end <= dest_offset.into() || dest_end <= src_offset.into() { - return SpatialOverlap::No; - } - - SpatialOverlap::Partial -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum TemporalOrder { - /// `src` will never be executed before `dest`. - NeverBefore, - - /// `src` may be executed before `dest`. - MaybeBefore, - - /// `src` will always be executed before `dest`. - /// There may still be other instructions in between. - DefinitivelyBefore, -} - -fn temporal_order(ctx: &Context, src: Inst, dest: Inst) -> TemporalOrder { - debug_assert_ne!(src, dest); - - if ctx.domtree.dominates(src, dest, &ctx.func.layout) { - TemporalOrder::DefinitivelyBefore - } else if ctx.domtree.dominates(src, dest, &ctx.func.layout) { - TemporalOrder::NeverBefore - } else { - TemporalOrder::MaybeBefore - } -} diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index d22ea3772ee..158811c5eaf 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -207,7 +207,7 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { pub(crate) fn write_ir_file( tcx: TyCtxt<'_>, - name: &str, + name: impl FnOnce() -> String, write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>, ) { if !should_write_ir(tcx) { @@ -222,7 +222,7 @@ pub(crate) fn write_ir_file( res @ Err(_) => res.unwrap(), } - let clif_file_name = clif_output_dir.join(name); + let clif_file_name = clif_output_dir.join(name()); let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file)); if let Err(err) = res { @@ -238,30 +238,31 @@ pub(crate) fn write_clif_file<'tcx>( context: &cranelift_codegen::Context, mut clif_comments: &CommentWriter, ) { - write_ir_file(tcx, &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), |file| { - let value_ranges = - isa.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges")); + write_ir_file( + tcx, + || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), + |file| { + let value_ranges = isa + .map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges")); - let mut clif = String::new(); - cranelift_codegen::write::decorate_function( - &mut clif_comments, - &mut clif, - &context.func, - &DisplayFunctionAnnotations { - isa: Some(&*crate::build_isa(tcx.sess)), - value_ranges: value_ranges.as_ref(), - }, - ) - .unwrap(); + let mut clif = String::new(); + cranelift_codegen::write::decorate_function( + &mut clif_comments, + &mut clif, + &context.func, + &DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() }, + ) + .unwrap(); - writeln!(file, "test compile")?; - writeln!(file, "set is_pic")?; - writeln!(file, "set enable_simd")?; - writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?; - writeln!(file)?; - file.write_all(clif.as_bytes())?; - Ok(()) - }); + writeln!(file, "test compile")?; + writeln!(file, "set is_pic")?; + writeln!(file, "set enable_simd")?; + writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?; + writeln!(file)?; + file.write_all(clif.as_bytes())?; + Ok(()) + }, + ); } impl fmt::Debug for FunctionCx<'_, '_, '_> { diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 1ab0703e981..819c8b51558 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -4,7 +4,6 @@ use crate::prelude::*; fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { let puts = fx - .cx .module .declare_function( "puts", @@ -16,13 +15,12 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { }, ) .unwrap(); - let puts = fx.cx.module.declare_func_in_func(puts, &mut fx.bcx.func); + let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func); if fx.clif_comments.enabled() { fx.add_comment(puts, "puts"); } - let symbol_name = fx.tcx.symbol_name(fx.instance); - let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg); + let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg); let msg_ptr = fx.anonymous_str("trap", &real_msg); fx.bcx.ins().call(puts, &[msg_ptr]); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index b97d3900984..9a572c3501f 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -554,7 +554,7 @@ impl<'tcx> CPlace<'tcx> { let src_align = src_layout.align.abi.bytes() as u8; let dst_align = dst_layout.align.abi.bytes() as u8; fx.bcx.emit_small_memory_copy( - fx.cx.module.target_config(), + fx.module.target_config(), to_addr, from_addr, size, diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 9053d1aa1b0..bbf07ffc85d 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -72,15 +72,15 @@ pub(crate) fn get_vtable<'tcx>( layout: TyAndLayout<'tcx>, trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, ) -> Value { - let data_id = if let Some(data_id) = fx.cx.vtables.get(&(layout.ty, trait_ref)) { + let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) { *data_id } else { let data_id = build_vtable(fx, layout, trait_ref); - fx.cx.vtables.insert((layout.ty, trait_ref), data_id); + fx.vtables.insert((layout.ty, trait_ref), data_id); data_id }; - let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); + let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } @@ -94,7 +94,7 @@ fn build_vtable<'tcx>( let drop_in_place_fn = import_function( tcx, - fx.cx.module, + fx.module, Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx), ); @@ -111,7 +111,7 @@ fn build_vtable<'tcx>( opt_mth.map(|(def_id, substs)| { import_function( tcx, - fx.cx.module, + fx.module, Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs) .unwrap() .polymorphize(fx.tcx), @@ -132,34 +132,16 @@ fn build_vtable<'tcx>( for (i, component) in components.into_iter().enumerate() { if let Some(func_id) = component { - let func_ref = fx.cx.module.declare_func_in_data(func_id, &mut data_ctx); + let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx); data_ctx.write_function_addr((i * usize_size) as u32, func_ref); } } data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes()); - let data_id = fx - .cx - .module - .declare_data( - &format!( - "__vtable.{}.for.{:?}.{}", - trait_ref - .as_ref() - .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into()) - .unwrap_or(std::borrow::Cow::Borrowed("???")), - layout.ty, - fx.cx.vtables.len(), - ), - Linkage::Local, - false, - false, - ) - .unwrap(); - - // FIXME don't duplicate definitions in lazy jit mode - let _ = fx.cx.module.define_data(data_id, &data_ctx); + let data_id = fx.module.declare_anonymous_data(false, false).unwrap(); + + fx.module.define_data(data_id, &data_ctx).unwrap(); data_id } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 2ac814bf228..1faaa7e86f6 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -8,6 +8,7 @@ use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_llvm::RustString; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::CodeRegion; use rustc_span::Symbol; @@ -280,6 +281,10 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default(); for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { + let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + continue; + } // Make sure the non-codegenned (unused) function has a file_name if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) { let def_ids = diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index e6fa852155b..280d9a4d370 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -309,6 +309,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> { unfinished_type, member_holding_stub, member_descriptions, + None, ); MetadataCreationResult::new(metadata_stub, true) } @@ -1459,6 +1460,7 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { layout: TyAndLayout<'tcx>, tag_type_metadata: Option<&'ll DIType>, containing_scope: &'ll DIScope, + common_members: Vec<Option<&'ll DIType>>, span: Span, } @@ -1493,10 +1495,6 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } else { type_metadata(cx, self.enum_type, self.span) }; - let flags = match self.enum_type.kind() { - ty::Generator(..) => DIFlags::FlagArtificial, - _ => DIFlags::FlagZero, - }; match self.layout.variants { Variants::Single { index } => { @@ -1523,6 +1521,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.enum_type, variant_type_metadata, member_descriptions, + Some(&self.common_members), ); vec![MemberDescription { name: if fallback { String::new() } else { variant_info.variant_name() }, @@ -1530,7 +1529,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags, + flags: DIFlags::FlagZero, discriminant: None, source_info: variant_info.source_info(cx), }] @@ -1572,6 +1571,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.enum_type, variant_type_metadata, member_descriptions, + Some(&self.common_members), ); MemberDescription { @@ -1584,7 +1584,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags, + flags: DIFlags::FlagZero, discriminant: Some( self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val as u64, @@ -1621,6 +1621,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.enum_type, variant_type_metadata, variant_member_descriptions, + Some(&self.common_members), ); // Encode the information about the null variant in the union @@ -1667,7 +1668,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: variant.size, align: variant.align.abi, - flags, + flags: DIFlags::FlagZero, discriminant: None, source_info: variant_info.source_info(cx), }] @@ -1695,6 +1696,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { self.enum_type, variant_type_metadata, member_descriptions, + Some(&self.common_members), ); let niche_value = if i == dataful_variant { @@ -1717,7 +1719,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { offset: Size::ZERO, size: self.layout.size, align: self.layout.align.abi, - flags, + flags: DIFlags::FlagZero, discriminant: niche_value, source_info: variant_info.source_info(cx), } @@ -1849,13 +1851,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> { } None } - - fn is_artificial(&self) -> bool { - match self { - VariantInfo::Generator { .. } => true, - VariantInfo::Adt(..) => false, - } - } } /// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a @@ -1881,8 +1876,7 @@ fn describe_enum_variant( &variant_name, unique_type_id, Some(containing_scope), - // FIXME(tmandry): This doesn't seem to have any effect. - if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero }, + DIFlags::FlagZero, ) }); @@ -1945,11 +1939,6 @@ fn prepare_enum_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let tcx = cx.tcx; let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); - // FIXME(tmandry): This doesn't seem to have any effect. - let enum_flags = match enum_type.kind() { - ty::Generator(..) => DIFlags::FlagArtificial, - _ => DIFlags::FlagZero, - }; let containing_scope = get_namespace_for_item(cx, enum_def_id); // FIXME: This should emit actual file metadata for the enum, but we @@ -2082,7 +2071,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - enum_flags, + DIFlags::FlagZero, None, 0, // RuntimeLang unique_type_id_str.as_ptr().cast(), @@ -2102,6 +2091,7 @@ fn prepare_enum_metadata( layout, tag_type_metadata: discriminant_type_metadata, containing_scope, + common_members: vec![], span, }), ); @@ -2171,7 +2161,7 @@ fn prepare_enum_metadata( } }; - let mut outer_fields = match layout.variants { + let outer_fields = match layout.variants { Variants::Single { .. } => vec![], Variants::Multiple { .. } => { let tuple_mdf = TupleMemberDescriptionFactory { @@ -2203,18 +2193,21 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - enum_flags, + DIFlags::FlagZero, discriminator_metadata, empty_array, variant_part_unique_type_id_str.as_ptr().cast(), variant_part_unique_type_id_str.len(), ) }; - outer_fields.push(Some(variant_part)); let struct_wrapper = { // The variant part must be wrapped in a struct according to DWARF. - let type_array = create_DIArray(DIB(cx), &outer_fields); + // All fields except the discriminant (including `outer_fields`) + // should be put into structures inside the variant part, which gives + // an equivalent layout but offers us much better integration with + // debuggers. + let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]); let type_map = debug_context(cx).type_map.borrow(); let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); @@ -2229,7 +2222,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, layout.size.bits(), layout.align.abi.bits() as u32, - enum_flags, + DIFlags::FlagZero, None, type_array, 0, @@ -2251,6 +2244,7 @@ fn prepare_enum_metadata( layout, tag_type_metadata: None, containing_scope, + common_members: outer_fields, span, }), ) @@ -2283,7 +2277,13 @@ fn composite_type_metadata( DIFlags::FlagZero, ); // ... and immediately create and add the member descriptions. - set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions); + set_members_of_composite_type( + cx, + composite_type, + composite_type_metadata, + member_descriptions, + None, + ); composite_type_metadata } @@ -2293,6 +2293,7 @@ fn set_members_of_composite_type( composite_type: Ty<'tcx>, composite_type_metadata: &'ll DICompositeType, member_descriptions: Vec<MemberDescription<'ll>>, + common_members: Option<&Vec<Option<&'ll DIType>>>, ) { // In some rare cases LLVM metadata uniquing would lead to an existing type // description being used instead of a new one created in @@ -2311,10 +2312,13 @@ fn set_members_of_composite_type( } } - let member_metadata: Vec<_> = member_descriptions + let mut member_metadata: Vec<_> = member_descriptions .into_iter() .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata))) .collect(); + if let Some(other_members) = common_members { + member_metadata.extend(other_members.iter()); + } let type_params = compute_type_parameters(cx, composite_type); unsafe { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index e157a38aa03..b928e903730 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -344,7 +344,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { spflags |= DISPFlags::SPFlagOptimized; } if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { - if id.to_def_id() == def_id { + if id == def_id { spflags |= DISPFlags::SPFlagMainSubprogram; } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 318eed76acf..e045a23eb0c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{par_iter, ParallelIterator}; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -348,12 +348,29 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, ) -> Option<Bx::Function> { let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?; - let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id()); + let main_is_local = main_def_id.is_local(); + let instance = Instance::mono(cx.tcx(), main_def_id); - if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { + if main_is_local { // We want to create the wrapper in the same codegen unit as Rust's main // function. - return None; + if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) { + return None; + } + } else { + // FIXME: Add support for non-local main fn codegen + let span = cx.tcx().main_def.unwrap().span; + let n = 28937; + cx.sess() + .struct_span_err(span, "entry symbol `main` from foreign crate is not yet supported.") + .note(&format!( + "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \ + for more information", + n, n, + )) + .emit(); + cx.sess().abort_if_errors(); + bug!(); } let main_llfn = cx.get_fn_addr(instance); @@ -366,7 +383,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, rust_main: Bx::Value, - rust_main_def_id: LocalDefId, + rust_main_def_id: DefId, use_start_lang_item: bool, ) -> Bx::Function { // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 507425d64e3..aa95ecbdaf9 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,6 @@ tempfile = "3.2" [dependencies.parking_lot] version = "0.11" -features = ["nightly"] [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "psapi"] } diff --git a/compiler/rustc_error_codes/src/error_codes/E0136.md b/compiler/rustc_error_codes/src/error_codes/E0136.md index b91b52c074c..15cf09a18cb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0136.md +++ b/compiler/rustc_error_codes/src/error_codes/E0136.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + More than one `main` function was found. Erroneous code example: -```compile_fail,E0136 +```compile_fail fn main() { // ... } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 529ef7e4611..3347c93948c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -20,7 +20,7 @@ use rustc_attr::{self as attr, is_builtin_attr}; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma}; use rustc_parse::validate_attr; @@ -414,6 +414,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.article(), kind.descr() ), ); + // FIXME: this workaround issue #84569 + FatalError.raise(); } }; self.cx.trace_macros_diag(); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index bc45c57596e..91d4a0f0d65 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -955,15 +955,15 @@ fn check_matcher_core( if let TokenTree::MetaVarDecl(span, name, Some(kind)) = *token { for next_token in &suffix_first.tokens { // Check if the old pat is used and the next token is `|`. - if let NonterminalKind::Pat2015 { inferred: true } = kind { + if let NonterminalKind::PatParam { inferred: true } = kind { if let TokenTree::Token(token) = next_token { if let BinOp(token) = token.kind { if let token::BinOpToken::Or = token { - // It is suggestion to use pat2015, for example: $x:pat -> $x:pat2015. + // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param. let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( span, name, - Some(NonterminalKind::Pat2015 { inferred: false }), + Some(NonterminalKind::PatParam { inferred: false }), )); sess.buffer_lint_with_diagnostic( &OR_PATTERNS_BACK_COMPAT, @@ -1105,7 +1105,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::Pat2015 { .. } => { + NonterminalKind::PatParam { .. } => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { @@ -1116,7 +1116,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { _ => IsInFollow::No(TOKENS), } } - NonterminalKind::Pat2021 { .. } => { + NonterminalKind::PatWithOr { .. } => { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index e205cb65d02..aca02ef93f8 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -6,8 +6,8 @@ use rustc_ast::tokenstream; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_feature::Features; -use rustc_session::parse::{feature_err, ParseSess}; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_session::parse::ParseSess; +use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; @@ -62,21 +62,6 @@ pub(super) fn parse( Some((frag, _)) => { let span = token.span.with_lo(start_sp.lo()); - match frag.name { - sym::pat2015 | sym::pat2021 => { - if !features.edition_macro_pats { - feature_err( - sess, - sym::edition_macro_pats, - frag.span, - "`pat2015` and `pat2021` are unstable.", - ) - .emit(); - } - } - _ => {} - } - let kind = token::NonterminalKind::from_symbol(frag.name, || { span.edition() diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 304d7ede625..4ad5f085ad0 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -607,9 +607,6 @@ declare_features! ( /// Allows arbitrary expressions in key-value attributes at parse time. (active, extended_key_value_attributes, "1.50.0", Some(78835), None), - /// `:pat2015` and `:pat2021` macro matchers. - (active, edition_macro_pats, "1.51.0", Some(54883), None), - /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`). (active, const_generics_defaults, "1.51.0", Some(44580), None), @@ -646,12 +643,19 @@ declare_features! ( /// Allows `extern "wasm" fn` (active, wasm_abi, "1.53.0", Some(83788), None), + /// Allows function attribute `#[no_coverage]`, to bypass coverage + /// instrumentation of that function. + (active, no_coverage, "1.53.0", Some(84605), None), + /// Allows trait bounds in `const fn`. (active, const_fn_trait_bound, "1.53.0", Some(57563), None), /// Allows unsizing coercions in `const fn`. (active, const_fn_unsize, "1.53.0", Some(64992), None), + /// Allows using imported `main` function + (active, imported_main, "1.53.0", Some(28937), 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 b8a0b8debcd..5474fea9c78 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -273,6 +273,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: "address, memory, thread"), experimental!(no_sanitize) ), + ungated!( + // Not exclusively gated at the crate level (though crate-level is + // supported). The feature can alternatively be enabled on individual + // functions. + no_coverage, AssumedUsed, + template!(Word), + ), // FIXME: #14408 assume docs are used since rustdoc looks at them. ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 259e540c612..2661afd7ffc 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -104,7 +104,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Fortunately, we just checked that this isn't the case. let path = dep_graph_path_from(&sess.incr_comp_session_dir()); let report_incremental_info = sess.opts.debugging_opts.incremental_info; - let expected_hash = sess.opts.dep_tracking_hash(); + let expected_hash = sess.opts.dep_tracking_hash(false); let mut prev_work_products = FxHashMap::default(); let nightly_build = sess.is_nightly_build(); diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index d558af3c1d5..1484088837a 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -219,7 +219,7 @@ pub fn build_dep_graph( } // First encode the commandline arguments hash - if let Err(err) = sess.opts.dep_tracking_hash().encode(&mut encoder) { + if let Err(err) = sess.opts.dep_tracking_hash(false).encode(&mut encoder) { sess.err(&format!( "failed to write dependency graph hash `{}`: {}", path_buf.display(), diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 87684c2715f..1cde4802a40 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -305,9 +305,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( Some(assoc_name), )); for (super_predicate, _) in super_predicates.predicates { - let bound_predicate = super_predicate.kind(); - let subst_predicate = super_predicate - .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); + let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref); if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { stack.push(binder.value); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 01853eab530..bc94fb67ac3 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -307,7 +307,7 @@ impl<'tcx> Queries<'tcx> { _ => return, }; - let attrs = &*tcx.get_attrs(def_id.to_def_id()); + let attrs = &*tcx.get_attrs(def_id); let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error)); for attr in attrs { match attr.meta_item_list() { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9685d21762b..d8c1a7a2682 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -19,6 +19,7 @@ use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel}; + use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use std::num::NonZeroUsize; @@ -74,6 +75,27 @@ fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> { BTreeMap::from_iter(entries.into_iter()) } +fn assert_same_clone(x: &Options) { + assert_eq!(x.dep_tracking_hash(true), x.clone().dep_tracking_hash(true)); + assert_eq!(x.dep_tracking_hash(false), x.clone().dep_tracking_hash(false)); +} + +fn assert_same_hash(x: &Options, y: &Options) { + assert_eq!(x.dep_tracking_hash(true), y.dep_tracking_hash(true)); + assert_eq!(x.dep_tracking_hash(false), y.dep_tracking_hash(false)); + // Check clone + assert_same_clone(x); + assert_same_clone(y); +} + +fn assert_different_hash(x: &Options, y: &Options) { + assert_ne!(x.dep_tracking_hash(true), y.dep_tracking_hash(true)); + assert_ne!(x.dep_tracking_hash(false), y.dep_tracking_hash(false)); + // Check clone + assert_same_clone(x); + assert_same_clone(y); +} + // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { @@ -130,14 +152,9 @@ fn test_output_types_tracking_hash_different_paths() { v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]); v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); - assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash()); - assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); + assert_different_hash(&v1, &v2); + assert_different_hash(&v1, &v3); + assert_different_hash(&v2, &v3); } #[test] @@ -155,10 +172,7 @@ fn test_output_types_tracking_hash_different_construction_order() { (OutputType::Exe, Some(PathBuf::from("./some/thing"))), ]); - assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); + assert_same_hash(&v1, &v2); } #[test] @@ -182,14 +196,9 @@ fn test_externs_tracking_hash_different_construction_order() { (String::from("d"), new_public_extern_entry(vec!["f", "e"])), ])); - assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash()); - assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); + assert_same_hash(&v1, &v2); + assert_same_hash(&v1, &v3); + assert_same_hash(&v2, &v3); } #[test] @@ -219,14 +228,9 @@ fn test_lints_tracking_hash_different_values() { (String::from("d"), Level::Deny), ]; - assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash()); - assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); + assert_different_hash(&v1, &v2); + assert_different_hash(&v1, &v3); + assert_different_hash(&v2, &v3); } #[test] @@ -248,11 +252,7 @@ fn test_lints_tracking_hash_different_construction_order() { (String::from("d"), Level::Forbid), ]; - assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); + assert_same_hash(&v1, &v2); } #[test] @@ -292,15 +292,9 @@ fn test_search_paths_tracking_hash_different_order() { v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON)); v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON)); - assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); - assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash()); + assert_same_hash(&v1, &v2); + assert_same_hash(&v1, &v3); + assert_same_hash(&v1, &v4); } #[test] @@ -338,15 +332,9 @@ fn test_native_libs_tracking_hash_different_values() { (String::from("c"), None, NativeLibKind::Unspecified), ]; - assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); - assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash()); + assert_different_hash(&v1, &v2); + assert_different_hash(&v1, &v3); + assert_different_hash(&v1, &v4); } #[test] @@ -374,14 +362,9 @@ fn test_native_libs_tracking_hash_different_order() { (String::from("b"), None, NativeLibKind::Framework), ]; - assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); - assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash()); - assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash()); - - // Check clone - assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash()); - assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash()); - assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash()); + assert_same_hash(&v1, &v2); + assert_same_hash(&v1, &v3); + assert_same_hash(&v2, &v3); } #[test] @@ -391,8 +374,9 @@ fn test_codegen_options_tracking_hash() { macro_rules! untracked { ($name: ident, $non_default_value: expr) => { + assert_ne!(opts.cg.$name, $non_default_value); opts.cg.$name = $non_default_value; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + assert_same_hash(&reference, &opts); }; } @@ -416,8 +400,9 @@ fn test_codegen_options_tracking_hash() { macro_rules! tracked { ($name: ident, $non_default_value: expr) => { opts = reference.clone(); + assert_ne!(opts.cg.$name, $non_default_value); opts.cg.$name = $non_default_value; - assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + assert_different_hash(&reference, &opts); }; } @@ -455,14 +440,41 @@ fn test_codegen_options_tracking_hash() { } #[test] +fn test_top_level_options_tracked_no_crate() { + let reference = Options::default(); + let mut opts; + + macro_rules! tracked { + ($name: ident, $non_default_value: expr) => { + opts = reference.clone(); + assert_ne!(opts.$name, $non_default_value); + opts.$name = $non_default_value; + // The crate hash should be the same + assert_eq!(reference.dep_tracking_hash(true), opts.dep_tracking_hash(true)); + // The incremental hash should be different + assert_ne!(reference.dep_tracking_hash(false), opts.dep_tracking_hash(false)); + }; + } + + // Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash. + // This list is in alphabetical order. + tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]); + tracked!( + real_rust_source_base_dir, + Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into()) + ); +} + +#[test] fn test_debugging_options_tracking_hash() { let reference = Options::default(); let mut opts = Options::default(); macro_rules! untracked { ($name: ident, $non_default_value: expr) => { + assert_ne!(opts.debugging_opts.$name, $non_default_value); opts.debugging_opts.$name = $non_default_value; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + assert_same_hash(&reference, &opts); }; } @@ -471,7 +483,7 @@ fn test_debugging_options_tracking_hash() { untracked!(ast_json, true); untracked!(ast_json_noexpand, true); untracked!(borrowck, String::from("other")); - untracked!(deduplicate_diagnostics, true); + untracked!(deduplicate_diagnostics, false); untracked!(dep_tasks, true); untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); @@ -515,7 +527,7 @@ fn test_debugging_options_tracking_hash() { untracked!(self_profile_events, Some(vec![String::new()])); untracked!(span_debug, true); untracked!(span_free_formats, true); - untracked!(strip, Strip::None); + untracked!(strip, Strip::Debuginfo); untracked!(terminal_width, Some(80)); untracked!(threads, 99); untracked!(time, true); @@ -532,8 +544,9 @@ fn test_debugging_options_tracking_hash() { macro_rules! tracked { ($name: ident, $non_default_value: expr) => { opts = reference.clone(); + assert_ne!(opts.debugging_opts.$name, $non_default_value); opts.debugging_opts.$name = $non_default_value; - assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + assert_different_hash(&reference, &opts); }; } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b3a19bfbf75..c1d6a4f1de1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -710,7 +710,7 @@ pub trait LintContext: Sized { db.note(¬e); } BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => { - db.span_suggestion(span, "use pat2015 to preserve semantics", suggestion, Applicability::MachineApplicable); + db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable); } } // Rewrap `db`, and pass control to the user. diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 617b2ed970e..65a988629c3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -609,7 +609,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, std::string ErrorInfo; std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::F_None); + raw_fd_ostream OS(Path, EC, sys::fs::OF_None); if (EC) ErrorInfo = EC.message(); if (ErrorInfo != "") { @@ -619,7 +619,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, buffer_ostream BOS(OS); if (DwoPath) { - raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None); + raw_fd_ostream DOS(DwoPath, EC, sys::fs::OF_None); EC.clear(); if (EC) ErrorInfo = EC.message(); @@ -1146,7 +1146,7 @@ extern "C" LLVMRustResult LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) { std::string ErrorInfo; std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::F_None); + raw_fd_ostream OS(Path, EC, sys::fs::OF_None); if (EC) ErrorInfo = EC.message(); if (ErrorInfo != "") { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 19ae5ce69c1..2ade1bb4f95 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1617,7 +1617,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map(Path::new) .filter(|_| { // Only spend time on further checks if we have what to translate *to*. - sess.real_rust_source_base_dir.is_some() + sess.opts.real_rust_source_base_dir.is_some() }) .filter(|virtual_dir| { // Don't translate away `/rustc/$hash` if we're still remapping to it, @@ -1629,11 +1629,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { debug!( "try_to_translate_virtual_to_real(name={:?}): \ virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}", - name, virtual_rust_source_base_dir, sess.real_rust_source_base_dir, + name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir, ); if let Some(virtual_dir) = virtual_rust_source_base_dir { - if let Some(real_dir) = &sess.real_rust_source_base_dir { + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { if let rustc_span::FileName::Real(old_name) = name { if let rustc_span::RealFileName::Named(one_path) = old_name { if let Ok(rest) = one_path.strip_prefix(virtual_dir) { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9a42bbe7bac..d5697513eef 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -91,7 +91,7 @@ macro_rules! arena_types { [] predicates: rustc_middle::ty::PredicateInner<$tcx>, // HIR query types - [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, + [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>, [few] hir_definitions: rustc_hir::definitions::Definitions, [] hir_owner: rustc_middle::hir::Owner<$tcx>, [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 501e7d624d2..719bbf04c95 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,22 +1,20 @@ use crate::arena::Arena; -use crate::hir::map::{Entry, HirOwnerData, Map}; -use crate::hir::{Owner, OwnerNodes, ParentedNode}; +use crate::hir::map::{HirOwnerData, Map}; +use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode}; use crate::ich::StableHashingContext; -use crate::middle::cstore::CrateStore; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::svh::Svh; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_INDEX; -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; -use rustc_hir::definitions::{self, DefPathHash}; +use rustc_hir::definitions; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::Session; use rustc_span::source_map::SourceMap; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; use std::iter::repeat; @@ -31,6 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> { source_map: &'a SourceMap, map: IndexVec<LocalDefId, HirOwnerData<'hir>>, + parenting: FxHashMap<LocalDefId, HirId>, /// The parent of this node parent_node: hir::HirId, @@ -40,10 +39,6 @@ pub(super) struct NodeCollector<'a, 'hir> { definitions: &'a definitions::Definitions, hcx: StableHashingContext<'a>, - - // We are collecting HIR hashes here so we can compute the - // crate hash from them later on. - hir_body_nodes: Vec<(DefPathHash, Fingerprint)>, } fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) { @@ -58,34 +53,20 @@ fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V fn hash_body( hcx: &mut StableHashingContext<'_>, - def_path_hash: DefPathHash, item_like: impl for<'a> HashStable<StableHashingContext<'a>>, - hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>, ) -> Fingerprint { - let hash = { - let mut stable_hasher = StableHasher::new(); - hcx.while_hashing_hir_bodies(true, |hcx| { - item_like.hash_stable(hcx, &mut stable_hasher); - }); - stable_hasher.finish() - }; - hir_body_nodes.push((def_path_hash, hash)); - hash + let mut stable_hasher = StableHasher::new(); + hcx.while_hashing_hir_bodies(true, |hcx| { + item_like.hash_stable(hcx, &mut stable_hasher); + }); + stable_hasher.finish() } -fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> { - let mut upstream_crates: Vec<_> = cstore - .crates_untracked() - .iter() - .map(|&cnum| { - let name = cstore.crate_name_untracked(cnum); - let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint(); - let hash = cstore.crate_hash_untracked(cnum); - (name, disambiguator, hash) - }) - .collect(); - upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis)); - upstream_crates +/// Represents an entry and its parent `HirId`. +#[derive(Copy, Clone, Debug)] +pub struct Entry<'hir> { + parent: HirId, + node: Node<'hir>, } impl<'a, 'hir> NodeCollector<'a, 'hir> { @@ -96,11 +77,6 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { definitions: &'a definitions::Definitions, mut hcx: StableHashingContext<'a>, ) -> NodeCollector<'a, 'hir> { - let root_mod_def_path_hash = - definitions.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX }); - - let mut hir_body_nodes = Vec::new(); - let hash = { let Crate { ref item, @@ -120,7 +96,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { attrs: _, } = *krate; - hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes) + hash_body(&mut hcx, item) }; let mut collector = NodeCollector { @@ -131,10 +107,10 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, definitions, hcx, - hir_body_nodes, map: (0..definitions.def_index_count()) .map(|_| HirOwnerData { signature: None, with_bodies: None }) .collect(), + parenting: FxHashMap::default(), }; collector.insert_entry( hir::CRATE_HIR_ID, @@ -145,55 +121,13 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { collector } - pub(super) fn finalize_and_compute_crate_hash( - mut self, - crate_disambiguator: CrateDisambiguator, - cstore: &dyn CrateStore, - commandline_args_hash: u64, - ) -> (IndexVec<LocalDefId, HirOwnerData<'hir>>, Svh) { + 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; assert!(bodies.insert(id.hir_id.local_id, body).is_none()); } - - self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - - let node_hashes = self.hir_body_nodes.iter().fold( - Fingerprint::ZERO, - |combined_fingerprint, &(def_path_hash, fingerprint)| { - combined_fingerprint.combine(def_path_hash.0.combine(fingerprint)) - }, - ); - - let upstream_crates = upstream_crates(cstore); - - // We hash the final, remapped names of all local source files so we - // don't have to include the path prefix remapping commandline args. - // If we included the full mapping in the SVH, we could only have - // reproducible builds by compiling from the same directory. So we just - // hash the result of the mapping instead of the mapping itself. - let mut source_file_names: Vec<_> = self - .source_map - .files() - .iter() - .filter(|source_file| source_file.cnum == LOCAL_CRATE) - .map(|source_file| source_file.name_hash) - .collect(); - - source_file_names.sort_unstable(); - - let crate_hash_input = ( - ((node_hashes, upstream_crates), source_file_names), - (commandline_args_hash, crate_disambiguator.to_fingerprint()), - ); - - let mut stable_hasher = StableHasher::new(); - crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher); - let crate_hash: Fingerprint = stable_hasher.finish(); - - let svh = Svh::new(crate_hash.to_smaller_hash()); - (self.map, svh) + IndexedHir { map: self.map, parenting: self.parenting } } fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) { @@ -218,8 +152,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { nodes.hash = hash; debug_assert!(data.signature.is_none()); - data.signature = - Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node })); + 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 { @@ -231,6 +164,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { id.owner, dk_parent, entry.parent, ) } + + debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent)); } } else { assert_eq!(entry.parent.owner, id.owner); @@ -294,15 +229,28 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { f: F, ) { let prev_owner = self.current_dep_node_owner; - - let def_path_hash = self.definitions.def_path_hash(dep_node_owner); - - let hash = hash_body(&mut self.hcx, def_path_hash, item_like, &mut self.hir_body_nodes); + let hash = hash_body(&mut self.hcx, item_like); self.current_dep_node_owner = dep_node_owner; f(self, hash); self.current_dep_node_owner = prev_owner; } + + fn insert_nested(&mut self, item: LocalDefId) { + #[cfg(debug_assertions)] + { + let dk_parent = self.definitions.def_key(item).parent.unwrap(); + let dk_parent = LocalDefId { local_def_index: dk_parent }; + let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent); + debug_assert_eq!( + dk_parent.owner, self.parent_node.owner, + "Different parents for {:?}", + item + ) + } + + assert_eq!(self.parenting.insert(item, self.parent_node), None); + } } impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { @@ -318,18 +266,22 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); + self.insert_nested(item.def_id); self.visit_item(self.krate.item(item)); } fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { + self.insert_nested(item_id.def_id); self.visit_trait_item(self.krate.trait_item(item_id)); } fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { + self.insert_nested(item_id.def_id); self.visit_impl_item(self.krate.impl_item(item_id)); } fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { + self.insert_nested(foreign_id.def_id); self.visit_foreign_item(self.krate.foreign_item(foreign_id)); } @@ -517,6 +469,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index }) }); self.with_parent(parent, |this| { + this.insert_nested(macro_def.def_id); this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| { this.insert_with_hash( macro_def.span, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d155276051e..73f3b550c37 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,8 +1,11 @@ use self::collector::NodeCollector; -use crate::hir::{Owner, OwnerNodes}; +use crate::hir::{HirOwnerData, IndexedHir}; +use crate::middle::cstore::CrateStore; use crate::ty::TyCtxt; use rustc_ast as ast; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -11,7 +14,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; -use rustc_index::vec::IndexVec; +use rustc_index::vec::Idx; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -21,22 +24,6 @@ use rustc_target::spec::abi::Abi; pub mod blocks; mod collector; -/// Represents an entry and its parent `HirId`. -#[derive(Copy, Clone, Debug)] -pub struct Entry<'hir> { - parent: HirId, - node: Node<'hir>, -} - -impl<'hir> Entry<'hir> { - fn parent_node(self) -> Option<HirId> { - match self.node { - Node::Crate(_) => None, - _ => Some(self.parent), - } - } -} - fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { match node { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) @@ -86,20 +73,6 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool { } } -#[derive(Debug)] -pub(super) struct HirOwnerData<'hir> { - pub(super) signature: Option<&'hir Owner<'hir>>, - pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>, -} - -#[derive(Debug)] -pub struct IndexedHir<'hir> { - /// The SVH of the local crate. - pub crate_hash: Svh, - - pub(super) map: IndexVec<LocalDefId, HirOwnerData<'hir>>, -} - #[derive(Copy, Clone)] pub struct Map<'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -129,10 +102,48 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> { } self.current_id = parent_id; - if let Some(entry) = self.map.find_entry(parent_id) { - return Some((parent_id, entry.node)); + if let Some(node) = self.map.find(parent_id) { + return Some((parent_id, node)); + } + // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. + } + } +} + +/// An iterator that walks up the ancestor tree of a given `HirId`. +/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`. +pub struct ParentOwnerIterator<'map, 'hir> { + current_id: HirId, + map: &'map Map<'hir>, +} + +impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> { + type Item = (HirId, Node<'hir>); + + fn next(&mut self) -> Option<Self::Item> { + if self.current_id.local_id.index() != 0 { + self.current_id.local_id = ItemLocalId::new(0); + if let Some(node) = self.map.find(self.current_id) { + return Some((self.current_id, node)); + } + } + if self.current_id == CRATE_HIR_ID { + return None; + } + loop { + // There are nodes that do not have entries, so we need to skip them. + let parent_id = self.map.def_key(self.current_id.owner).parent; + + let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| { + let def_id = LocalDefId { local_def_index }; + self.map.local_def_id_to_hir_id(def_id).owner + }); + self.current_id = HirId::make_owner(parent_id); + + // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`. + if let Some(node) = self.map.find(self.current_id) { + return Some((self.current_id, node)); } - // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`. } } } @@ -165,7 +176,7 @@ impl<'hir> Map<'hir> { bug!( "local_def_id: no entry for `{:?}`, which has a map of `{:?}`", hir_id, - self.find_entry(hir_id) + self.find(hir_id) ) }) } @@ -272,27 +283,60 @@ impl<'hir> Map<'hir> { .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id)) } - fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> { + pub fn find_parent_node(&self, id: HirId) -> Option<HirId> { if id.local_id == ItemLocalId::from_u32(0) { - let owner = self.tcx.hir_owner(id.owner); - owner.map(|owner| Entry { parent: owner.parent, node: owner.node }) + Some(self.tcx.hir_owner_parent(id.owner)) } else { - let owner = self.tcx.hir_owner_nodes(id.owner); - owner.and_then(|owner| { - let node = owner.nodes[id.local_id].as_ref(); - // FIXME(eddyb) use a single generic type instead of having both - // `Entry` and `ParentedNode`, which are effectively the same. - // Alternatively, rewrite code using `Entry` to use `ParentedNode`. - node.map(|node| Entry { - parent: HirId { owner: id.owner, local_id: node.parent }, - node: node.node, - }) - }) + let owner = self.tcx.hir_owner_nodes(id.owner)?; + let node = owner.nodes[id.local_id].as_ref()?; + let hir_id = HirId { owner: id.owner, local_id: node.parent }; + Some(hir_id) + } + } + + pub fn get_parent_node(&self, hir_id: HirId) -> HirId { + self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID) + } + + /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. + pub fn find(&self, id: HirId) -> Option<Node<'hir>> { + if id.local_id == ItemLocalId::from_u32(0) { + let owner = self.tcx.hir_owner(id.owner)?; + Some(owner.node) + } else { + let owner = self.tcx.hir_owner_nodes(id.owner)?; + let node = owner.nodes[id.local_id].as_ref()?; + Some(node.node) } } - fn get_entry(&self, id: HirId) -> Entry<'hir> { - self.find_entry(id).unwrap() + /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. + pub fn get(&self, id: HirId) -> Node<'hir> { + self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id)) + } + + pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> { + id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id))) + } + + pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> { + self.get_if_local(id).and_then(|node| match &node { + Node::ImplItem(impl_item) => Some(&impl_item.generics), + Node::TraitItem(trait_item) => Some(&trait_item.generics), + Node::Item(Item { + kind: + ItemKind::Fn(_, generics, _) + | ItemKind::TyAlias(_, generics) + | ItemKind::Enum(_, generics) + | ItemKind::Struct(_, generics) + | ItemKind::Union(_, generics) + | ItemKind::Trait(_, _, generics, ..) + | ItemKind::TraitAlias(generics, _) + | ItemKind::Impl(Impl { generics, .. }), + .. + }) => Some(generics), + _ => None, + }) } pub fn item(&self, id: ItemId) -> &'hir Item<'hir> { @@ -457,7 +501,7 @@ impl<'hir> Map<'hir> { pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) { let hir_id = self.local_def_id_to_hir_id(module); - match self.get_entry(hir_id).node { + match self.get(hir_id) { Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id), Node::Crate(item) => (&item, item.inner, hir_id), node => panic!("not a module: {:?}", node), @@ -496,60 +540,18 @@ impl<'hir> Map<'hir> { } } - /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found. - pub fn get(&self, id: HirId) -> Node<'hir> { - self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id)) - } - - pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> { - id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id))) - } - - pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> { - self.get_if_local(id).and_then(|node| match &node { - Node::ImplItem(impl_item) => Some(&impl_item.generics), - Node::TraitItem(trait_item) => Some(&trait_item.generics), - Node::Item(Item { - kind: - ItemKind::Fn(_, generics, _) - | ItemKind::TyAlias(_, generics) - | ItemKind::Enum(_, generics) - | ItemKind::Struct(_, generics) - | ItemKind::Union(_, generics) - | ItemKind::Trait(_, _, generics, ..) - | ItemKind::TraitAlias(generics, _) - | ItemKind::Impl(Impl { generics, .. }), - .. - }) => Some(generics), - _ => None, - }) - } - - /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. - pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> { - self.find_entry(hir_id).map(|entry| entry.node) - } - - /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there - /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself - /// present in the map, so passing the return value of `get_parent_node` to - /// `get` may in fact panic. - /// This function returns the immediate parent in the HIR, whereas `get_parent` - /// returns the enclosing item. Note that this might not be the actual parent - /// node in the HIR -- some kinds of nodes are not in the map and these will - /// never appear as the parent node. Thus, you can always walk the parent nodes - /// from a node to the root of the HIR (unless you get back the same ID here, - /// which can happen if the ID is not in the map itself or is just weird). - pub fn get_parent_node(&self, hir_id: HirId) -> HirId { - self.get_entry(hir_id).parent_node().unwrap_or(hir_id) - } - /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> { ParentHirIterator { current_id, map: self } } + /// Returns an iterator for the nodes in the ancestor tree of the `current_id` + /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`. + pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> { + ParentOwnerIterator { current_id, map: self } + } + /// Checks if the node is left-hand side of an assignment. pub fn is_lhs(&self, id: HirId) -> bool { match self.find(self.get_parent_node(id)) { @@ -570,7 +572,7 @@ impl<'hir> Map<'hir> { /// Whether `hir_id` corresponds to a `mod` or a crate. pub fn is_hir_id_module(&self, hir_id: HirId) -> bool { matches!( - self.get_entry(hir_id).node, + self.get(hir_id), Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..) ) } @@ -600,8 +602,8 @@ impl<'hir> Map<'hir> { pub fn get_return_block(&self, id: HirId) -> Option<HirId> { let mut iter = self.parent_iter(id).peekable(); let mut ignore_tail = false; - if let Some(entry) = self.find_entry(id) { - if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node { + if let Some(node) = self.find(id) { + if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = node { // When dealing with `return` statements, we don't care about climbing only tail // expressions. ignore_tail = true; @@ -638,23 +640,23 @@ impl<'hir> Map<'hir> { /// in the HIR which is recorded by the map and is an item, either an item /// in a module, trait, or impl. pub fn get_parent_item(&self, hir_id: HirId) -> HirId { - for (hir_id, node) in self.parent_iter(hir_id) { - match node { - Node::Crate(_) - | Node::Item(_) - | Node::ForeignItem(_) - | Node::TraitItem(_) - | Node::ImplItem(_) => return hir_id, - _ => {} + for (hir_id, node) in self.parent_owner_iter(hir_id) { + if let Node::Crate(_) + | Node::Item(_) + | Node::ForeignItem(_) + | Node::TraitItem(_) + | Node::ImplItem(_) = node + { + return hir_id; } } - hir_id + CRATE_HIR_ID } /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no /// module parent is in this map. pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId { - for (hir_id, node) in self.parent_iter(hir_id) { + for (hir_id, node) in self.parent_owner_iter(hir_id) { if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node { return hir_id; } @@ -728,12 +730,8 @@ impl<'hir> Map<'hir> { pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi { let parent = self.get_parent_item(hir_id); - if let Some(entry) = self.find_entry(parent) { - if let Entry { - node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }), - .. - } = entry - { + if let Some(node) = self.find(parent) { + if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node { return *abi; } } @@ -827,7 +825,7 @@ impl<'hir> Map<'hir> { } pub fn opt_span(&self, hir_id: HirId) -> Option<Span> { - let span = match self.find_entry(hir_id)?.node { + let span = match self.find(hir_id)? { Node::Param(param) => param.span, Node::Item(item) => match &item.kind { ItemKind::Fn(sig, _, _) => sig.span, @@ -876,7 +874,7 @@ impl<'hir> Map<'hir> { /// Like `hir.span()`, but includes the body of function items /// (instead of just the function header) pub fn span_with_body(&self, hir_id: HirId) -> Span { - match self.find_entry(hir_id).map(|entry| entry.node) { + match self.find(hir_id) { Some(Node::TraitItem(item)) => item.span, Some(Node::ImplItem(impl_item)) => impl_item.span, Some(Node::Item(item)) => item.span, @@ -935,19 +933,78 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx Indexe let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map"); - let (map, crate_hash) = { - let hcx = tcx.create_stable_hashing_context(); + let hcx = tcx.create_stable_hashing_context(); + let mut collector = + NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx); + intravisit::walk_crate(&mut collector, tcx.untracked_crate); - let mut collector = - NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx); - intravisit::walk_crate(&mut collector, tcx.untracked_crate); + let map = collector.finalize_and_compute_crate_hash(); + tcx.arena.alloc(map) +} - let crate_disambiguator = tcx.sess.local_crate_disambiguator(); - let cmdline_args = tcx.sess.opts.dep_tracking_hash(); - collector.finalize_and_compute_crate_hash(crate_disambiguator, &*tcx.cstore, cmdline_args) - }; +pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { + let mut hir_body_nodes: Vec<_> = tcx + .index_hir(crate_num) + .map + .iter_enumerated() + .filter_map(|(def_id, hod)| { + let def_path_hash = tcx.definitions.def_path_hash(def_id); + let hash = hod.with_bodies.as_ref()?.hash; + Some((def_path_hash, hash)) + }) + .collect(); + hir_body_nodes.sort_unstable_by_key(|bn| bn.0); - tcx.arena.alloc(IndexedHir { crate_hash, map }) + let node_hashes = hir_body_nodes.iter().fold( + Fingerprint::ZERO, + |combined_fingerprint, &(def_path_hash, fingerprint)| { + combined_fingerprint.combine(def_path_hash.0.combine(fingerprint)) + }, + ); + + let upstream_crates = upstream_crates(&*tcx.cstore); + + // We hash the final, remapped names of all local source files so we + // don't have to include the path prefix remapping commandline args. + // If we included the full mapping in the SVH, we could only have + // reproducible builds by compiling from the same directory. So we just + // hash the result of the mapping instead of the mapping itself. + let mut source_file_names: Vec<_> = tcx + .sess + .source_map() + .files() + .iter() + .filter(|source_file| source_file.cnum == LOCAL_CRATE) + .map(|source_file| source_file.name_hash) + .collect(); + + source_file_names.sort_unstable(); + + let mut hcx = tcx.create_stable_hashing_context(); + let mut stable_hasher = StableHasher::new(); + node_hashes.hash_stable(&mut hcx, &mut stable_hasher); + upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); + source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); + tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher); + + let crate_hash: Fingerprint = stable_hasher.finish(); + Svh::new(crate_hash.to_smaller_hash()) +} + +fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> { + let mut upstream_crates: Vec<_> = cstore + .crates_untracked() + .iter() + .map(|&cnum| { + let name = cstore.crate_name_untracked(cnum); + let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint(); + let hash = cstore.crate_hash_untracked(cnum); + (name, disambiguator, hash) + }) + .collect(); + upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis)); + upstream_crates } fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index cf4e473d8ac..565664778e5 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -20,18 +20,26 @@ 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>>, +} + +#[derive(Debug)] +pub struct IndexedHir<'hir> { + map: IndexVec<LocalDefId, HirOwnerData<'hir>>, + parenting: FxHashMap<LocalDefId, HirId>, +} + +#[derive(Debug)] pub struct Owner<'tcx> { - parent: HirId, node: Node<'tcx>, } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Owner { parent, node } = self; - hcx.while_hashing_hir_bodies(false, |hcx| { - parent.hash_stable(hcx, hasher); - node.hash_stable(hcx, hasher); - }); + let Owner { node } = self; + hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher)); } } @@ -117,9 +125,14 @@ pub fn provide(providers: &mut Providers) { }; providers.hir_crate = |tcx, _| tcx.untracked_crate; 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(LOCAL_CRATE).map[id].signature; providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref(); + providers.hir_owner_parent = |tcx, id| { + let index = tcx.index_hir(LOCAL_CRATE); + index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) + }; providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id }; providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP); providers.fn_arg_names = |tcx, id| { diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 7024d9a3d21..93e7aeaffce 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -89,6 +89,10 @@ bitflags! { /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a /// function as an entry function from Non-Secure code. const CMSE_NONSECURE_ENTRY = 1 << 14; + /// `#[no_coverage]`: indicates that the function should be ignored by + /// the MIR `InstrumentCoverage` pass and not added to the coverage map + /// during codegen. + const NO_COVERAGE = 1 << 15; } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e22c0b40d5a..252b5fc70de 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -683,6 +683,15 @@ impl BorrowKind { BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, } } + + pub fn describe_mutability(&self) -> String { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => { + "immutable".to_string() + } + BorrowKind::Mut { .. } => "mutable".to_string(), + } + } } /////////////////////////////////////////////////////////////////////////// @@ -1340,7 +1349,7 @@ impl<O> AssertKind<O> { } /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing. - fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result + pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result where O: Debug, { @@ -2369,6 +2378,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; let mut struct_fmt = fmt.debug_struct(&name); + // FIXME(project-rfc-2229#48): This should be a list of capture names/places if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); @@ -2388,6 +2398,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); let mut struct_fmt = fmt.debug_struct(&name); + // FIXME(project-rfc-2229#48): This should be a list of capture names/places if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 92a1094bbcd..77f38e52ad2 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -6,7 +6,7 @@ use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::{HirId, ItemId}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; @@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> { // indicator, then we'll be creating a globally shared version. if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() || !instance.def.generates_cgu_internal_copy(tcx) - || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id) + || Some(instance.def_id()) == entry_def_id { return InstantiationMode::GloballyShared { may_conflict: false }; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 08fa12aa371..3ffc3641b62 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -28,7 +28,7 @@ rustc_queries! { /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. /// Avoid calling this query directly. - query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { + query index_hir(_: CrateNum) -> &'tcx crate::hir::IndexedHir<'tcx> { eval_always no_hash desc { "index HIR" } @@ -52,6 +52,15 @@ rustc_queries! { desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } + /// Gives access to the HIR node's parent for the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. + query hir_owner_parent(key: LocalDefId) -> hir::HirId { + eval_always + desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) } + } + /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. /// /// This can be conveniently accessed by methods on `tcx.hir()`. @@ -1194,7 +1203,7 @@ rustc_queries! { /// Identifies the entry-point (e.g., the `main` function) for a given /// crate, returning `None` if there is no entry point (such as for library crates). - query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> { + query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> { desc { "looking up the entry function of a crate" } } query plugin_registrar_fn(_: CrateNum) -> Option<DefId> { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 00dec3b355f..c9b73c68209 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -670,6 +670,9 @@ pub enum ObjectSafetyViolation { /// Associated const. AssocConst(Symbol, Span), + + /// GAT + GAT(Symbol, Span), } impl ObjectSafetyViolation { @@ -715,6 +718,9 @@ impl ObjectSafetyViolation { format!("it contains associated `const` `{}`", name).into() } ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), + ObjectSafetyViolation::GAT(name, _) => { + format!("it contains the generic associated type `{}`", name).into() + } } } @@ -773,6 +779,7 @@ impl ObjectSafetyViolation { ); } ObjectSafetyViolation::AssocConst(name, _) + | ObjectSafetyViolation::GAT(name, _) | ObjectSafetyViolation::Method(name, ..) => { err.help(&format!("consider moving `{}` to another trait", name)); } @@ -786,6 +793,7 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::SupertraitSelf(spans) | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), ObjectSafetyViolation::AssocConst(_, span) + | ObjectSafetyViolation::GAT(_, span) | ObjectSafetyViolation::Method(_, _, span) if *span != DUMMY_SP => { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 887a5831cd7..7790369af7f 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -151,6 +151,10 @@ pub struct CapturedPlace<'tcx> { } impl CapturedPlace<'tcx> { + pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String { + place_to_string_for_capture(tcx, &self.place) + } + /// Returns the hir-id of the root variable for the captured place. /// e.g., if `a.b.c` was captured, would return the hir-id for `a`. pub fn get_root_variable(&self) -> hir::HirId { @@ -168,6 +172,22 @@ impl CapturedPlace<'tcx> { } } + /// Return span pointing to use that resulted in selecting the captured path + pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span { + if let Some(path_expr_id) = self.info.path_expr_id { + tcx.hir().span(path_expr_id) + } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id { + tcx.hir().span(capture_kind_expr_id) + } else { + // Fallback on upvars mentioned if neither path or capture expr id is captured + + // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars. + tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap() + [&self.get_root_variable()] + .span + } + } + /// Return span pointing to use that resulted in selecting the current capture kind pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span { if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index bb2b00cbaea..b414618f7d5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -20,8 +20,8 @@ use crate::ty::TyKind::*; use crate::ty::{ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst, - InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, - PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions, + InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig, + Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use rustc_ast as ast; @@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> { layout_interner: ShardedHashMap<&'tcx Layout, ()>, output_filenames: Arc<OutputFilenames>, + + pub main_def: Option<MainDefinition>, } impl<'tcx> TyCtxt<'tcx> { @@ -1185,6 +1187,7 @@ impl<'tcx> TyCtxt<'tcx> { const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames.clone()), + main_def: resolutions.main_def, } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 01bc5cc761c..92288c89827 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -59,6 +59,10 @@ impl FlagComputation { { let mut computation = FlagComputation::new(); + if !value.bound_vars().is_empty() { + computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND; + } + f(&mut computation, value.skip_binder()); self.add_flags(computation.flags); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6574c938260..af49533753f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -124,6 +124,20 @@ pub struct ResolverOutputs { /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap<Symbol, bool>, + pub main_def: Option<MainDefinition>, +} + +#[derive(Clone, Copy)] +pub struct MainDefinition { + pub res: Res<ast::NodeId>, + pub is_import: bool, + pub span: Span, +} + +impl MainDefinition { + pub fn opt_fn_def_id(self) -> Option<DefId> { + if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None } + } } /// The "header" of an impl is everything outside the body: a Self type, a trait diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index c170858ba85..81230e32f56 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -1,6 +1,5 @@ use crate::dep_graph; use crate::hir::exports::Export; -use crate::hir::map; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; 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 416199b3840..43b775f8083 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1185,20 +1185,27 @@ where assert!(Q::query_state(tcx).all_inactive()); let cache = Q::query_cache(tcx); - cache.iter_results(|results| { - for (key, value, dep_node) in results { - if Q::cache_on_disk(tcx, &key, Some(value)) { - let dep_node = SerializedDepNodeIndex::new(dep_node.index()); - - // Record position of the cache entry. - query_result_index - .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position()))); - - // Encode the type check tables with the `SerializedDepNodeIndex` - // as tag. - encoder.encode_tagged(dep_node, value)?; + let mut res = Ok(()); + cache.iter_results(&mut |key, value, dep_node| { + if res.is_err() { + return; + } + if Q::cache_on_disk(tcx, &key, Some(value)) { + let dep_node = SerializedDepNodeIndex::new(dep_node.index()); + + // Record position of the cache entry. + query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position()))); + + // Encode the type check tables with the `SerializedDepNodeIndex` + // as tag. + match encoder.encode_tagged(dep_node, value) { + Ok(()) => {} + Err(e) => { + res = Err(e); + } } } - Ok(()) - }) + }); + + res } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 9f19a474ca3..30e0b293ffb 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); - use_spans.var_span_label( + use_spans.var_span_label_path_only( &mut err, format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); @@ -255,6 +255,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { partially_str, move_spans.describe() ), + "moved", ); } } @@ -304,7 +305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - use_spans.var_span_label( + use_spans.var_span_label_path_only( &mut err, format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); @@ -434,13 +435,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); err.span_label(span, format!("move out of {} occurs here", value_msg)); - borrow_spans.var_span_label( + borrow_spans.var_span_label_path_only( &mut err, format!("borrow occurs due to use{}", borrow_spans.describe()), ); - move_spans - .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe())); + move_spans.var_span_label( + &mut err, + format!("move occurs due to use{}", move_spans.describe()), + "moved", + ); self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( @@ -468,6 +472,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let use_spans = self.move_spans(place.as_ref(), location); let span = use_spans.var_or_use(); + // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use + // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure let mut err = self.cannot_use_when_mutably_borrowed( span, &self.describe_any_place(place.as_ref()), @@ -475,11 +481,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.describe_any_place(borrow.borrowed_place.as_ref()), ); - borrow_spans.var_span_label(&mut err, { - let place = &borrow.borrowed_place; - let desc_place = self.describe_any_place(place.as_ref()); - format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) - }); + borrow_spans.var_span_label( + &mut err, + { + let place = &borrow.borrowed_place; + let desc_place = self.describe_any_place(place.as_ref()); + format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) + }, + "mutable", + ); self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( @@ -591,6 +601,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desc_place, borrow_spans.describe(), ), + "immutable", ); return err; @@ -667,7 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if issued_spans == borrow_spans { borrow_spans.var_span_label( &mut err, - format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()), + format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),), + gen_borrow_kind.describe_mutability(), ); } else { let borrow_place = &issued_borrow.borrowed_place; @@ -679,6 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_place_desc, issued_spans.describe(), ), + issued_borrow.kind.describe_mutability(), ); borrow_spans.var_span_label( @@ -688,6 +701,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desc_place, borrow_spans.describe(), ), + gen_borrow_kind.describe_mutability(), ); } @@ -847,7 +861,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); let borrow_spans = self.retrieve_borrow_spans(borrow); - let borrow_span = borrow_spans.var_or_use(); + let borrow_span = borrow_spans.var_or_use_path_span(); assert!(root_place.projection.is_empty()); let proper_span = self.body.local_decls[root_place.local].source_info.span; @@ -987,7 +1001,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location, name, borrow, drop_span, borrow_spans ); - let borrow_span = borrow_spans.var_or_use(); + let borrow_span = borrow_spans.var_or_use_path_span(); if let BorrowExplanation::MustBeValidFor { category, span, @@ -1575,6 +1589,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { loan_spans.var_span_label( &mut err, format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), ); err.buffer(&mut self.errors_buffer); @@ -1585,8 +1600,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - loan_spans - .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe())); + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), + ); self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( self.infcx.tcx, 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 2a388b8a72b..1b0cae51d58 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -24,8 +24,8 @@ use super::{find_use, RegionName, UseSpans}; #[derive(Debug)] pub(in crate::borrow_check) enum BorrowExplanation { - UsedLater(LaterUseKind, Span), - UsedLaterInLoop(LaterUseKind, Span), + UsedLater(LaterUseKind, Span, Option<Span>), + UsedLaterInLoop(LaterUseKind, Span, Option<Span>), UsedLaterWhenDropped { drop_loc: Location, dropped_local: Local, @@ -67,7 +67,7 @@ impl BorrowExplanation { borrow_span: Option<Span>, ) { match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { + BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => "captured here by trait object", LaterUseKind::ClosureCapture => "captured here by closure", @@ -75,14 +75,31 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, message), - ); + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { + if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, message), + ); + } + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } } } - BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => { "borrow captured here by trait object, in later iteration of loop" @@ -94,7 +111,24 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "borrow later stored here", LaterUseKind::Other => "borrow used here, in later iteration of loop", }; - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { + err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } + } } BorrowExplanation::UsedLaterWhenDropped { drop_loc, @@ -311,13 +345,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_location = location; if self.is_use_in_later_iteration_of_loop(borrow_location, location) { let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) + BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = <expr>` patterns. let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1) + BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) } } @@ -498,16 +532,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Determine how the borrow was later used. + /// First span returned points to the location of the conflicting use + /// Second span if `Some` is returned in the case of closures and points + /// to the use of the path fn later_use_kind( &self, borrow: &BorrowData<'tcx>, use_spans: UseSpans<'tcx>, location: Location, - ) -> (LaterUseKind, Span) { + ) -> (LaterUseKind, Span, Option<Span>) { match use_spans { - UseSpans::ClosureUse { var_span, .. } => { + UseSpans::ClosureUse { capture_kind_span, path_span, .. } => { // Used in a closure. - (LaterUseKind::ClosureCapture, var_span) + (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span)) } UseSpans::PatUse(span) | UseSpans::OtherUse(span) @@ -542,7 +579,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } }; - return (LaterUseKind::Call, function_span); + return (LaterUseKind::Call, function_span, None); } else { LaterUseKind::Other } @@ -550,7 +587,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { LaterUseKind::Other }; - (kind, span) + (kind, span, None) } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index aa9f18d9996..1bb8c7ebe5a 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -18,7 +18,6 @@ use rustc_span::{ Span, }; use rustc_target::abi::VariantIdx; -use std::iter; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -216,11 +215,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Deref => { - // FIXME(project-rfc_2229#36): print capture precisely here. let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.upvars[var_index].name.to_string(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); if self.upvars[var_index].by_ref { buf.push_str(&name); } else { @@ -265,7 +263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.upvars[var_index].name.to_string(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); buf.push_str(&name); } else { let field_name = self @@ -550,8 +548,12 @@ pub(super) enum UseSpans<'tcx> { /// The span of the args of the closure, including the `move` keyword if /// it's present. args_span: Span, - /// The span of the first use of the captured variable inside the closure. - var_span: Span, + /// The span of the use resulting in capture kind + /// Check `ty::CaptureInfo` for more details + capture_kind_span: Span, + /// The span of the use resulting in the captured path + /// Check `ty::CaptureInfo` for more details + path_span: Span, }, /// The access is caused by using a variable as the receiver of a method /// that takes 'self' @@ -606,9 +608,23 @@ impl UseSpans<'_> { } } + /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span` + pub(super) fn var_or_use_path_span(self) -> Span { + match self { + UseSpans::ClosureUse { path_span: span, .. } + | UseSpans::PatUse(span) + | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, + } + } + + /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span` pub(super) fn var_or_use(self) -> Span { match self { - UseSpans::ClosureUse { var_span: span, .. } + UseSpans::ClosureUse { capture_kind_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, UseSpans::FnSelfUse { @@ -637,13 +653,34 @@ impl UseSpans<'_> { } // Add a span label to the use of the captured variable, if it exists. + // only adds label to the `path_span` + pub(super) fn var_span_label_path_only( + self, + err: &mut DiagnosticBuilder<'_>, + message: impl Into<String>, + ) { + if let UseSpans::ClosureUse { path_span, .. } = self { + err.span_label(path_span, message); + } + } + + // Add a span label to the use of the captured variable, if it exists. pub(super) fn var_span_label( self, err: &mut DiagnosticBuilder<'_>, message: impl Into<String>, + kind_desc: impl Into<String>, ) { - if let UseSpans::ClosureUse { var_span, .. } = self { - err.span_label(var_span, message); + if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { + if capture_kind_span == path_span { + err.span_label(capture_kind_span, message); + } else { + let capture_kind_label = + format!("capture is {} because of use here", kind_desc.into()); + let path_label = message; + err.span_label(capture_kind_span, capture_kind_label); + err.span_label(path_span, path_label); + } } } @@ -791,10 +828,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { box AggregateKind::Closure(def_id, _) | box AggregateKind::Generator(def_id, _, _) => { debug!("move_spans: def_id={:?} places={:?}", def_id, places); - if let Some((args_span, generator_kind, var_span)) = + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(*def_id, moved_place, places) { - return ClosureUse { generator_kind, args_span, var_span }; + return ClosureUse { + generator_kind, + args_span, + capture_kind_span, + path_span, + }; } } _ => {} @@ -809,10 +851,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | FakeReadCause::ForLet(Some(closure_def_id)) => { debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); let places = &[Operand::Move(*place)]; - if let Some((args_span, generator_kind, var_span)) = + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(closure_def_id, moved_place, places) { - return ClosureUse { generator_kind, args_span, var_span }; + return ClosureUse { + generator_kind, + args_span, + capture_kind_span, + path_span, + }; } } _ => {} @@ -972,10 +1019,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow_spans: def_id={:?} is_generator={:?} places={:?}", def_id, is_generator, places ); - if let Some((args_span, generator_kind, var_span)) = + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(*def_id, Place::from(target).as_ref(), places) { - return ClosureUse { generator_kind, args_span, var_span }; + return ClosureUse { generator_kind, args_span, capture_kind_span, path_span }; } else { return OtherUse(use_span); } @@ -989,13 +1036,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { OtherUse(use_span) } - /// Finds the span of a captured variable within a closure or generator. + /// Finds the spans of a captured place within a closure or generator. + /// The first span is the location of the use resulting in the capture kind of the capture + /// The second span is the location the use resulting in the captured path of the capture fn closure_span( &self, def_id: DefId, target_place: PlaceRef<'tcx>, places: &[Operand<'tcx>], - ) -> Option<(Span, Option<GeneratorKind>, Span)> { + ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> { debug!( "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places @@ -1005,13 +1054,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (captured_place, place) in iter::zip( - self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id), - places, - ) { - let upvar_hir_id = captured_place.get_root_variable(); - //FIXME(project-rfc-2229#8): Use better span from captured_place - let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span; + for (captured_place, place) in self + .infcx + .tcx + .typeck(def_id.expect_local()) + .closure_min_captures_flattened(def_id) + .zip(places) + { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -1020,18 +1069,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let body = self.infcx.tcx.hir().body(*body_id); let generator_kind = body.generator_kind(); - // If we have a more specific span available, point to that. - // We do this even though this span might be part of a borrow error - // message rather than a move error message. Our goal is to point - // to a span that shows why the upvar is used in the closure, - // so a move-related span is as good as any (and potentially better, - // if the overall error is due to a move of the upvar). - - let usage_span = match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue(Some(span)) => span, - _ => span, - }; - return Some((*args_span, generator_kind, usage_span)); + return Some(( + *args_span, + generator_kind, + captured_place.get_capture_kind_span(self.infcx.tcx), + captured_place.get_path_span(self.infcx.tcx), + )); } _ => {} } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index fb7694b7d88..3f87d9c7ac9 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -345,10 +345,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; let upvar = &self.upvars[upvar_field.unwrap().index()]; - // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise - // capture. let upvar_hir_id = upvar.place.get_root_variable(); - let upvar_name = upvar.name; + let upvar_name = upvar.place.to_string(self.infcx.tcx); let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); let place_name = self.describe_any_place(move_place.as_ref()); @@ -478,8 +476,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); - use_spans - .var_span_label(err, format!("move occurs due to use{}", use_spans.describe())); + use_spans.var_span_label( + err, + format!("move occurs due to use{}", use_spans.describe()), + "moved", + ); } } } 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 28f6508cab2..88122777d2e 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.is_upvar_field_projection(access_place.as_ref()).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.upvars[upvar_index.index()].name; + let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); reason = format!(", as `{}` is not declared as mutable", name); } } @@ -195,6 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "mutable borrow occurs due to use of {} in closure", self.describe_any_place(access_place.as_ref()), ), + "mutable", ); borrow_span } @@ -642,15 +643,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .starts_with(&original_method_ident.name.to_string()) }) .map(|ident| format!("{}()", ident)) + .peekable() }); - if let Some(suggestions) = opt_suggestions { - err.span_suggestions( - path_segment.ident.span, - &format!("use mutable method"), - suggestions, - Applicability::MaybeIncorrect, - ); + if let Some(mut suggestions) = opt_suggestions { + if suggestions.peek().is_some() { + err.span_suggestions( + path_segment.ident.span, + &format!("use mutable method"), + suggestions, + Applicability::MaybeIncorrect, + ); + } } } }; 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 058986593a4..8665ef06126 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -385,6 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(*span, message); + // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id if let ReturnConstraint::ClosureUpvar(upvar) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { DefiningTy::Closure(def_id, _) => def_id, diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 2d1d83b1655..4c35be39a3d 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -74,9 +74,6 @@ crate use region_infer::RegionInferenceContext; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] crate struct Upvar<'tcx> { - // FIXME(project-rfc_2229#36): print capture precisely here. - name: Symbol, - place: CapturedPlace<'tcx>, /// If true, the capture is behind a reference. @@ -159,13 +156,12 @@ fn do_mir_borrowck<'a, 'tcx>( let upvars: Vec<_> = tables .closure_min_captures_flattened(def.did.to_def_id()) .map(|captured_place| { - let var_hir_id = captured_place.get_root_variable(); let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, }; - Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref } + Upvar { place: captured_place.clone(), by_ref } }) .collect(); 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 3248554e204..d27fcb2f26f 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -97,7 +97,7 @@ mod relate_tys; /// Type checks the given `mir` in the context of the inference /// context `infcx`. Returns any region constraints that have yet to -/// be proven. This result is includes liveness constraints that +/// be proven. This result includes liveness constraints that /// ensure that regions appearing in the types of all local variables /// are live at all points where that local variable may later be /// used. diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index e621bc9167d..fdefc890674 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -1066,7 +1066,7 @@ struct RootCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode, output: &'a mut Vec<Spanned<MonoItem<'tcx>>>, - entry_fn: Option<(LocalDefId, EntryFnType)>, + entry_fn: Option<(DefId, EntryFnType)>, } impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { @@ -1154,7 +1154,7 @@ impl RootCollector<'_, 'v> { && match self.mode { MonoItemCollectionMode::Eager => true, MonoItemCollectionMode::Lazy => { - self.entry_fn.map(|(id, _)| id) == Some(def_id) + self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) || self.tcx.is_reachable_non_generic(def_id) || self .tcx diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index cf7d404a077..63fc66f2b9f 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -426,7 +426,7 @@ impl Validator<'mir, 'tcx> { ty::PredicateKind::Subtype(_) => { bug!("subtype predicate on function: {:#?}", predicate) } - ty::PredicateKind::Trait(pred, constness) => { + ty::PredicateKind::Trait(pred, _constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } @@ -440,16 +440,7 @@ impl Validator<'mir, 'tcx> { // arguments when determining importance. let kind = LocalKind::Arg; - if constness == hir::Constness::Const { - self.check_op_spanned(ops::ty::TraitBound(kind), span); - } else if !tcx.features().const_fn - || self.ccx.is_const_stable_const_fn() - { - // HACK: We shouldn't need the conditional above, but trait - // bounds on containing impl blocks are wrongly being marked as - // "not-const". - self.check_op_spanned(ops::ty::TraitBound(kind), span); - } + self.check_op_spanned(ops::ty::TraitBound(kind), span); } // other kinds of bounds are either tautologies // or cause errors in other passes diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 3ef03ec21ad..eaeb44289cf 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -23,6 +23,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::hir; use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::ich::StableHashingContext; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator, @@ -87,6 +88,11 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { _ => {} } + let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id()); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + return; + } + trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); Instrumentor::new(&self.name(), tcx, mir_body).inject_counters(); trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 249f5e835cd..b3fc2a0cb5e 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -11,8 +11,9 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::source_map::original_sp; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; +use std::cell::RefCell; use std::cmp::Ordering; #[derive(Debug, Copy, Clone)] @@ -67,6 +68,8 @@ impl CoverageStatement { #[derive(Debug, Clone)] pub(super) struct CoverageSpan { pub span: Span, + pub expn_span: Span, + pub current_macro_or_none: RefCell<Option<Option<Symbol>>>, pub bcb: BasicCoverageBlock, pub coverage_statements: Vec<CoverageStatement>, pub is_closure: bool, @@ -74,12 +77,20 @@ pub(super) struct CoverageSpan { impl CoverageSpan { pub fn for_fn_sig(fn_sig_span: Span) -> Self { - Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false } + Self { + span: fn_sig_span, + expn_span: fn_sig_span, + current_macro_or_none: Default::default(), + bcb: START_BCB, + coverage_statements: vec![], + is_closure: false, + } } pub fn for_statement( statement: &Statement<'tcx>, span: Span, + expn_span: Span, bcb: BasicCoverageBlock, bb: BasicBlock, stmt_index: usize, @@ -94,15 +105,24 @@ impl CoverageSpan { Self { span, + expn_span, + current_macro_or_none: Default::default(), bcb, coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)], is_closure, } } - pub fn for_terminator(span: Span, bcb: BasicCoverageBlock, bb: BasicBlock) -> Self { + pub fn for_terminator( + span: Span, + expn_span: Span, + bcb: BasicCoverageBlock, + bb: BasicBlock, + ) -> Self { Self { span, + expn_span, + current_macro_or_none: Default::default(), bcb, coverage_statements: vec![CoverageStatement::Terminator(bb, span)], is_closure: false, @@ -158,6 +178,38 @@ impl CoverageSpan { .collect::<Vec<_>>() .join("\n") } + + /// If the span is part of a macro, returns the macro name symbol. + pub fn current_macro(&self) -> Option<Symbol> { + self.current_macro_or_none + .borrow_mut() + .get_or_insert_with(|| { + if let ExpnKind::Macro(MacroKind::Bang, current_macro) = + self.expn_span.ctxt().outer_expn_data().kind + { + return Some(current_macro); + } + None + }) + .map(|symbol| symbol) + } + + /// If the span is part of a macro, and the macro is visible (expands directly to the given + /// body_span), returns the macro name symbol. + pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> { + if let Some(current_macro) = self.current_macro() { + if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt() + == body_span.ctxt() + { + return Some(current_macro); + } + } + None + } + + pub fn is_macro_expansion(&self) -> bool { + self.current_macro().is_some() + } } /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a @@ -191,16 +243,23 @@ pub struct CoverageSpans<'a, 'tcx> { /// iteration. some_curr: Option<CoverageSpan>, - /// The original `span` for `curr`, in case the `curr` span is modified. + /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span` + /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()` + /// is mutated. curr_original_span: Span, /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`. /// If that `curr` was discarded, `prev` retains its value from the previous iteration. some_prev: Option<CoverageSpan>, - /// Assigned from `curr_original_span` from the previous iteration. + /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span` + /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()` + /// is mutated. prev_original_span: Span, + /// A copy of the expn_span from the prior iteration. + prev_expn_span: Option<Span>, + /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. /// If a new `curr` span also fits this criteria (compared to an existing list of @@ -255,15 +314,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), some_prev: None, prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), + prev_expn_span: None, pending_dups: Vec::new(), }; let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans(); coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter()); - coverage_spans.some_prev = coverage_spans.sorted_spans_iter.as_mut().unwrap().next(); - coverage_spans.prev_original_span = - coverage_spans.some_prev.as_ref().expect("at least one span").span; coverage_spans.to_refined_spans() } @@ -317,10 +374,14 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// de-duplicated `CoverageSpan`s. fn to_refined_spans(mut self) -> Vec<CoverageSpan> { while self.next_coverage_span() { - if self.curr().is_mergeable(self.prev()) { + if self.some_prev.is_none() { + debug!(" initial span"); + self.check_invoked_macro_name_span(); + } else if self.curr().is_mergeable(self.prev()) { debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); let prev = self.take_prev(); self.curr_mut().merge_from(prev); + self.check_invoked_macro_name_span(); // Note that curr.span may now differ from curr_original_span } else if self.prev_ends_before_curr() { debug!( @@ -329,7 +390,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { self.prev() ); let prev = self.take_prev(); - self.refined_spans.push(prev); + self.push_refined_span(prev); + self.check_invoked_macro_name_span(); } else if self.prev().is_closure { // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // next iter @@ -342,20 +404,45 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } else if self.curr().is_closure { self.carve_out_span_for_closure(); } else if self.prev_original_span == self.curr().span { - // Note that this compares the new span to `prev_original_span`, which may not - // be the full `prev.span` (if merged during the previous iteration). - self.hold_pending_dups_unless_dominated(); + // Note that this compares the new (`curr`) span to `prev_original_span`. + // In this branch, the actual span byte range of `prev_original_span` is not + // important. What is important is knowing whether the new `curr` span was + // **originally** the same as the original span of `prev()`. The original spans + // reflect their original sort order, and for equal spans, conveys a partial + // ordering based on CFG dominator priority. + if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { + // Macros that expand to include branching (such as + // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or + // `trace!()) typically generate callee spans with identical + // ranges (typically the full span of the macro) for all + // `BasicBlocks`. This makes it impossible to distinguish + // the condition (`if val1 != val2`) from the optional + // branched statements (such as the call to `panic!()` on + // assert failure). In this case it is better (or less + // worse) to drop the optional branch bcbs and keep the + // non-conditional statements, to count when reached. + debug!( + " curr and prev are part of a macro expansion, and curr has the same span \ + as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ + prev={:?}", + self.prev() + ); + self.take_curr(); + } else { + self.hold_pending_dups_unless_dominated(); + } } else { self.cutoff_prev_at_overlapping_curr(); + self.check_invoked_macro_name_span(); } } debug!(" AT END, adding last prev={:?}", self.prev()); let prev = self.take_prev(); - let CoverageSpans { pending_dups, mut refined_spans, .. } = self; + let pending_dups = self.pending_dups.split_off(0); for dup in pending_dups { debug!(" ...adding at least one pending dup={:?}", dup); - refined_spans.push(dup); + self.push_refined_span(dup); } // Async functions wrap a closure that implements the body to be executed. The enclosing @@ -365,21 +452,60 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { // excluded. The closure's `Return` is the only one that will be counted. This provides // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace // of the function body.) - let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() { + let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() { last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() } else { false }; if !body_ends_with_closure { - refined_spans.push(prev); + self.push_refined_span(prev); } // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage // regions for the current function leave room for the closure's own coverage regions // (injected separately, from the closure's own MIR). - refined_spans.retain(|covspan| !covspan.is_closure); - refined_spans + self.refined_spans.retain(|covspan| !covspan.is_closure); + self.refined_spans + } + + fn push_refined_span(&mut self, covspan: CoverageSpan) { + let len = self.refined_spans.len(); + if len > 0 { + let last = &mut self.refined_spans[len - 1]; + if last.is_mergeable(&covspan) { + debug!( + "merging new refined span with last refined span, last={:?}, covspan={:?}", + last, covspan + ); + last.merge_from(covspan); + return; + } + } + self.refined_spans.push(covspan) + } + + fn check_invoked_macro_name_span(&mut self) { + if let Some(visible_macro) = self.curr().visible_macro(self.body_span) { + if self.prev_expn_span.map_or(true, |prev_expn_span| { + self.curr().expn_span.ctxt() != prev_expn_span.ctxt() + }) { + let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo(); + let after_macro_bang = + merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1); + let mut macro_name_cov = self.curr().clone(); + self.curr_mut().span = + self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang); + macro_name_cov.span = + macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); + debug!( + " and curr starts a new macro expansion, so add a new span just for \ + the macro `{}!`, new span={:?}", + visible_macro, macro_name_cov + ); + self.push_refined_span(macro_name_cov); + } + } } // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of @@ -401,14 +527,17 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { .iter() .enumerate() .filter_map(move |(index, statement)| { - filtered_statement_span(statement, self.body_span).map(|span| { - CoverageSpan::for_statement(statement, span, bcb, bb, index) - }) + filtered_statement_span(statement, self.body_span).map( + |(span, expn_span)| { + CoverageSpan::for_statement( + statement, span, expn_span, bcb, bb, index, + ) + }, + ) }) - .chain( - filtered_terminator_span(data.terminator(), self.body_span) - .map(|span| CoverageSpan::for_terminator(span, bcb, bb)), - ) + .chain(filtered_terminator_span(data.terminator(), self.body_span).map( + |(span, expn_span)| CoverageSpan::for_terminator(span, expn_span, bcb, bb), + )) }) .collect() } @@ -461,7 +590,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { let pending_dups = self.pending_dups.split_off(0); for dup in pending_dups.into_iter() { debug!(" ...adding at least one pending={:?}", dup); - self.refined_spans.push(dup); + self.push_refined_span(dup); } } else { self.pending_dups.clear(); @@ -473,12 +602,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. fn next_coverage_span(&mut self) -> bool { if let Some(curr) = self.some_curr.take() { + self.prev_expn_span = Some(curr.expn_span); self.some_prev = Some(curr); self.prev_original_span = self.curr_original_span; } while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() { debug!("FOR curr={:?}", curr); - if self.prev_starts_after_next(&curr) { + if self.some_prev.is_some() && self.prev_starts_after_next(&curr) { debug!( " prev.span starts after curr.span, so curr will be dropped (skipping past \ closure?); prev={:?}", @@ -535,29 +665,38 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { for mut dup in pending_dups.iter().cloned() { dup.span = dup.span.with_hi(left_cutoff); debug!(" ...and at least one pre_closure dup={:?}", dup); - self.refined_spans.push(dup); + self.push_refined_span(dup); } } - self.refined_spans.push(pre_closure); + self.push_refined_span(pre_closure); } if has_post_closure_span { - // Update prev.span to start after the closure (and discard curr) + // Mutate `prev.span()` to start after the closure (and discard curr). + // (**NEVER** update `prev_original_span` because it affects the assumptions + // about how the `CoverageSpan`s are ordered.) self.prev_mut().span = self.prev().span.with_lo(right_cutoff); - self.prev_original_span = self.prev().span; + debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); for dup in pending_dups.iter_mut() { + debug!(" ...and at least one overlapping dup={:?}", dup); dup.span = dup.span.with_lo(right_cutoff); } self.pending_dups.append(&mut pending_dups); let closure_covspan = self.take_curr(); - self.refined_spans.push(closure_covspan); // since self.prev() was already updated + self.push_refined_span(closure_covspan); // since self.prev() was already updated } else { pending_dups.clear(); } } /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all - /// `pending_dups` spans, if any); but keep in mind, `prev.span` may start at a `Span.lo()` that - /// is less than (further left of) `prev_original_span.lo()`. + /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. + /// If prev.span() was merged into other spans (with matching BCB, for instance), + /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. + /// If prev.span() was split off to the right of a closure, prev.span().lo() will be + /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is + /// not as important as knowing that `prev()` **used to have the same span** as `curr(), + /// which means their sort order is still meaningful for determinating the dominator + /// relationship. /// /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, @@ -640,7 +779,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } else { debug!(" ... adding modified prev={:?}", self.prev()); let prev = self.take_prev(); - self.refined_spans.push(prev); + self.push_refined_span(prev); } } else { // with `pending_dups`, `prev` cannot have any statements that don't overlap @@ -653,10 +792,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } } +/// See `function_source_span()` for a description of the two returned spans. +/// If the MIR `Statement` is not contributive to computing coverage spans, +/// returns `None`. pub(super) fn filtered_statement_span( statement: &'a Statement<'tcx>, body_span: Span, -) -> Option<Span> { +) -> Option<(Span, Span)> { match statement.kind { // These statements have spans that are often outside the scope of the executed source code // for their parent `BasicBlock`. @@ -698,10 +840,13 @@ pub(super) fn filtered_statement_span( } } +/// See `function_source_span()` for a description of the two returned spans. +/// If the MIR `Terminator` is not contributive to computing coverage spans, +/// returns `None`. pub(super) fn filtered_terminator_span( terminator: &'a Terminator<'tcx>, body_span: Span, -) -> Option<Span> { +) -> Option<(Span, Span)> { match terminator.kind { // These terminators have spans that don't positively contribute to computing a reasonable // span of actually executed source code. (For example, SwitchInt terminators extracted from @@ -717,11 +862,21 @@ pub(super) fn filtered_terminator_span( | TerminatorKind::FalseEdge { .. } | TerminatorKind::Goto { .. } => None, + // Call `func` operand can have a more specific span when part of a chain of calls + | TerminatorKind::Call { ref func, .. } => { + let mut span = terminator.source_info.span; + if let mir::Operand::Constant(box constant) = func { + if constant.span.lo() > span.lo() { + span = span.with_lo(constant.span.lo()); + } + } + Some(function_source_span(span, body_span)) + } + // Retain spans from all other terminators TerminatorKind::Resume | TerminatorKind::Abort | TerminatorKind::Return - | TerminatorKind::Call { .. } | TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop | TerminatorKind::FalseUnwind { .. } @@ -731,8 +886,23 @@ pub(super) fn filtered_terminator_span( } } +/// Returns two spans from the given span (the span associated with a +/// `Statement` or `Terminator`): +/// +/// 1. An extrapolated span (pre-expansion[^1]) corresponding to a range within +/// the function's body source. This span is guaranteed to be contained +/// within, or equal to, the `body_span`. If the extrapolated span is not +/// contained within the `body_span`, the `body_span` is returned. +/// 2. The actual `span` value from the `Statement`, before expansion. +/// +/// Only the first span is used when computing coverage code regions. The second +/// span is useful if additional expansion data is needed (such as to look up +/// the macro name for a composed span within that macro).) +/// +/// [^1]Expansions result from Rust syntax including macros, syntactic +/// sugar, etc.). #[inline] -fn function_source_span(span: Span, body_span: Span) -> Span { - let span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); - if body_span.contains(span) { span } else { body_span } +fn function_source_span(span: Span, body_span: Span) -> (Span, Span) { + let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); + (if body_span.contains(original_span) { original_span } else { body_span }, span) } diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs index dee112443d3..9b84173c8a2 100644 --- a/compiler/rustc_mir/src/transform/coverage/tests.rs +++ b/compiler/rustc_mir/src/transform/coverage/tests.rs @@ -1,6 +1,10 @@ //! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR //! pass. //! +//! ```shell +//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage' +//! ``` +//! //! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage` //! functions and algorithms. Mocked objects include instances of `mir::Body`; including //! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on @@ -679,10 +683,15 @@ fn test_make_bcb_counters() { let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); let mut coverage_spans = Vec::new(); for (bcb, data) in basic_coverage_blocks.iter_enumerated() { - if let Some(span) = + if let Some((span, expn_span)) = spans::filtered_terminator_span(data.terminator(&mir_body), body_span) { - coverage_spans.push(spans::CoverageSpan::for_terminator(span, bcb, data.last_bb())); + coverage_spans.push(spans::CoverageSpan::for_terminator( + span, + expn_span, + bcb, + data.last_bb(), + )); } } let mut coverage_counters = counters::CoverageCounters::new(0); diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs index a9a30e407b4..9abfa4a8dc6 100644 --- a/compiler/rustc_mir/src/util/spanview.rs +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -99,7 +99,11 @@ where W: Write, { let def_id = body.source.def_id(); - let body_span = hir_body(tcx, def_id).value.span; + let hir_body = hir_body(tcx, def_id); + if hir_body.is_none() { + return Ok(()); + } + let body_span = hir_body.unwrap().value.span; let mut span_viewables = Vec::new(); for (bb, data) in body.basic_blocks().iter_enumerated() { match spanview { @@ -664,19 +668,16 @@ fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); let fn_decl_span = tcx.hir().span(hir_id); - let body_span = hir_body(tcx, def_id).value.span; - if fn_decl_span.ctxt() == body_span.ctxt() { - fn_decl_span.to(body_span) + if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) { + if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span } } else { - // This probably occurs for functions defined via macros - body_span + fn_decl_span } } -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> { let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - tcx.hir().body(fn_body_id) + hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id)) } fn escape_html(s: &str) -> String { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 5c4a2785d6e..0c43e304f1e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -61,7 +61,8 @@ impl<'a> Parser<'a> { }, _ => false, }, - NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind { + NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { + match token.kind { token::Ident(..) | // box, ref, mut, and other identifiers (can stricten) token::OpenDelim(token::Paren) | // tuple pattern token::OpenDelim(token::Bracket) | // slice pattern @@ -75,10 +76,11 @@ impl<'a> Parser<'a> { token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) // leading vert `|` or-pattern - token::BinOp(token::Or) => matches!(kind, NonterminalKind::Pat2021 {..}), + token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}), token::Interpolated(ref nt) => may_be_ident(nt), _ => false, - }, + } + } NonterminalKind::Lifetime => match token.kind { token::Lifetime(_) => true, token::Interpolated(ref nt) => { @@ -118,10 +120,10 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, "expected a statement")); } }, - NonterminalKind::Pat2015 { .. } | NonterminalKind::Pat2021 { .. } => { + NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { token::NtPat(self.collect_tokens_no_attrs(|this| match kind { - NonterminalKind::Pat2015 { .. } => this.parse_pat_no_top_alt(None), - NonterminalKind::Pat2021 { .. } => { + NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None), + NonterminalKind::PatWithOr { .. } => { this.parse_pat_allow_top_alt(None, RecoverComma::No) } _ => unreachable!(), diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c63edf365a1..d32180525bf 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>( ) .chain( // Seed entry point - tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().local_def_id_to_hir_id(def_id)), + tcx.entry_fn(LOCAL_CRATE).and_then(|(def_id, _)| { + def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + }), ) .collect::<Vec<_>>(); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e1b750df33c..65cfe986ad4 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,12 +1,13 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; -use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID}; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, EntryFnType}; +use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> { map: Map<'tcx>, - /// The top-level function called `main`. - main_fn: Option<(HirId, Span)>, - /// The function that has attribute named `main`. attr_main_fn: Option<(HirId, Span)>, @@ -50,7 +48,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } } -fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> { +fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> { assert_eq!(cnum, LOCAL_CRATE); let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable); @@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType) let mut ctxt = EntryContext { session: tcx.sess, map: tcx.hir(), - main_fn: None, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new(), @@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { throw_attr_err(&ctxt.session, attr.span, "rustc_main"); } } - EntryPointType::MainNamed => { - if ctxt.main_fn.is_none() { - ctxt.main_fn = Some((item.hir_id(), item.span)); - } else { - struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions") - .emit(); - } - } + EntryPointType::MainNamed => (), EntryPointType::OtherMain => { ctxt.non_main_fns.push((item.hir_id(), item.span)); } @@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) { } } -fn configure_main( - tcx: TyCtxt<'_>, - visitor: &EntryContext<'_, '_>, -) -> Option<(LocalDefId, EntryFnType)> { +fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> { if let Some((hir_id, _)) = visitor.start_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start)) + Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start)) } else if let Some((hir_id, _)) = visitor.attr_main_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main)) - } else if let Some((hir_id, _)) = visitor.main_fn { - Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main)) + Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main)) + } else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) { + if tcx.main_def.unwrap().is_import && !tcx.features().imported_main { + let span = tcx.main_def.unwrap().span; + feature_err( + &tcx.sess.parse_sess, + sym::imported_main, + span, + "using an imported function as entry point `main` is experimental", + ) + .emit(); + } + Some((def_id, EntryFnType::Main)) } else { no_main_err(tcx, visitor); None @@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { } else { err.note(¬e); } + + if let Some(main_def) = tcx.main_def { + if main_def.opt_fn_def_id().is_none() { + // There is something at `crate::main`, but it is not a function definition. + err.span_label(main_def.span, &format!("non-function item at `crate::main` is found")); + } + } + if tcx.sess.teach(&err.get_code().unwrap()) { err.note( "If you don't know the basics of Rust, you can go look to the Rust Book \ @@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { err.emit(); } -pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(LocalDefId, EntryFnType)> { +pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> { tcx.entry_fn(LOCAL_CRATE) } diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 24485889731..2517793ecea 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -250,8 +250,8 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( // need to invoke queries itself, we cannot keep the query caches // locked while doing so. Instead we copy out the // `(query_key, dep_node_index)` pairs and release the lock again. - let query_keys_and_indices: Vec<_> = query_cache - .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect()); + let mut query_keys_and_indices = Vec::new(); + query_cache.iter_results(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i))); // Now actually allocate the strings. If allocating the strings // generates new entries in the query cache, we'll miss them but @@ -275,14 +275,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>( let query_name = profiler.get_or_alloc_cached_string(query_name); let event_id = event_id_builder.from_label(query_name).to_string_id(); - query_cache.iter_results(|results| { - let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect(); - - profiler.bulk_map_query_invocation_id_to_single_string( - query_invocation_ids.into_iter(), - event_id, - ); + let mut query_invocation_ids = Vec::new(); + query_cache.iter_results(&mut |_, _, i| { + query_invocation_ids.push(i.into()); }); + + profiler.bulk_map_query_invocation_id_to_single_string( + query_invocation_ids.into_iter(), + event_id, + ); } }); } diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs index 4d52483c3b8..e877034bd7b 100644 --- a/compiler/rustc_query_impl/src/stats.rs +++ b/compiler/rustc_query_impl/src/stats.rs @@ -50,13 +50,12 @@ where key_type: type_name::<C::Key>(), value_size: mem::size_of::<C::Value>(), value_type: type_name::<C::Value>(), - entry_count: map.iter_results(|results| results.count()), + entry_count: 0, local_def_id_keys: None, }; - map.iter_results(|results| { - for (key, _, _) in results { - key.key_stats(&mut stats) - } + map.iter_results(&mut |key, _, _| { + stats.entry_count += 1; + key.key_stats(&mut stats) }); stats } diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 001bf3b216b..2e4c8d0565a 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -49,13 +49,11 @@ pub trait QueryCache: QueryStorage { index: DepNodeIndex, ) -> Self::Stored; - fn iter<R>( + fn iter( &self, shards: &Sharded<Self::Sharded>, - f: impl for<'a> FnOnce( - &'a mut dyn Iterator<Item = (&'a Self::Key, &'a Self::Value, DepNodeIndex)>, - ) -> R, - ) -> R; + f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex), + ); } pub struct DefaultCacheSelector; @@ -124,14 +122,17 @@ where value } - fn iter<R>( + fn iter( &self, shards: &Sharded<Self::Sharded>, - f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R, - ) -> R { + f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex), + ) { let shards = shards.lock_shards(); - let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); - f(&mut results) + for shard in shards.iter() { + for (k, v) in shard.iter() { + f(k, &v.0, v.1); + } + } } } @@ -207,13 +208,16 @@ where &value.0 } - fn iter<R>( + fn iter( &self, shards: &Sharded<Self::Sharded>, - f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R, - ) -> R { + f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex), + ) { let shards = shards.lock_shards(); - let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); - f(&mut results) + for shard in shards.iter() { + for (k, v) in shard.iter() { + f(k, &v.0, v.1); + } + } } } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index fb8a53048fa..c9125b3ffe9 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -73,12 +73,7 @@ impl<C: QueryCache> QueryCacheStore<C> { (QueryLookup { key_hash, shard }, lock) } - pub fn iter_results<R>( - &self, - f: impl for<'a> FnOnce( - &'a mut dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)>, - ) -> R, - ) -> R { + pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex)) { self.cache.iter(&self.shards, f) } } @@ -130,18 +125,15 @@ where // We use try_lock_shards here since we are called from the // deadlock handler, and this shouldn't be locked. let shards = self.shards.try_lock_shards()?; - let shards = shards.iter().enumerate(); - jobs.extend(shards.flat_map(|(shard_id, shard)| { - shard.active.iter().filter_map(move |(k, v)| { + for (shard_id, shard) in shards.iter().enumerate() { + for (k, v) in shard.active.iter() { if let QueryResult::Started(ref job) = *v { let id = QueryJobId::new(job.id, shard_id, kind); let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) }; - Some((id, QueryJobInfo { info, job: job.clone() })) - } else { - None + jobs.insert(id, QueryJobInfo { info, job: job.clone() }); } - }) - })); + } + } Some(()) } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c5f12c0c691..6ea46f5c528 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -487,7 +487,13 @@ impl<'a> Resolver<'a> { name )); } - err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions"); + + if self.session.is_nightly_build() { + err.help( + "use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` \ + to allow generic const expressions" + ); + } err } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1d1969f7e78..9197f4059ca 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -50,7 +50,7 @@ use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, DefIdTree, ResolverOutputs}; +use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -1021,6 +1021,8 @@ pub struct Resolver<'a> { trait_impl_items: FxHashSet<LocalDefId>, legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>, + + main_def: Option<MainDefinition>, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1348,6 +1350,7 @@ impl<'a> Resolver<'a> { next_disambiguator: Default::default(), trait_impl_items: Default::default(), legacy_const_generic_args: Default::default(), + main_def: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1382,6 +1385,7 @@ impl<'a> Resolver<'a> { let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; + let main_def = self.main_def; ResolverOutputs { definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1396,6 +1400,7 @@ impl<'a> Resolver<'a> { .iter() .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) .collect(), + main_def, } } @@ -1414,6 +1419,7 @@ impl<'a> Resolver<'a> { .iter() .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) .collect(), + main_def: self.main_def.clone(), } } @@ -1459,6 +1465,7 @@ impl<'a> Resolver<'a> { self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports()); self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.session.time("late_resolve_crate", || self.late_resolve_crate(krate)); + self.session.time("resolve_main", || self.resolve_main()); self.session.time("resolve_check_unused", || self.check_unused(krate)); self.session.time("resolve_report_errors", || self.report_errors(krate)); self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate)); @@ -3350,6 +3357,32 @@ impl<'a> Resolver<'a> { } None } + + fn resolve_main(&mut self) { + let module = self.graph_root; + let ident = Ident::with_dummy_span(sym::main); + let parent_scope = &ParentScope::module(module, self); + + let name_binding = match self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ValueNS, + parent_scope, + false, + DUMMY_SP, + ) { + Ok(name_binding) => name_binding, + _ => return, + }; + + let res = name_binding.res(); + let is_import = name_binding.is_import(); + let span = name_binding.span; + if let Res::Def(DefKind::Fn, _) = res { + self.record_use(ident, ValueNS, name_binding, false); + } + self.main_def = Some(MainDefinition { res, is_import, span }); + } } fn names_to_string(names: &[Symbol]) -> String { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 52a6e4ff924..1f5cb5b8abc 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -156,7 +156,7 @@ pub enum InstrumentCoverage { Off, } -#[derive(Clone, PartialEq, Hash)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), LinkerPluginAuto, @@ -172,7 +172,7 @@ impl LinkerPluginLto { } } -#[derive(Clone, PartialEq, Hash)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum SwitchWithOptPath { Enabled(Option<PathBuf>), Disabled, @@ -702,6 +702,7 @@ impl Default for Options { cli_forced_codegen_units: None, cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), + real_rust_source_base_dir: None, edition: DEFAULT_EDITION, json_artifact_notifications: false, json_unused_externs: false, @@ -778,7 +779,7 @@ pub enum CrateType { impl_stable_hash_via_hash!(CrateType); -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub enum Passes { Some(Vec<String>), All, @@ -1980,6 +1981,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } + // Try to find a directory containing the Rust `src`, for more details see + // the doc comment on the `real_rust_source_base_dir` field. + let tmp_buf; + let sysroot = match &sysroot_opt { + Some(s) => s, + None => { + tmp_buf = crate::filesearch::get_or_default_sysroot(); + &tmp_buf + } + }; + let real_rust_source_base_dir = { + // This is the location used by the `rust-src` `rustup` component. + let mut candidate = sysroot.join("lib/rustlib/src/rust"); + if let Ok(metadata) = candidate.symlink_metadata() { + // Replace the symlink rustbuild creates, with its destination. + // We could try to use `fs::canonicalize` instead, but that might + // produce unnecessarily verbose path. + if metadata.file_type().is_symlink() { + if let Ok(symlink_dest) = std::fs::read_link(&candidate) { + candidate = symlink_dest; + } + } + } + + // Only use this directory if it has a file we can expect to always find. + if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None } + }; + Options { crate_types, optimize: opt_level, @@ -2010,6 +2039,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, + real_rust_source_base_dir, edition, json_artifact_notifications, json_unused_externs, @@ -2374,6 +2404,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); + impl_dep_tracking_hash_for_sortable_vec_of!((PathBuf, PathBuf)); impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index fd26f50da5a..735188768e4 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -20,73 +20,112 @@ use std::num::NonZeroUsize; use std::path::PathBuf; use std::str; -macro_rules! hash_option { - ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => {{}}; - ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => {{ +macro_rules! insert { + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => { if $sub_hashes .insert(stringify!($opt_name), $opt_expr as &dyn dep_tracking::DepTrackingHash) .is_some() { panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name)) } + }; +} + +macro_rules! hash_opt { + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [UNTRACKED]) => {{}}; + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [TRACKED]) => {{ insert!($opt_name, $opt_expr, $sub_hashes) }}; + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $for_crate_hash: ident, [TRACKED_NO_CRATE_HASH]) => {{ + if !$for_crate_hash { + insert!($opt_name, $opt_expr, $sub_hashes) + } }}; + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [SUBSTRUCT]) => {{}}; +} + +macro_rules! hash_substruct { + ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [UNTRACKED]) => {{}}; + ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED]) => {{}}; + ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED_NO_CRATE_HASH]) => {{}}; + ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [SUBSTRUCT]) => { + use crate::config::dep_tracking::DepTrackingHash; + $opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash($hasher, $error_format); + }; } macro_rules! top_level_options { - (pub struct Options { $( - $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*], + ( $( #[$top_level_attr:meta] )* pub struct Options { $( + $( #[$attr:meta] )* + $opt:ident : $t:ty [$dep_tracking_marker:ident], )* } ) => ( #[derive(Clone)] + $( #[$top_level_attr] )* pub struct Options { - $(pub $opt: $t),* + $( + $( #[$attr] )* + pub $opt: $t + ),* } impl Options { - pub fn dep_tracking_hash(&self) -> u64 { + pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> u64 { let mut sub_hashes = BTreeMap::new(); $({ - hash_option!($opt, - &self.$opt, - &mut sub_hashes, - [$dep_tracking_marker $($warn_val, - $warn_text, - self.error_format)*]); + hash_opt!($opt, + &self.$opt, + &mut sub_hashes, + for_crate_hash, + [$dep_tracking_marker]); })* let mut hasher = DefaultHasher::new(); dep_tracking::stable_hash(sub_hashes, &mut hasher, self.error_format); + $({ + hash_substruct!($opt, + &self.$opt, + self.error_format, + for_crate_hash, + &mut hasher, + [$dep_tracking_marker]); + })* hasher.finish() } } ); } -// The top-level command-line options struct. -// -// For each option, one has to specify how it behaves with regard to the -// dependency tracking system of incremental compilation. This is done via the -// square-bracketed directive after the field type. The options are: -// -// [TRACKED] -// A change in the given field will cause the compiler to completely clear the -// incremental compilation cache before proceeding. -// -// [UNTRACKED] -// Incremental compilation is not influenced by this option. -// -// If you add a new option to this struct or one of the sub-structs like -// `CodegenOptions`, think about how it influences incremental compilation. If in -// doubt, specify [TRACKED], which is always "correct" but might lead to -// unnecessary re-compilation. top_level_options!( + /// The top-level command-line options struct. + /// + /// For each option, one has to specify how it behaves with regard to the + /// dependency tracking system of incremental compilation. This is done via the + /// square-bracketed directive after the field type. The options are: + /// + /// - `[TRACKED]` + /// A change in the given field will cause the compiler to completely clear the + /// incremental compilation cache before proceeding. + /// + /// - `[TRACKED_NO_CRATE_HASH]` + /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that only + /// affect the incremental cache. + /// + /// - `[UNTRACKED]` + /// Incremental compilation is not influenced by this option. + /// + /// - `[SUBSTRUCT]` + /// Second-level sub-structs containing more options. + /// + /// If you add a new option to this struct or one of the sub-structs like + /// `CodegenOptions`, think about how it influences incremental compilation. If in + /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to + /// unnecessary re-compilation. pub struct Options { - // The crate config requested for the session, which may be combined - // with additional crate configurations during the compile process. + /// The crate config requested for the session, which may be combined + /// with additional crate configurations during the compile process. crate_types: Vec<CrateType> [TRACKED], optimize: OptLevel [TRACKED], - // Include the `debug_assertions` flag in dependency tracking, since it - // can influence whether overflow checks are done or not. + /// Include the `debug_assertions` flag in dependency tracking, since it + /// can influence whether overflow checks are done or not. debug_assertions: bool [TRACKED], debuginfo: DebugInfo [TRACKED], lint_opts: Vec<(String, lint::Level)> [TRACKED], @@ -102,52 +141,60 @@ top_level_options!( test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], - // If `Some`, enable incremental compilation, using the given - // directory to store intermediate results. + /// If `Some`, enable incremental compilation, using the given + /// directory to store intermediate results. incremental: Option<PathBuf> [UNTRACKED], - debugging_opts: DebuggingOptions [TRACKED], + debugging_opts: DebuggingOptions [SUBSTRUCT], prints: Vec<PrintRequest> [UNTRACKED], - // Determines which borrow checker(s) to run. This is the parsed, sanitized - // version of `debugging_opts.borrowck`, which is just a plain string. + /// Determines which borrow checker(s) to run. This is the parsed, sanitized + /// version of `debugging_opts.borrowck`, which is just a plain string. borrowck_mode: BorrowckMode [UNTRACKED], - cg: CodegenOptions [TRACKED], + cg: CodegenOptions [SUBSTRUCT], externs: Externs [UNTRACKED], extern_dep_specs: ExternDepSpecs [UNTRACKED], crate_name: Option<String> [TRACKED], - // An optional name to use as the crate for std during std injection, - // written `extern crate name as std`. Defaults to `std`. Used by - // out-of-tree drivers. + /// An optional name to use as the crate for std during std injection, + /// written `extern crate name as std`. Defaults to `std`. Used by + /// out-of-tree drivers. alt_std_name: Option<String> [TRACKED], - // Indicates how the compiler should treat unstable features. + /// Indicates how the compiler should treat unstable features. unstable_features: UnstableFeatures [TRACKED], - // Indicates whether this run of the compiler is actually rustdoc. This - // is currently just a hack and will be removed eventually, so please - // try to not rely on this too much. + /// Indicates whether this run of the compiler is actually rustdoc. This + /// is currently just a hack and will be removed eventually, so please + /// try to not rely on this too much. actually_rustdoc: bool [TRACKED], - // Control path trimming. + /// Control path trimming. trimmed_def_paths: TrimmedDefPaths [TRACKED], - // Specifications of codegen units / ThinLTO which are forced as a - // result of parsing command line options. These are not necessarily - // what rustc was invoked with, but massaged a bit to agree with - // commands like `--emit llvm-ir` which they're often incompatible with - // if we otherwise use the defaults of rustc. + /// Specifications of codegen units / ThinLTO which are forced as a + /// result of parsing command line options. These are not necessarily + /// what rustc was invoked with, but massaged a bit to agree with + /// commands like `--emit llvm-ir` which they're often incompatible with + /// if we otherwise use the defaults of rustc. cli_forced_codegen_units: Option<usize> [UNTRACKED], cli_forced_thinlto_off: bool [UNTRACKED], - // Remap source path prefixes in all output (messages, object files, debug, etc.). - remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], + /// Remap source path prefixes in all output (messages, object files, debug, etc.). + remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH], + /// Base directory containing the `src/` for the Rust standard library, and + /// potentially `rustc` as well, if we can can find it. Right now it's always + /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component). + /// + /// This directory is what the virtual `/rustc/$hash` is translated back to, + /// if Rust was built with path remapping to `/rustc/$hash` enabled + /// (the `rust.remap-debuginfo` option in `config.toml`). + real_rust_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH], edition: Edition [TRACKED], - // `true` if we're emitting JSON blobs about each artifact produced - // by the compiler. + /// `true` if we're emitting JSON blobs about each artifact produced + /// by the compiler. json_artifact_notifications: bool [TRACKED], - // `true` if we're emitting a JSON blob containing the unused externs + /// `true` if we're emitting a JSON blob containing the unused externs json_unused_externs: bool [UNTRACKED], pretty: Option<PpMode> [UNTRACKED], @@ -165,11 +212,11 @@ top_level_options!( macro_rules! options { ($struct_name:ident, $setter_name:ident, $defaultfn:ident, $buildfn:ident, $prefix:expr, $outputname:expr, - $stat:ident, $mod_desc:ident, $mod_set:ident, - $($opt:ident : $t:ty = ( + $stat:ident, + $($( #[$attr:meta] )* $opt:ident : $t:ty = ( $init:expr, $parse:ident, - [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*], + [$dep_tracking_marker:ident], $desc:expr) ),* ,) => ( @@ -177,7 +224,7 @@ macro_rules! options { pub struct $struct_name { $(pub $opt: $t),* } pub fn $defaultfn() -> $struct_name { - $struct_name { $($opt: $init),* } + $struct_name { $( $( #[$attr] )* $opt: $init),* } } pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name @@ -219,563 +266,590 @@ macro_rules! options { return op; } - impl dep_tracking::DepTrackingHash for $struct_name { - fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { + impl $struct_name { + fn dep_tracking_hash(&self, _for_crate_hash: bool, error_format: ErrorOutputType) -> u64 { let mut sub_hashes = BTreeMap::new(); $({ - hash_option!($opt, - &self.$opt, - &mut sub_hashes, - [$dep_tracking_marker $($dep_warn_val, - $dep_warn_text, - error_format)*]); + hash_opt!($opt, + &self.$opt, + &mut sub_hashes, + _for_crate_hash, + [$dep_tracking_marker]); })* - dep_tracking::stable_hash(sub_hashes, hasher, error_format); + let mut hasher = DefaultHasher::new(); + dep_tracking::stable_hash(sub_hashes, + &mut hasher, + error_format); + hasher.finish() } } pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool; pub const $stat: &[(&str, $setter_name, &str, &str)] = - &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ]; - - #[allow(non_upper_case_globals, dead_code)] - mod $mod_desc { - pub const parse_no_flag: &str = "no value"; - pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`"; - pub const parse_opt_bool: &str = parse_bool; - pub const parse_string: &str = "a string"; - pub const parse_opt_string: &str = parse_string; - pub const parse_string_push: &str = parse_string; - pub const parse_opt_pathbuf: &str = "a path"; - pub const parse_pathbuf_push: &str = parse_opt_pathbuf; - pub const parse_list: &str = "a space-separated list of strings"; - pub const parse_opt_list: &str = parse_list; - pub const parse_opt_comma_list: &str = "a comma-separated list of strings"; - pub const parse_number: &str = "a number"; - pub const parse_opt_number: &str = parse_number; - pub const parse_threads: &str = parse_number; - pub const parse_passes: &str = "a space-separated list of passes, or `all`"; - pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; - pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`"; - pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; - pub const parse_cfguard: &str = - "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; - pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; - pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); - pub const parse_optimization_fuel: &str = "crate=integer"; - pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; - pub const parse_instrument_coverage: &str = "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; - pub const parse_unpretty: &str = "`string` or `string=string`"; - pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; - pub const parse_lto: &str = - "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; - pub const parse_linker_plugin_lto: &str = - "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin"; - pub const parse_switch_with_opt_path: &str = - "an optional path to the profiling data output directory"; - pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; - pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; - pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; - pub const parse_relocation_model: &str = - "one of supported relocation models (`rustc --print relocation-models`)"; - pub const parse_code_model: &str = - "one of supported code models (`rustc --print code-models`)"; - pub const parse_tls_model: &str = - "one of supported TLS models (`rustc --print tls-models`)"; - 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`)"; + &[ $( (stringify!($opt), crate::options::parse::$opt, $crate::options::desc::$parse, $desc) ),* ]; + + // Sometimes different options need to build a common structure. + // That structure can kept in one of the options' fields, the others become dummy. + macro_rules! redirect_field { + ($cg:ident.link_arg) => { $cg.link_args }; + ($cg:ident.pre_link_arg) => { $cg.pre_link_args }; + ($cg:ident.$field:ident) => { $cg.$field }; } - #[allow(dead_code)] - mod $mod_set { - use super::*; - use std::str::FromStr; - - // Sometimes different options need to build a common structure. - // That structure can kept in one of the options' fields, the others become dummy. - macro_rules! redirect_field { - ($cg:ident.link_arg) => { $cg.link_args }; - ($cg:ident.pre_link_arg) => { $cg.pre_link_args }; - ($cg:ident.$field:ident) => { $cg.$field }; + $( + pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { + $crate::options::parse::$parse(&mut redirect_field!(cg.$opt), v) } + )* - $( - pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { - $parse(&mut redirect_field!(cg.$opt), v) - } - )* - - /// This is for boolean options that don't take a value and start with - /// `no-`. This style of option is deprecated. - fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool { - match v { - None => { *slot = true; true } - Some(_) => false, - } - } +) } - /// Use this for any boolean option that has a static default. - fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool { - match v { - Some("y") | Some("yes") | Some("on") | None => { *slot = true; true } - Some("n") | Some("no") | Some("off") => { *slot = false; true } - _ => false, - } - } +#[allow(non_upper_case_globals)] +mod desc { + pub const parse_no_flag: &str = "no value"; + pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`"; + pub const parse_opt_bool: &str = parse_bool; + pub const parse_string: &str = "a string"; + pub const parse_opt_string: &str = parse_string; + pub const parse_string_push: &str = parse_string; + pub const parse_opt_pathbuf: &str = "a path"; + pub const parse_list: &str = "a space-separated list of strings"; + pub const parse_opt_comma_list: &str = "a comma-separated list of strings"; + pub const parse_number: &str = "a number"; + pub const parse_opt_number: &str = parse_number; + pub const parse_threads: &str = parse_number; + pub const parse_passes: &str = "a space-separated list of passes, or `all`"; + pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; + pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; + pub const parse_sanitizers: &str = + "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`"; + pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; + pub const parse_cfguard: &str = + "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; + pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; + pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); + pub const parse_optimization_fuel: &str = "crate=integer"; + pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; + pub const parse_instrument_coverage: &str = + "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; + pub const parse_unpretty: &str = "`string` or `string=string`"; + pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; + pub const parse_lto: &str = + "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; + pub const parse_linker_plugin_lto: &str = + "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin"; + pub const parse_switch_with_opt_path: &str = + "an optional path to the profiling data output directory"; + pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; + pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; + pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; + pub const parse_relocation_model: &str = + "one of supported relocation models (`rustc --print relocation-models`)"; + pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)"; + pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)"; + 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`)"; +} - /// Use this for any boolean option that lacks a static default. (The - /// actions taken when such an option is not specified will depend on - /// other factors, such as other options, or target options.) - fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool { - match v { - Some("y") | Some("yes") | Some("on") | None => { *slot = Some(true); true } - Some("n") | Some("no") | Some("off") => { *slot = Some(false); true } - _ => false, +mod parse { + crate use super::*; + use std::str::FromStr; + + /// This is for boolean options that don't take a value and start with + /// `no-`. This style of option is deprecated. + crate fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool { + match v { + None => { + *slot = true; + true } + Some(_) => false, } + } - /// Use this for any string option that has a static default. - fn parse_string(slot: &mut String, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.to_string(); true }, - None => false, + /// Use this for any boolean option that has a static default. + crate fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool { + match v { + Some("y") | Some("yes") | Some("on") | None => { + *slot = true; + true } + Some("n") | Some("no") | Some("off") => { + *slot = false; + true + } + _ => false, } + } - /// Use this for any string option that lacks a static default. - fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = Some(s.to_string()); true }, - None => false, + /// Use this for any boolean option that lacks a static default. (The + /// actions taken when such an option is not specified will depend on + /// other factors, such as other options, or target options.) + crate fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool { + match v { + Some("y") | Some("yes") | Some("on") | None => { + *slot = Some(true); + true + } + Some("n") | Some("no") | Some("off") => { + *slot = Some(false); + true } + _ => false, } + } - fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = Some(PathBuf::from(s)); true }, - None => false, + /// Use this for any string option that has a static default. + crate fn parse_string(slot: &mut String, v: Option<&str>) -> bool { + match v { + Some(s) => { + *slot = s.to_string(); + true } + None => false, } + } - fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool { - match v { - Some(s) => { slot.push(s.to_string()); true }, - None => false, + /// Use this for any string option that lacks a static default. + crate fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool { + match v { + Some(s) => { + *slot = Some(s.to_string()); + true } + None => false, } + } - fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool { - match v { - Some(s) => { slot.push(PathBuf::from(s)); true }, - None => false, + crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool { + match v { + Some(s) => { + *slot = Some(PathBuf::from(s)); + true } + None => false, } + } - fn parse_list(slot: &mut Vec<String>, v: Option<&str>) - -> bool { - match v { - Some(s) => { - slot.extend(s.split_whitespace().map(|s| s.to_string())); - true - }, - None => false, + crate fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool { + match v { + Some(s) => { + slot.push(s.to_string()); + true } + None => false, } + } - fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>) - -> bool { - match v { - Some(s) => { - let v = s.split_whitespace().map(|s| s.to_string()).collect(); - *slot = Some(v); - true - }, - None => false, + crate fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool { + match v { + Some(s) => { + slot.extend(s.split_whitespace().map(|s| s.to_string())); + true } + None => false, } + } - fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) - -> bool { - match v { - Some(s) => { - let v = s.split(',').map(|s| s.to_string()).collect(); - *slot = Some(v); - true - }, - None => false, + crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool { + match v { + Some(s) => { + let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect(); + v.sort_unstable(); + *slot = Some(v); + true } + None => false, } + } - fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { - match v.and_then(|s| s.parse().ok()) { - Some(0) => { *slot = ::num_cpus::get(); true }, - Some(i) => { *slot = i; true }, - None => false + crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(0) => { + *slot = ::num_cpus::get(); + true + } + Some(i) => { + *slot = i; + true } + None => false, } + } - /// Use this for any numeric option that has a static default. - fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool { - match v.and_then(|s| s.parse().ok()) { - Some(i) => { *slot = i; true }, - None => false + /// Use this for any numeric option that has a static default. + crate fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(i) => { + *slot = i; + true } + None => false, } + } - /// Use this for any numeric option that lacks a static default. - fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.parse().ok(); slot.is_some() } - None => false + /// Use this for any numeric option that lacks a static default. + crate fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool { + match v { + Some(s) => { + *slot = s.parse().ok(); + slot.is_some() } + None => false, } + } - fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { - match v { - Some("all") => { - *slot = Passes::All; + crate fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { + match v { + Some("all") => { + *slot = Passes::All; + true + } + v => { + let mut passes = vec![]; + if parse_list(&mut passes, v) { + *slot = Passes::Some(passes); true - } - v => { - let mut passes = vec![]; - if parse_list(&mut passes, v) { - *slot = Passes::Some(passes); - true - } else { - false - } + } else { + false } } } + } - fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool { - match v { - Some("unwind") => *slot = Some(PanicStrategy::Unwind), - Some("abort") => *slot = Some(PanicStrategy::Abort), - _ => return false - } - true + crate fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool { + match v { + Some("unwind") => *slot = Some(PanicStrategy::Unwind), + Some("abort") => *slot = Some(PanicStrategy::Abort), + _ => return false, } + true + } - fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool { - match v { - Some(s) => { - match s.parse::<RelroLevel>() { - Ok(level) => *slot = Some(level), - _ => return false - } - }, - _ => return false - } - true + crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool { + match v { + Some(s) => match s.parse::<RelroLevel>() { + Ok(level) => *slot = Some(level), + _ => return false, + }, + _ => return false, } + true + } - fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool { - if let Some(v) = v { - for s in v.split(',') { - *slot |= match s { - "address" => SanitizerSet::ADDRESS, - "leak" => SanitizerSet::LEAK, - "memory" => SanitizerSet::MEMORY, - "thread" => SanitizerSet::THREAD, - "hwaddress" => SanitizerSet::HWADDRESS, - _ => return false, - } + crate fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool { + if let Some(v) = v { + for s in v.split(',') { + *slot |= match s { + "address" => SanitizerSet::ADDRESS, + "leak" => SanitizerSet::LEAK, + "memory" => SanitizerSet::MEMORY, + "thread" => SanitizerSet::THREAD, + "hwaddress" => SanitizerSet::HWADDRESS, + _ => return false, } - true - } else { - false } + true + } else { + false } + } - fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool { - match v { - Some("2") | None => { *slot = 2; true } - Some("1") => { *slot = 1; true } - Some("0") => { *slot = 0; true } - Some(_) => false, + crate fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool { + match v { + Some("2") | None => { + *slot = 2; + true + } + Some("1") => { + *slot = 1; + true + } + Some("0") => { + *slot = 0; + true } + Some(_) => false, } + } - fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool { - match v { - Some("none") => *slot = Strip::None, - Some("debuginfo") => *slot = Strip::Debuginfo, - Some("symbols") => *slot = Strip::Symbols, - _ => return false, - } - true + crate fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool { + match v { + Some("none") => *slot = Strip::None, + Some("debuginfo") => *slot = Strip::Debuginfo, + Some("symbols") => *slot = Strip::Symbols, + _ => return false, } + true + } - fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - CFGuard::Checks - } else { - CFGuard::Disabled - }; - return true - } + crate fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled }; + return true; } - - *slot = match v { - None => CFGuard::Checks, - Some("checks") => CFGuard::Checks, - Some("nochecks") => CFGuard::NoChecks, - Some(_) => return false, - }; - true } - fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavor::from_str) { - Some(lf) => *slote = Some(lf), - _ => return false, - } - true + *slot = match v { + None => CFGuard::Checks, + Some("checks") => CFGuard::Checks, + Some("nochecks") => CFGuard::NoChecks, + Some(_) => return false, + }; + true + } + + crate fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavor::from_str) { + Some(lf) => *slote = Some(lf), + _ => return false, } + true + } - fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { - match v { - None => false, - Some(s) => { - let parts = s.split('=').collect::<Vec<_>>(); - if parts.len() != 2 { return false; } - let crate_name = parts[0].to_string(); - let fuel = parts[1].parse::<u64>(); - if fuel.is_err() { return false; } - *slot = Some((crate_name, fuel.unwrap())); - true + crate fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::<Vec<_>>(); + if parts.len() != 2 { + return false; + } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::<u64>(); + if fuel.is_err() { + return false; } + *slot = Some((crate_name, fuel.unwrap())); + true } } + } - fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool { - match v { - None => false, - Some(s) if s.split('=').count() <= 2 => { - *slot = Some(s.to_string()); - true - } - _ => false, + crate fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) if s.split('=').count() <= 2 => { + *slot = Some(s.to_string()); + true } + _ => false, } + } - fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - Some(MirSpanview::Statement) - } else { - None - }; - return true - } + crate fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { Some(MirSpanview::Statement) } else { None }; + return true; } - - let v = match v { - None => { - *slot = Some(MirSpanview::Statement); - return true; - } - Some(v) => v, - }; - - *slot = Some(match v.trim_end_matches("s") { - "statement" | "stmt" => MirSpanview::Statement, - "terminator" | "term" => MirSpanview::Terminator, - "block" | "basicblock" => MirSpanview::Block, - _ => return false, - }); - true } - fn parse_instrument_coverage(slot: &mut Option<InstrumentCoverage>, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - Some(InstrumentCoverage::All) - } else { - None - }; - return true - } + let v = match v { + None => { + *slot = Some(MirSpanview::Statement); + return true; } + Some(v) => v, + }; + + *slot = Some(match v.trim_end_matches("s") { + "statement" | "stmt" => MirSpanview::Statement, + "terminator" | "term" => MirSpanview::Terminator, + "block" | "basicblock" => MirSpanview::Block, + _ => return false, + }); + true + } - let v = match v { - None => { - *slot = Some(InstrumentCoverage::All); - return true; - } - Some(v) => v, - }; - - *slot = Some(match v { - "all" => InstrumentCoverage::All, - "except-unused-generics" | "except_unused_generics" => { - InstrumentCoverage::ExceptUnusedGenerics - } - "except-unused-functions" | "except_unused_functions" => { - InstrumentCoverage::ExceptUnusedFunctions - } - "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off, - _ => return false, - }); - true + crate fn parse_instrument_coverage( + slot: &mut Option<InstrumentCoverage>, + v: Option<&str>, + ) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { Some(InstrumentCoverage::All) } else { None }; + return true; + } } - fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.parse().ok(); slot.is_some() } - None => { *slot = NonZeroUsize::new(1); true } + let v = match v { + None => { + *slot = Some(InstrumentCoverage::All); + return true; } - } + Some(v) => v, + }; - fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - LtoCli::Yes - } else { - LtoCli::No - }; - return true - } + *slot = Some(match v { + "all" => InstrumentCoverage::All, + "except-unused-generics" | "except_unused_generics" => { + InstrumentCoverage::ExceptUnusedGenerics } + "except-unused-functions" | "except_unused_functions" => { + InstrumentCoverage::ExceptUnusedFunctions + } + "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off, + _ => return false, + }); + true + } - *slot = match v { - None => LtoCli::NoParam, - Some("thin") => LtoCli::Thin, - Some("fat") => LtoCli::Fat, - Some(_) => return false, - }; - true + crate fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool { + match v { + Some(s) => { + *slot = s.parse().ok(); + slot.is_some() + } + None => { + *slot = NonZeroUsize::new(1); + true + } } + } - fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - LinkerPluginLto::LinkerPluginAuto - } else { - LinkerPluginLto::Disabled - }; - return true - } + crate fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No }; + return true; } - - *slot = match v { - None => LinkerPluginLto::LinkerPluginAuto, - Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)), - }; - true } - fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool { - *slot = match v { - None => SwitchWithOptPath::Enabled(None), - Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))), - }; - true - } + *slot = match v { + None => LtoCli::NoParam, + Some("thin") => LtoCli::Thin, + Some("fat") => LtoCli::Fat, + Some(_) => return false, + }; + true + } - fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool { - match v.and_then(|s| MergeFunctions::from_str(s).ok()) { - Some(mergefunc) => *slot = Some(mergefunc), - _ => return false, + crate fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + LinkerPluginLto::LinkerPluginAuto + } else { + LinkerPluginLto::Disabled + }; + return true; } - true } - fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool { - match v.and_then(|s| RelocModel::from_str(s).ok()) { - Some(relocation_model) => *slot = Some(relocation_model), - None if v == Some("default") => *slot = None, - _ => return false, - } - true + *slot = match v { + None => LinkerPluginLto::LinkerPluginAuto, + Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)), + }; + true + } + + crate fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool { + *slot = match v { + None => SwitchWithOptPath::Enabled(None), + Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))), + }; + true + } + + crate fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool { + match v.and_then(|s| MergeFunctions::from_str(s).ok()) { + Some(mergefunc) => *slot = Some(mergefunc), + _ => return false, } + true + } - fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool { - match v.and_then(|s| CodeModel::from_str(s).ok()) { - Some(code_model) => *slot = Some(code_model), - _ => return false, - } - true + crate fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool { + match v.and_then(|s| RelocModel::from_str(s).ok()) { + Some(relocation_model) => *slot = Some(relocation_model), + None if v == Some("default") => *slot = None, + _ => return false, } + true + } - fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool { - match v.and_then(|s| TlsModel::from_str(s).ok()) { - Some(tls_model) => *slot = Some(tls_model), - _ => return false, - } - true + crate fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool { + match v.and_then(|s| CodeModel::from_str(s).ok()) { + Some(code_model) => *slot = Some(code_model), + _ => return false, } + true + } - fn parse_symbol_mangling_version( - slot: &mut Option<SymbolManglingVersion>, - v: Option<&str>, - ) -> bool { - *slot = match v { - Some("legacy") => Some(SymbolManglingVersion::Legacy), - Some("v0") => Some(SymbolManglingVersion::V0), - _ => return false, - }; - true + crate fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool { + match v.and_then(|s| TlsModel::from_str(s).ok()) { + Some(tls_model) => *slot = Some(tls_model), + _ => return false, } + true + } - fn parse_src_file_hash(slot: &mut Option<SourceFileHashAlgorithm>, v: Option<&str>) -> bool { - match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) { - Some(hash_kind) => *slot = Some(hash_kind), - _ => return false, - } - true + crate fn parse_symbol_mangling_version( + slot: &mut Option<SymbolManglingVersion>, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("legacy") => Some(SymbolManglingVersion::Legacy), + Some("v0") => Some(SymbolManglingVersion::V0), + _ => return false, + }; + true + } + + crate fn parse_src_file_hash( + slot: &mut Option<SourceFileHashAlgorithm>, + v: Option<&str>, + ) -> bool { + match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) { + Some(hash_kind) => *slot = Some(hash_kind), + _ => return false, } + true + } - fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool { - match v { - Some(s) => { - if !slot.is_empty() { - slot.push_str(","); - } - slot.push_str(s); - true + crate fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool { + match v { + Some(s) => { + if !slot.is_empty() { + slot.push_str(","); } - None => false, + slot.push_str(s); + true } + None => false, } + } - fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool { - match v { - Some("command") => *slot = Some(WasiExecModel::Command), - Some("reactor") => *slot = Some(WasiExecModel::Reactor), - _ => return false, - } - true + crate fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool { + match v { + Some("command") => *slot = Some(WasiExecModel::Command), + Some("reactor") => *slot = Some(WasiExecModel::Reactor), + _ => return false, } + true + } - fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool { - match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) { - Some(e) => *slot = Some(e), - _ => return false, - } - true + crate fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool { + match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) { + Some(e) => *slot = Some(e), + _ => return false, } + true } -) } +} options! {CodegenOptions, CodegenSetter, basic_codegen_options, build_codegen_options, "C", "codegen", - CG_OPTIONS, cg_type_desc, cgsetters, + CG_OPTIONS, // This list is in alphabetical order. // @@ -885,7 +959,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, build_debugging_options, "Z", "debugging", - DB_OPTIONS, db_type_desc, dbsetters, + DB_OPTIONS, // This list is in alphabetical order. // @@ -1128,7 +1202,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, parse_switch_with_opt_path, [UNTRACKED], "run the self profiler and output the raw event data"), - // keep this in sync with the event filter names in librustc_data_structures/profiling.rs + /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED], "specify the events recorded by the self profiler; for example: `-Z self-profile-events=default,query-keys` @@ -1140,7 +1214,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show spans for compiler debugging (expr|pat|ty)"), span_debug: bool = (false, parse_bool, [UNTRACKED], "forward proc_macro::Span's `Debug` impl to `Span`"), - // o/w tests have closure@path + /// o/w tests have closure@path span_free_formats: bool = (false, parse_bool, [UNTRACKED], "exclude spans when debug-printing compiler state (default: no)"), src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED], @@ -1161,10 +1235,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "select processor to schedule for (`rustc --print target-cpus` for details)"), thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), - // We default to 1 here since we want to behave like - // a sequential compiler for now. This'll likely be adjusted - // in the future. Note that -Zthreads=0 is the way to get - // the num_cpus behavior. + /// We default to 1 here since we want to behave like + /// a sequential compiler for now. This'll likely be adjusted + /// in the future. Note that -Zthreads=0 is the way to get + /// the num_cpus behavior. threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), time: bool = (false, parse_bool, [UNTRACKED], @@ -1220,7 +1294,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, // - compiler/rustc_interface/src/tests.rs } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, PartialEq, Eq, Debug)] pub enum WasiExecModel { Command, Reactor, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 7bff634fb2d..e7dfc4b8c41 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -214,15 +214,6 @@ pub struct Session { /// drown everything else in noise. miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>, - /// Base directory containing the `src/` for the Rust standard library, and - /// potentially `rustc` as well, if we can can find it. Right now it's always - /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component). - /// - /// This directory is what the virtual `/rustc/$hash` is translated back to, - /// if Rust was built with path remapping to `/rustc/$hash` enabled - /// (the `rust.remap-debuginfo` option in `config.toml`). - pub real_rust_source_base_dir: Option<PathBuf>, - /// Architecture to use for interpreting asm!. pub asm_arch: Option<InlineAsmArch>, @@ -1390,26 +1381,6 @@ pub fn build_session( _ => CtfeBacktrace::Disabled, }); - // Try to find a directory containing the Rust `src`, for more details see - // the doc comment on the `real_rust_source_base_dir` field. - let real_rust_source_base_dir = { - // This is the location used by the `rust-src` `rustup` component. - let mut candidate = sysroot.join("lib/rustlib/src/rust"); - if let Ok(metadata) = candidate.symlink_metadata() { - // Replace the symlink rustbuild creates, with its destination. - // We could try to use `fs::canonicalize` instead, but that might - // produce unnecessarily verbose path. - if metadata.file_type().is_symlink() { - if let Ok(symlink_dest) = std::fs::read_link(&candidate) { - candidate = symlink_dest; - } - } - } - - // Only use this directory if it has a file we can expect to always find. - if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None } - }; - let asm_arch = if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None }; @@ -1453,7 +1424,6 @@ pub fn build_session( system_library_path: OneThread::new(RefCell::new(Default::default())), ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), - real_rust_source_base_dir, asm_arch, target_features: FxHashSet::default(), known_attrs: Lock::new(MarkedAttrs::new()), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4be187c5208..b2dac10c83f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -634,6 +634,7 @@ symbols! { impl_macros, impl_trait_in_bindings, import_shadowing, + imported_main, in_band_lifetimes, include, include_bytes, @@ -781,6 +782,7 @@ symbols! { no, no_builtins, no_core, + no_coverage, no_crate_inject, no_debug, no_default_passes, @@ -852,8 +854,7 @@ symbols! { partial_ord, passes, pat, - pat2015, - pat2021, + pat_param, path, pattern_parentheses, phantom_data, diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index e7c9edea765..f180eea01a3 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -85,8 +85,6 @@ def_regs! { x15: reg = ["x15", "w15"], x16: reg = ["x16", "w16"], x17: reg = ["x17", "w17"], - x18: reg = ["x18", "w18"], - x19: reg = ["x19", "w19"], x20: reg = ["x20", "w20"], x21: reg = ["x21", "w21"], x22: reg = ["x22", "w22"], @@ -96,7 +94,7 @@ def_regs! { x26: reg = ["x26", "w26"], x27: reg = ["x27", "w27"], x28: reg = ["x28", "w28"], - x30: reg = ["x30", "w30", "lr"], + x30: reg = ["x30", "w30", "lr", "wlr"], v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"], v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"], v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"], @@ -129,7 +127,11 @@ def_regs! { v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"], v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"], v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"], - #error = ["x29", "fp"] => + #error = ["x18", "w18"] => + "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm", + #error = ["x19", "w19"] => + "x19 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["x29", "w29", "fp", "wfp"] => "the frame pointer cannot be used as an operand for inline asm", #error = ["sp", "wsp"] => "the stack pointer cannot be used as an operand for inline asm", diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index a7a708fe7de..4c323fc35d6 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -98,7 +98,6 @@ def_regs! { r5: reg, reg_thumb = ["r5", "v2"], r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7, r8: reg = ["r8", "v5"], - r9: reg = ["r9", "v6", "rfp"], r10: reg = ["r10", "sl"], r11: reg = ["r11", "fp"] % frame_pointer_r11, r12: reg = ["r12", "ip"], @@ -185,6 +184,8 @@ def_regs! { q15: qreg = ["q15"], #error = ["r6", "v3"] => "r6 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["r9", "v6", "rfp"] => + "r9 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r13", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r15", "pc"] => diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs index d41941d0b4c..74afddb69dc 100644 --- a/compiler/rustc_target/src/asm/hexagon.rs +++ b/compiler/rustc_target/src/asm/hexagon.rs @@ -60,7 +60,6 @@ def_regs! { r16: reg = ["r16"], r17: reg = ["r17"], r18: reg = ["r18"], - r19: reg = ["r19"], r20: reg = ["r20"], r21: reg = ["r21"], r22: reg = ["r22"], @@ -70,6 +69,8 @@ def_regs! { r26: reg = ["r26"], r27: reg = ["r27"], r28: reg = ["r28"], + #error = ["r19"] => + "r19 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r29", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r30", "fr"] => diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 185d6ac8246..e276a9175f9 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -66,7 +66,6 @@ def_regs! { x5: reg = ["x5", "t0"], x6: reg = ["x6", "t1"], x7: reg = ["x7", "t2"], - x9: reg = ["x9", "s1"], x10: reg = ["x10", "a0"], x11: reg = ["x11", "a1"], x12: reg = ["x12", "a2"], @@ -121,6 +120,8 @@ def_regs! { f29: freg = ["f29", "ft9"], f30: freg = ["f30", "ft10"], f31: freg = ["f31", "ft11"], + #error = ["x9", "s1"] => + "s1 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["x8", "s0", "fp"] => "the frame pointer cannot be used as an operand for inline asm", #error = ["x2", "sp"] => diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 90660dad4c2..48f83ca7cd4 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -152,13 +152,41 @@ fn high_byte( } } +fn rbx_reserved( + arch: InlineAsmArch, + _has_feature: impl FnMut(&str) -> bool, + _target: &Target, +) -> Result<(), &'static str> { + match arch { + InlineAsmArch::X86 => Ok(()), + InlineAsmArch::X86_64 => { + Err("rbx is used internally by LLVM and cannot be used as an operand for inline asm") + } + _ => unreachable!(), + } +} + +fn esi_reserved( + arch: InlineAsmArch, + _has_feature: impl FnMut(&str) -> bool, + _target: &Target, +) -> Result<(), &'static str> { + match arch { + InlineAsmArch::X86 => { + Err("esi is used internally by LLVM and cannot be used as an operand for inline asm") + } + InlineAsmArch::X86_64 => Ok(()), + _ => unreachable!(), + } +} + def_regs! { X86 X86InlineAsmReg X86InlineAsmRegClass { ax: reg, reg_abcd = ["ax", "eax", "rax"], - bx: reg, reg_abcd = ["bx", "ebx", "rbx"], + bx: reg, reg_abcd = ["bx", "ebx", "rbx"] % rbx_reserved, cx: reg, reg_abcd = ["cx", "ecx", "rcx"], dx: reg, reg_abcd = ["dx", "edx", "rdx"], - si: reg = ["si", "esi", "rsi"], + si: reg = ["si", "esi", "rsi"] % esi_reserved, di: reg = ["di", "edi", "rdi"], r8: reg = ["r8", "r8w", "r8d"] % x86_64_only, r9: reg = ["r9", "r9w", "r9d"] % x86_64_only, diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs index cfaf020175b..f5d7be4537b 100644 --- a/compiler/rustc_target/src/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -12,7 +12,8 @@ pub fn target() -> Target { arch: "x86".to_string(), options: TargetOptions { max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + stack_probes: StackProbeType::Call, ..base }, } diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 2d3310c7582..06d71db4af2 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.eliminate_frame_pointer = false; // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs index 18cd8847abd..19d7b3c95cf 100644 --- a/compiler/rustc_target/src/spec/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/i686_linux_android.rs @@ -11,7 +11,8 @@ pub fn target() -> Target { // http://developer.android.com/ndk/guides/abis.html#x86 base.cpu = "pentiumpro".to_string(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-linux-android".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index a26cabdc90a..d8e37e72371 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -7,7 +7,8 @@ pub fn target() -> Target { let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); pre_link_args.push("-m32".to_string()); pre_link_args.push("-Wl,-znotext".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-freebsd".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index 5fba4e3f14a..e4c01db5439 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-haiku".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index 633e8da0ccb..165505ee731 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-linux-gnu".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index 8bcd261e4df..228976779f0 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index e020264ad7a..989e3fb1adf 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-netbsdelf".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index 86448cb9115..7ff79961375 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-openbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index e596eca86b0..c7963dbde77 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "i686-unknown-linux-gnu".to_string(), diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index d17d729c289..64f47b4aa9b 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -5,7 +5,8 @@ pub fn opts() -> TargetOptions { env: "gnu".to_string(), disable_redzone: true, panic_strategy: PanicStrategy::Abort, - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + stack_probes: StackProbeType::Call, eliminate_frame_pointer: false, linker_is_gnu: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index c82359223da..dc7597fe7b2 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -10,7 +10,8 @@ pub fn target() -> Target { vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()], ); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; // Clang automatically chooses a more specific target based on diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs index 6feeeac451b..adb87718589 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -11,7 +11,8 @@ pub fn target() -> Target { arch: "x86_64".to_string(), options: TargetOptions { max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + stack_probes: StackProbeType::Call, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index a6e066213e7..c228e42ef30 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -11,7 +11,8 @@ pub fn target() -> Target { arch: "x86_64".to_string(), options: TargetOptions { max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + stack_probes: StackProbeType::Call, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index f8c47168da8..e3a5de4cbd1 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -10,7 +10,8 @@ pub fn target() -> Target { arch: "x86_64".to_string(), options: TargetOptions { max_atomic_width: Some(64), - stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }, + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + stack_probes: StackProbeType::Call, ..base }, } diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs index 99acc7c207b..aa65ebe1f9d 100644 --- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -4,7 +4,8 @@ pub fn target() -> Target { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 0945a9f5c59..9065283b731 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -7,7 +7,8 @@ pub fn target() -> Target { base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-linux-android".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs index 75eece74ff9..b78e43d4fe9 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.vendor = "pc".to_string(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-pc-solaris".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 63e524fa8a9..2fa53470f74 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -6,7 +6,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.vendor = "sun".to_string(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-pc-solaris".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 295f9c837c3..d69830f0a3f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index ca3556fc48e..b5fc15f5e04 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 963d4fdb12f..fcd96ddd61b 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; // This option is required to build executables on Haiku x86_64 base.position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index 31164f8408d..1ef24b6eb36 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.features = "+rdrnd,+rdseed".to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-hermit".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 9569e98ed59..085079e06e5 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 5f87534fe95..7b77ad668cd 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.has_elf_tls = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index 1e2e5766a31..5ad243aa407 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 54e7ceee82e..0269c7afe55 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-netbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs index a357def190b..28d9801b78c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs @@ -7,7 +7,8 @@ pub fn target() -> Target { base.features = "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .to_string(); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-none-elf".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 530e63966aa..4eb3f34a036 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-openbsd".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index 934f8de8ecc..b8269ecae20 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; Target { llvm_target: "x86_64-unknown-redox".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index f9fa9d93843..f9f775084fb 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -5,7 +5,8 @@ pub fn target() -> Target { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); - base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; base.disable_redzone = true; Target { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index ac5ec24eeee..d5e1bd3f9ea 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -132,6 +132,14 @@ fn object_safety_violations_for_trait( .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), ); + violations.extend( + tcx.associated_items(trait_def_id) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .filter(|item| !tcx.generics_of(item.def_id).params.is_empty()) + .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)), + ); + debug!( "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, violations diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 31685a012ca..e338a21b603 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -462,12 +462,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { if !tcx.generics_of(assoc_type).params.is_empty() { - // FIXME(generic_associated_types) generate placeholders to - // extend the trait substs. - tcx.sess.span_fatal( + tcx.sess.delay_span_bug( obligation.cause.span, - "generic associated types in trait objects are not supported yet", + "GATs in trait object shouldn't have been considered", ); + return Err(SelectionError::Unimplemented); } // This maybe belongs in wf, but that can't (doesn't) handle // higher-ranked things. diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 38e5ce6fd83..144c7281b67 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_middle::hir::map as hir_map; @@ -400,10 +399,6 @@ fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol { tcx.crate_name } -fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - tcx.index_hir(crate_num).crate_hash -} - fn instance_def_size_estimate<'tcx>( tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>, @@ -551,7 +546,6 @@ pub fn provide(providers: &mut ty::query::Providers) { trait_of_item, crate_disambiguator, original_crate_name, - crate_hash, instance_def_size_estimate, issue33140_self_ty, impl_defaultness, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index a3804e468da..077375c7c3b 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -278,9 +278,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // another. This is an error. However, if we already know that // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. - if arg_count.correct.is_ok() - && arg_count.explicit_late_bound == ExplicitLateBound::No - { + if arg_count.correct.is_ok() { // We're going to iterate over the parameters to sort them out, and // show that order to the user as a possible order for the parameters let mut param_types_present = defs @@ -462,7 +460,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if silent { - return false; + return true; } if provided > expected_max { diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 72c633dcb20..92d7ea26003 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -6,7 +6,7 @@ use super::*; use rustc_attr as attr; use rustc_errors::{Applicability, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{def::Res, ItemKind, Node, PathSegment}; @@ -16,15 +16,14 @@ 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, ToPredicate, Ty, TyCtxt}; -use rustc_session::config::EntryFnType; +use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt}; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCauseCode}; use rustc_ty_utils::representability::{self, Representability}; use std::iter; @@ -326,29 +325,6 @@ pub(super) fn check_fn<'a, 'tcx>( } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); - // Check that the main return type implements the termination trait. - if let Some(term_id) = tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { - let main_id = hir.local_def_id_to_hir_id(def_id); - if main_id == fn_id { - let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); - let trait_ref = ty::TraitRef::new(term_id, substs); - let return_ty_span = decl.output.span(); - let cause = traits::ObligationCause::new( - return_ty_span, - fn_id, - ObligationCauseCode::MainFunctionType, - ); - - inherited.register_predicate(traits::Obligation::new( - cause, - param_env, - trait_ref.without_const().to_predicate(tcx), - )); - } - } - } - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index a50f8e1c655..1959fe75e8e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1282,6 +1282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut infer_args_for_err = FxHashSet::default(); + let mut explicit_late_bound = ExplicitLateBound::No; for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = tcx.generics_of(def_id); @@ -1290,17 +1291,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - if let GenericArgCountResult { - correct: Err(GenericArgCountMismatch { reported: Some(_), .. }), - .. - } = <dyn AstConv<'_>>::check_generic_arg_count_for_call( + let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call( tcx, span, def_id, &generics, seg, IsMethodCall::No, - ) { + ); + + if let ExplicitLateBound::Yes = arg_count.explicit_late_bound { + explicit_late_bound = ExplicitLateBound::Yes; + } + + if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } @@ -1357,7 +1361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = tcx.type_of(def_id); let arg_count = GenericArgCountResult { - explicit_late_bound: ExplicitLateBound::No, + explicit_late_bound, correct: if infer_args_for_err.is_empty() { Ok(()) } else { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb4257e0534..cb7589318d2 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -116,7 +116,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::WithConstness; use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; use rustc_session::config; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 26871d6f028..d25dd9a6e83 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -315,17 +315,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ), ) } else { - tcx.sess - .struct_span_err( - hir_ty.span, - &format!( - "{} is forbidden as the type of a const generic parameter", - unsupported_type - ), - ) - .note("the only supported types are integers, `bool` and `char`") - .help("more complex types are supported with `#![feature(const_generics)]`") - .emit() + let mut err = tcx.sess.struct_span_err( + hir_ty.span, + &format!( + "{} is forbidden as the type of a const generic parameter", + unsupported_type + ), + ); + err.note("the only supported types are integers, `bool` and `char`"); + if tcx.sess.is_nightly_build() { + err.help( + "more complex types are supported with `#![feature(const_generics)]`", + ); + } + err.emit() } }; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 46ee8245432..190c9d35934 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2661,6 +2661,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; + let mut no_coverage_feature_enabled = false; + let mut no_coverage_attr = None; for attr in attrs.iter() { if tcx.sess.check_name(attr, sym::cold) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; @@ -2724,6 +2726,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; } else if tcx.sess.check_name(attr, sym::no_mangle) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + } else if attr.has_name(sym::feature) { + if let Some(list) = attr.meta_item_list() { + if list.iter().any(|nested_meta_item| nested_meta_item.has_name(sym::no_coverage)) { + tcx.sess.mark_attr_used(attr); + no_coverage_feature_enabled = true; + } + } + } else if tcx.sess.check_name(attr, sym::no_coverage) { + no_coverage_attr = Some(attr); } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if tcx.sess.check_name(attr, sym::used) { @@ -2934,6 +2945,23 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } + if let Some(no_coverage_attr) = no_coverage_attr { + if tcx.sess.features_untracked().no_coverage || no_coverage_feature_enabled { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE + } else { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::no_coverage, + no_coverage_attr.span, + "the `#[no_coverage]` attribute is an experimental feature", + ); + if tcx.sess.parse_sess.unstable_features.is_nightly_build() { + err.help("or, alternatively, add `#[feature(no_coverage)]` to the function"); + } + err.emit(); + } + } + codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if !attr.has_name(sym::inline) { return ia; diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 532ee00daf8..f1749412794 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -763,7 +763,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { PlaceBase::Local(*var_hir_id) }; let place_with_id = PlaceWithHirId::new( - capture_info.path_expr_id.unwrap_or(closure_expr.hir_id), + capture_info.path_expr_id.unwrap_or( + capture_info.capture_kind_expr_id.unwrap_or(closure_expr.hir_id), + ), place.base_ty, place_base, place.projections.clone(), diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 190744fe6f1..4e07e52347a 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -97,8 +97,8 @@ mod variance; use rustc_errors::{struct_span_err, ErrorReported}; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; -use rustc_hir::Node; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::middle; @@ -110,7 +110,7 @@ use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ - ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, }; use std::iter; @@ -164,106 +164,203 @@ fn require_same_types<'tcx>( }) } -fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { - let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id); +fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { + let main_fnsig = tcx.fn_sig(main_def_id); let main_span = tcx.def_span(main_def_id); - let main_t = tcx.type_of(main_def_id); - match main_t.kind() { - ty::FnDef(..) => { - if let Some(Node::Item(it)) = tcx.hir().find(main_id) { - if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { - let mut error = false; - if !generics.params.is_empty() { - let msg = "`main` function is not allowed to have generic \ - parameters" - .to_owned(); - let label = "`main` cannot have generic parameters".to_string(); - struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg) - .span_label(generics.span, label) - .emit(); - error = true; - } - if let Some(sp) = generics.where_clause.span() { - struct_span_err!( - tcx.sess, - sp, - E0646, - "`main` function is not allowed to have a `where` clause" - ) - .span_label(sp, "`main` cannot have a `where` clause") - .emit(); - error = true; - } - if let hir::IsAsync::Async = sig.header.asyncness { - let span = tcx.sess.source_map().guess_head_span(it.span); - struct_span_err!( - tcx.sess, - span, - E0752, - "`main` function is not allowed to be `async`" - ) - .span_label(span, "`main` function is not allowed to be `async`") - .emit(); - error = true; - } - let attrs = tcx.hir().attrs(main_id); - for attr in attrs { - if tcx.sess.check_name(attr, sym::track_caller) { - tcx.sess - .struct_span_err( - attr.span, - "`main` function is not allowed to be `#[track_caller]`", - ) - .span_label( - main_span, - "`main` function is not allowed to be `#[track_caller]`", - ) - .emit(); - error = true; - } - } + fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId { + if let Some(local_def_id) = def_id.as_local() { + let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_type = tcx.type_of(local_def_id); + if !matches!(hir_type.kind(), ty::FnDef(..)) { + span_bug!(sp, "main has a non-function type: found `{}`", hir_type); + } + hir_id + } else { + CRATE_HIR_ID + } + } - if error { - return; - } - } + fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { + let generics_param_span = + if !generics.params.is_empty() { Some(generics.span) } else { None }; + generics_param_span + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); } + } + } - let actual = tcx.fn_sig(main_def_id); - let expected_return_type = if tcx.lang_items().termination().is_some() { - // we take the return type of the given main function, the real check is done - // in `check_fn` - actual.output() - } else { - // standard () main return type - ty::Binder::dummy(tcx.mk_unit()) - }; - - let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { - tcx.mk_fn_sig( - iter::empty(), - expected_return_type, - false, - hir::Unsafety::Normal, - Abi::Rust, - ) - })); + fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { + generics.where_clause.span() + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } + } + } - require_same_types( - tcx, - &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType), - se_ty, - tcx.mk_fn_ptr(actual), - ); + fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { + if !def_id.is_local() { + return None; } - _ => { - span_bug!(main_span, "main has a non-function type: found `{}`", main_t); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { span: item_span, .. })) => { + Some(tcx.sess.source_map().guess_head_span(*item_span)) + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } } } -} -fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { + fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { + if !def_id.is_local() { + return None; + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + match tcx.hir().find(hir_id) { + Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => { + Some(fn_sig.decl.output.span()) + } + _ => { + span_bug!(tcx.def_span(def_id), "main has a non-function type"); + } + } + } + + let mut error = false; + let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span); + let main_fn_generics = tcx.generics_of(main_def_id); + let main_fn_predicates = tcx.predicates_of(main_def_id); + if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() { + let generics_param_span = main_fn_generics_params_span(tcx, main_def_id); + let msg = "`main` function is not allowed to have generic \ + parameters"; + let mut diag = + struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg); + if let Some(generics_param_span) = generics_param_span { + let label = "`main` cannot have generic parameters".to_string(); + diag.span_label(generics_param_span, label); + } + diag.emit(); + error = true; + } else if !main_fn_predicates.predicates.is_empty() { + // generics may bring in implicit predicates, so we skip this check if generics is present. + let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id); + let mut diag = struct_span_err!( + tcx.sess, + generics_where_clauses_span.unwrap_or(main_span), + E0646, + "`main` function is not allowed to have a `where` clause" + ); + if let Some(generics_where_clauses_span) = generics_where_clauses_span { + diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause"); + } + diag.emit(); + error = true; + } + + let main_asyncness = tcx.asyncness(main_def_id); + if let hir::IsAsync::Async = main_asyncness { + let mut diag = struct_span_err!( + tcx.sess, + main_span, + E0752, + "`main` function is not allowed to be `async`" + ); + let asyncness_span = main_fn_asyncness_span(tcx, main_def_id); + if let Some(asyncness_span) = asyncness_span { + diag.span_label(asyncness_span, "`main` function is not allowed to be `async`"); + } + diag.emit(); + error = true; + } + + for attr in tcx.get_attrs(main_def_id) { + if tcx.sess.check_name(attr, sym::track_caller) { + tcx.sess + .struct_span_err( + attr.span, + "`main` function is not allowed to be `#[track_caller]`", + ) + .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`") + .emit(); + error = true; + } + } + + if error { + return; + } + + let expected_return_type; + if let Some(term_id) = tcx.lang_items().termination() { + let return_ty = main_fnsig.output(); + let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span); + if !return_ty.bound_vars().is_empty() { + let msg = "`main` function return type is not allowed to have generic \ + parameters" + .to_owned(); + struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit(); + error = true; + } + let return_ty = return_ty.skip_binder(); + tcx.infer_ctxt().enter(|infcx| { + let cause = traits::ObligationCause::new( + return_ty_span, + main_diagnostics_hir_id, + ObligationCauseCode::MainFunctionType, + ); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause); + if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&err, None, false); + error = true; + } + }); + // now we can take the return type of the given main function + expected_return_type = main_fnsig.output(); + } else { + // standard () main return type + expected_return_type = ty::Binder::dummy(tcx.mk_unit()); + } + + if error { + return; + } + + let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| { + tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust) + })); + + require_same_types( + tcx, + &ObligationCause::new( + main_span, + main_diagnostics_hir_id, + ObligationCauseCode::MainFunctionType, + ), + se_ty, + tcx.mk_fn_ptr(main_fnsig), + ); +} +fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { + let start_def_id = start_def_id.expect_local(); let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index f330a1bb3dc..af403496e38 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -89,7 +89,7 @@ impl<K, V> LeafNode<K, V> { /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an -/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the +/// `InternalNode` can be directly cast to a pointer to the underlying `LeafNode` portion of the /// node, allowing code to act on leaf and internal nodes generically without having to even check /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. #[repr(C)] @@ -408,7 +408,7 @@ impl<K, V> NodeRef<marker::Dying, K, V, marker::LeafOrInternal> { } impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { - /// Temporarily takes out another, mutable reference to the same node. Beware, as + /// Temporarily takes out another mutable reference to the same node. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// @@ -759,7 +759,7 @@ impl<BorrowType, K, V, NodeType, HandleType> PartialEq impl<BorrowType, K, V, NodeType, HandleType> Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> { - /// Temporarily takes out another, immutable handle on the same location. + /// Temporarily takes out another immutable handle on the same location. pub fn reborrow(&self) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData } @@ -767,7 +767,7 @@ impl<BorrowType, K, V, NodeType, HandleType> } impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> { - /// Temporarily takes out another, mutable handle on the same location. Beware, as + /// Temporarily takes out another mutable handle on the same location. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3a5dcec668f..15308a4469b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -76,7 +76,6 @@ #![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(new_uninit))] #![feature(allocator_api)] -#![feature(vec_extend_from_within)] #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e459442dfcf..85c9446689e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2124,8 +2124,6 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// ## Examples /// /// ``` - /// #![feature(vec_extend_from_within)] - /// /// let mut vec = vec![0, 1, 2, 3, 4]; /// /// vec.extend_from_within(2..); @@ -2137,7 +2135,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// vec.extend_from_within(4..8); /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); /// ``` - #[unstable(feature = "vec_extend_from_within", issue = "81656")] + #[stable(feature = "vec_extend_from_within", since = "1.53.0")] pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>, diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 7e1194cc4aa..25a83a0b014 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -20,7 +20,6 @@ #![feature(vecdeque_binary_search)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] -#![feature(vec_extend_from_within)] #![feature(vec_spare_capacity)] #![feature(string_remove_matches)] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index cdb6006b1b3..0a3e5789e8b 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -274,6 +274,8 @@ pub trait Eq: PartialEq<Self> { // // This should never be implemented by hand. #[doc(hidden)] + #[cfg_attr(not(bootstrap), feature(no_coverage))] + #[cfg_attr(not(bootstrap), no_coverage)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index f7aec736449..a0b65399da2 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -128,7 +128,7 @@ pub fn spin_loop() { #[cfg(target_arch = "aarch64")] { // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. - unsafe { crate::arch::aarch64::__yield() }; + unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; } #[cfg(target_arch = "arm")] { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 7977d599ae7..da9e5fde7cc 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2133,7 +2133,6 @@ pub trait Iterator { /// ``` /// /// [`reduce()`]: Iterator::reduce - #[doc(alias = "reduce")] #[doc(alias = "inject")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5f1f7d8cac4..c7f58f36154 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -21,7 +21,8 @@ #![feature(rustc_allow_const_fn_unstable)] #![feature(nll)] #![feature(staged_api)] -#![feature(const_fn)] +#![cfg_attr(bootstrap, feature(const_fn))] +#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))] #![feature(const_fn_fn_ptr_basics)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 116a37249e3..821e7d4cfe7 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -124,6 +124,10 @@ pub fn vars() -> Vars { /// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// +/// Note that the returned iterator will not check if the environment variables +/// are valid Unicode. If you want to panic on invalid UTF-8, +/// use the [`vars`] function instead. +/// /// # Examples /// /// ``` @@ -180,8 +184,9 @@ impl fmt::Debug for VarsOs { /// /// # Errors /// -/// * Environment variable is not present -/// * Environment variable is not valid unicode +/// Errors if the environment variable is not present. +/// Errors if the environment variable is not valid Unicode. If this is not desired, consider using +/// [`var_os`]. /// /// # Panics /// @@ -221,6 +226,10 @@ fn _var(key: &OsStr) -> Result<String, VarError> { /// `'='` or the NUL character `'\0'`, or when the value contains the NUL /// character. /// +/// Note that the method will not check if the environment variable +/// is valid Unicode. If you want to have an error on invalid UTF-8, +/// use the [`var`] function instead. +/// /// # Examples /// /// ``` @@ -752,7 +761,7 @@ pub fn args() -> Args { /// does on macOS and Windows. /// /// Note that the returned iterator will not check if the arguments to the -/// process are valid Unicode. To ensure UTF-8 validity, +/// process are valid Unicode. If you want to panic on invalid UTF-8, /// use the [`args`] function instead. /// /// # Examples diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ecaab670349..ea4b2866017 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,7 +71,6 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`&str`]: str /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions -#[derive(Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -421,6 +420,19 @@ impl Default for OsString { } #[stable(feature = "rust1", since = "1.0.0")] +impl Clone for OsString { + #[inline] + fn clone(&self) -> Self { + OsString { inner: self.inner.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for OsString { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index f4020a42879..ed0987064e8 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1065,7 +1065,6 @@ impl FusedIterator for Ancestors<'_> {} /// ``` /// /// Which method works best depends on what kind of situation you're in. -#[derive(Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: @@ -1406,6 +1405,19 @@ impl PathBuf { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for PathBuf { + #[inline] + fn clone(&self) -> Self { + PathBuf { inner: self.inner.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) + } +} + #[stable(feature = "box_from_path", since = "1.17.0")] impl From<&Path> for Box<Path> { fn from(path: &Path) -> Box<Path> { diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index c37111f665c..cd6b0b2d7ee 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -553,8 +553,10 @@ mod prim_pointer {} /// # Editions /// /// Prior to Rust 1.53, arrays did not implement `IntoIterator` by value, so the method call -/// `array.into_iter()` auto-referenced into a slice iterator. That behavior is preserved in the -/// 2015 and 2018 editions of Rust for compatability, ignoring `IntoIterator` by value. +/// `array.into_iter()` auto-referenced into a slice iterator. Right now, the old behavior +/// is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring +/// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition +/// might be made consistent to the behavior of later editions. /// #[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")] #[cfg_attr(not(bootstrap), doc = "```rust,edition2018")] @@ -601,6 +603,49 @@ mod prim_pointer {} /// } /// ``` /// +/// Future language versions might start treating the `array.into_iter()` +/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using +/// those older editions should still be written with this change in mind, to +/// prevent breakage in the future. The safest way to accomplish this is to +/// avoid the `into_iter` syntax on those editions. If an edition update is not +/// viable/desired, there are multiple alternatives: +/// * use `iter`, equivalent to the old behavior, creating references +/// * use [`array::IntoIter`], equivalent to the post-2021 behavior (Rust 1.51+) +/// * replace `for ... in array.into_iter() {` with `for ... in array {`, +/// equivalent to the post-2021 behavior (Rust 1.53+) +/// +#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")] +#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")] +/// use std::array::IntoIter; +/// +/// let array: [i32; 3] = [0; 3]; +/// +/// // This iterates by reference: +/// for item in array.iter() { +/// let x: &i32 = item; +/// println!("{}", x); +/// } +/// +/// // This iterates by value: +/// for item in IntoIter::new(array) { +/// let x: i32 = item; +/// println!("{}", x); +/// } +/// +/// // This iterates by value: +/// for item in array { +/// let x: i32 = item; +/// println!("{}", x); +/// } +/// +/// // IntoIter can also start a chain. +/// // This iterates by value: +/// for item in IntoIter::new(array).enumerate() { +/// let (i, x): (usize, i32) = item; +/// println!("array[{}] = {}", i, x); +/// } +/// ``` +/// /// [slice]: prim@slice /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 2615bea6592..773ab18b2ce 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.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::mutex as sys; @@ -376,23 +374,8 @@ impl<T: ?Sized> Mutex<T> { where T: Sized, { - // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner mutex. - // - // To get the inner value, we'd like to call `data.into_inner()`, - // but because `Mutex` impl-s `Drop`, we can't move out of it, so - // we'll have to destructure it manually instead. - unsafe { - // Like `let Mutex { inner, poison, data } = self`. - let (inner, poison, data) = { - let Mutex { ref inner, ref poison, ref data } = self; - (ptr::read(inner), ptr::read(poison), ptr::read(data)) - }; - mem::forget(self); - 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. diff --git a/library/std/src/sys/hermit/cmath.rs b/library/std/src/sys/hermit/cmath.rs deleted file mode 100644 index 304cf906b2a..00000000000 --- a/library/std/src/sys/hermit/cmath.rs +++ /dev/null @@ -1,29 +0,0 @@ -// These symbols are all defined in `compiler-builtins` -extern "C" { - pub fn acos(n: f64) -> f64; - pub fn acosf(n: f32) -> f32; - pub fn asin(n: f64) -> f64; - pub fn asinf(n: f32) -> f32; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn coshf(n: f32) -> f32; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; - pub fn hypot(x: f64, y: f64) -> f64; - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn sinhf(n: f32) -> f32; - pub fn tan(n: f64) -> f64; - pub fn tanf(n: f32) -> f32; - pub fn tanh(n: f64) -> f64; - pub fn tanhf(n: f32) -> f32; -} diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 3364d215776..0c49a6fb6de 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -20,6 +20,7 @@ use crate::os::raw::c_char; pub mod alloc; pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; pub mod env; diff --git a/library/std/src/sys/sgx/cmath.rs b/library/std/src/sys/sgx/cmath.rs deleted file mode 100644 index b89238f1da8..00000000000 --- a/library/std/src/sys/sgx/cmath.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![cfg(not(test))] - -// These symbols are all defined in `compiler-builtins` -extern "C" { - pub fn acos(n: f64) -> f64; - pub fn acosf(n: f32) -> f32; - pub fn asin(n: f64) -> f64; - pub fn asinf(n: f32) -> f32; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn coshf(n: f32) -> f32; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; - pub fn hypot(x: f64, y: f64) -> f64; - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn sinhf(n: f32) -> f32; - pub fn tan(n: f64) -> f64; - pub fn tanf(n: f32) -> f32; - pub fn tanh(n: f64) -> f64; - pub fn tanhf(n: f32) -> f32; -} diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs index 730db34e733..b0170e67446 100644 --- a/library/std/src/sys/sgx/ext/arch.rs +++ b/library/std/src/sys/sgx/ext/arch.rs @@ -32,9 +32,12 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> let error; asm!( + // rbx is reserved by LLVM + "xchg {0}, rbx", "enclu", + "mov rbx, {0}", + inout(reg) request => _, inlateout("eax") ENCLU_EGETKEY => error, - in("rbx") request, in("rcx") out.as_mut_ptr(), options(nostack), ); @@ -60,9 +63,12 @@ pub fn ereport( let mut report = MaybeUninit::uninit(); asm!( + // rbx is reserved by LLVM + "xchg {0}, rbx", "enclu", + "mov rbx, {0}", + inout(reg) targetinfo => _, in("eax") ENCLU_EREPORT, - in("rbx") targetinfo, in("rcx") reportdata, in("rdx") report.as_mut_ptr(), options(preserves_flags, nostack), diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 059d6cb5ba1..bf3bd57e982 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -13,6 +13,7 @@ mod waitqueue; pub mod alloc; pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; pub mod env; diff --git a/library/std/src/sys/unix/cmath.rs b/library/std/src/sys/unix/cmath.rs index f327b69fc75..2bf80d7a4cb 100644 --- a/library/std/src/sys/unix/cmath.rs +++ b/library/std/src/sys/unix/cmath.rs @@ -1,32 +1,33 @@ #![cfg(not(test))] -use libc::{c_double, c_float}; +// These symbols are all defined by `libm`, +// or by `compiler-builtins` on unsupported platforms. extern "C" { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; + pub fn acos(n: f64) -> f64; + pub fn acosf(n: f32) -> f32; + pub fn asin(n: f64) -> f64; + pub fn asinf(n: f32) -> f32; + pub fn atan(n: f64) -> f64; + pub fn atan2(a: f64, b: f64) -> f64; + pub fn atan2f(a: f32, b: f32) -> f32; + pub fn atanf(n: f32) -> f32; + pub fn cbrt(n: f64) -> f64; + pub fn cbrtf(n: f32) -> f32; + pub fn cosh(n: f64) -> f64; + pub fn coshf(n: f32) -> f32; + pub fn expm1(n: f64) -> f64; + pub fn expm1f(n: f32) -> f32; + pub fn fdim(a: f64, b: f64) -> f64; + pub fn fdimf(a: f32, b: f32) -> f32; + pub fn hypot(x: f64, y: f64) -> f64; + pub fn hypotf(x: f32, y: f32) -> f32; + pub fn log1p(n: f64) -> f64; + pub fn log1pf(n: f32) -> f32; + pub fn sinh(n: f64) -> f64; + pub fn sinhf(n: f32) -> f32; + pub fn tan(n: f64) -> f64; + pub fn tanf(n: f32) -> f32; + pub fn tanh(n: f64) -> f64; + pub fn tanhf(n: f32) -> f32; } diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 9a982a4acd9..9cf51be2836 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -884,3 +884,29 @@ impl DirBuilderExt for fs::DirBuilder { self } } + +/// Change the root directory of the current process to the specified path. +/// +/// This typically requires privileges, such as root or a specific capability. +/// +/// This does not change the current working directory; you should call +/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chroot)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::chroot("/sandbox")?; +/// std::env::set_current_dir("/")?; +/// // continue working in sandbox +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chroot", issue = "84715")] +#[cfg(not(target_os = "fuchsia"))] +pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { + sys::fs::chroot(dir.as_ref()) +} diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 16a7f727696..45bae25a0c3 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1328,3 +1328,10 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { })?; Ok(bytes_copied as u64) } + +#[cfg(not(target_os = "fuchsia"))] +pub fn chroot(dir: &Path) -> io::Result<()> { + let dir = cstr(dir)?; + cvt(unsafe { libc::chroot(dir.as_ptr()) })?; + Ok(()) +} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index a0ee69c2f72..6c4fbaf2734 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -11,6 +11,7 @@ pub mod weak; pub mod alloc; pub mod android; pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; pub mod env; diff --git a/library/std/src/sys/unsupported/cmath.rs b/library/std/src/sys/unsupported/cmath.rs deleted file mode 100644 index 304cf906b2a..00000000000 --- a/library/std/src/sys/unsupported/cmath.rs +++ /dev/null @@ -1,29 +0,0 @@ -// These symbols are all defined in `compiler-builtins` -extern "C" { - pub fn acos(n: f64) -> f64; - pub fn acosf(n: f32) -> f32; - pub fn asin(n: f64) -> f64; - pub fn asinf(n: f32) -> f32; - pub fn atan(n: f64) -> f64; - pub fn atan2(a: f64, b: f64) -> f64; - pub fn atan2f(a: f32, b: f32) -> f32; - pub fn atanf(n: f32) -> f32; - pub fn cbrt(n: f64) -> f64; - pub fn cbrtf(n: f32) -> f32; - pub fn cosh(n: f64) -> f64; - pub fn coshf(n: f32) -> f32; - pub fn expm1(n: f64) -> f64; - pub fn expm1f(n: f32) -> f32; - pub fn fdim(a: f64, b: f64) -> f64; - pub fn fdimf(a: f32, b: f32) -> f32; - pub fn hypot(x: f64, y: f64) -> f64; - pub fn hypotf(x: f32, y: f32) -> f32; - pub fn log1p(n: f64) -> f64; - pub fn log1pf(n: f32) -> f32; - pub fn sinh(n: f64) -> f64; - pub fn sinhf(n: f32) -> f32; - pub fn tan(n: f64) -> f64; - pub fn tanf(n: f32) -> f32; - pub fn tanh(n: f64) -> f64; - pub fn tanhf(n: f32) -> f32; -} diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 32ca68ef15b..3ef4c6b8a8f 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -2,6 +2,7 @@ pub mod alloc; pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; pub mod env; diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 2584d35b6ef..37f74fcc052 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -20,7 +20,7 @@ use crate::mem; #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[path = "../unsupported/cmath.rs"] +#[path = "../unix/cmath.rs"] pub mod cmath; #[path = "../unsupported/condvar.rs"] pub mod condvar; diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 8705910c73a..afcc5ca9286 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -18,7 +18,7 @@ pub mod alloc; pub mod args; -#[path = "../unsupported/cmath.rs"] +#[path = "../unix/cmath.rs"] pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 30bbfdd0dd1..a5799606142 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -19,9 +19,9 @@ use crate::sys::c; use crate::sys::cvt; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; -use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; +use crate::sys_common::mutex::StaticMutex; use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::AsInner; @@ -94,10 +94,6 @@ pub struct StdioPipes { pub stderr: Option<AnonPipe>, } -struct DropGuard<'a> { - lock: &'a Mutex, -} - impl Command { pub fn new(program: &OsStr) -> Command { Command { @@ -209,8 +205,9 @@ impl Command { // // For more information, msdn also has an article about this race: // http://support.microsoft.com/kb/315939 - static CREATE_PROCESS_LOCK: Mutex = Mutex::new(); - let _guard = DropGuard::new(&CREATE_PROCESS_LOCK); + static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new(); + + let _guard = unsafe { CREATE_PROCESS_LOCK.lock() }; let mut pipes = StdioPipes { stdin: None, stdout: None, stderr: None }; let null = Stdio::Null; @@ -259,23 +256,6 @@ impl fmt::Debug for Command { } } -impl<'a> DropGuard<'a> { - fn new(lock: &'a Mutex) -> DropGuard<'a> { - unsafe { - lock.lock(); - DropGuard { lock } - } - } -} - -impl<'a> Drop for DropGuard<'a> { - fn drop(&mut self) { - unsafe { - self.lock.unlock(); - } - } -} - impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> { match *self { diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs index 302c5197407..32705c432fa 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys_common/os_str_bytes.rs @@ -14,7 +14,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; use core::str::lossy::Utf8Lossy; -#[derive(Clone, Hash)] +#[derive(Hash)] pub(crate) struct Buf { pub inner: Vec<u8>, } @@ -53,6 +53,18 @@ impl fmt::Display for Buf { } } +impl Clone for Buf { + #[inline] + fn clone(&self) -> Self { + Buf { inner: self.inner.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) + } +} + impl IntoInner<Vec<u8>> for Buf { fn into_inner(self) -> Vec<u8> { self.inner diff --git a/rustfmt.toml b/rustfmt.toml index af807aa6f73..480b19a5e93 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -7,6 +7,8 @@ merge_derives = false # tidy only checks files which are not ignored, each entry follows gitignore style ignore = [ "/build/", + "/*-build/", + "/build-*/", "/vendor/", # tests for now are not formatted, as they are sometimes pretty-printing constrained diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 4111420e474..356d9f5d1ff 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -414,10 +414,13 @@ class RustBuild(object): filename = "rustc-{}-{}{}".format(rustc_channel, self.build, tarball_suffix) self._download_component_helper(filename, "rustc", tarball_suffix, stage0) - filename = "cargo-{}-{}{}".format(rustc_channel, self.build, - tarball_suffix) - self._download_component_helper(filename, "cargo", tarball_suffix) - if not stage0: + # download-rustc doesn't need its own cargo, it can just use beta's. + if stage0: + filename = "cargo-{}-{}{}".format(rustc_channel, self.build, + tarball_suffix) + self._download_component_helper(filename, "cargo", tarball_suffix) + self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root)) + else: filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix) self._download_component_helper( filename, "rustc-dev", tarball_suffix, stage0 @@ -425,7 +428,6 @@ class RustBuild(object): self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root)) self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root)) - self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root)) lib_dir = "{}/lib".format(bin_root) for lib in os.listdir(lib_dir): if lib.endswith(".so"): diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 38901a35296..62a3a87eeb8 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1627,6 +1627,11 @@ impl Cargo { pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { builder.add_rustc_lib_path(compiler, &mut self.command); } + + pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo { + self.command.current_dir(dir); + self + } } impl From<Cargo> for Command { diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 6626fead774..9b76c8b9a2d 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -280,7 +280,7 @@ impl Step for CodegenBackend { } macro_rules! tool_check_step { - ($name:ident, $path:expr, $source_type:expr) => { + ($name:ident, $path:literal, $($alias:literal, )* $source_type:path) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $name { pub target: TargetSelection, @@ -292,7 +292,7 @@ macro_rules! tool_check_step { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path($path) + run.paths(&[ $path, $($alias),* ]) } fn make_run(run: RunConfig<'_>) { @@ -321,11 +321,9 @@ macro_rules! tool_check_step { } // Enable internal lints for clippy and rustdoc - // NOTE: this intentionally doesn't enable lints for any other tools, - // see https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 - if $path == "src/tools/rustdoc" || $path == "src/tools/clippy" { - cargo.rustflag("-Zunstable-options"); - } + // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` + // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 + cargo.rustflag("-Zunstable-options"); builder.info(&format!( "Checking stage{} {} artifacts ({} -> {})", @@ -363,7 +361,7 @@ macro_rules! tool_check_step { }; } -tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree); +tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree); // Clippy is a hybrid. It is an external tool, but uses a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml index a9505922ca7..011ff6821b7 100644 --- a/src/bootstrap/defaults/config.codegen.toml +++ b/src/bootstrap/defaults/config.codegen.toml @@ -11,3 +11,5 @@ assertions = true debug-logging = true # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true +# Print backtrace on internal compiler errors during bootstrap +backtrace-on-ice = true diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index 883bfead64e..4d689d117bc 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -6,6 +6,8 @@ debug-logging = true # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true +# Print backtrace on internal compiler errors during bootstrap +backtrace-on-ice = true [llvm] # Will download LLVM from CI if available on your platform. diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index b9d7ecf8c0e..965d1162145 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -632,6 +632,26 @@ impl Step for Clippy { cargo.add_rustc_lib_path(builder, compiler); + if builder.try_run(&mut cargo.into()) { + // The tests succeeded; nothing to do. + return; + } + + if !builder.config.cmd.bless() { + std::process::exit(1); + } + + let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run"); + cargo.arg("-p").arg("clippy_dev"); + // clippy_dev gets confused if it can't find `clippy/Cargo.toml` + cargo.current_dir(&builder.src.join("src").join("tools").join("clippy")); + if builder.config.rust_optimize { + cargo.env("PROFILE", "release"); + } else { + cargo.env("PROFILE", "debug"); + } + cargo.arg("--"); + cargo.arg("bless"); builder.run(&mut cargo.into()); } } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index e85f4628fb0..4f2426648fd 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -392,7 +392,10 @@ impl ErrorIndex { let compiler = builder.compiler(builder.top_stage.saturating_sub(1), builder.config.build); let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler })); add_dylib_path( - vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))], + vec![ + PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)), + PathBuf::from(builder.rustc_libdir(compiler)), + ], &mut cmd, ); cmd diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index 08f07eb8284..ea70771a570 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -38,6 +38,7 @@ ENV HOSTS=x86_64-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --enable-extended \ + --enable-sanitizers \ --enable-profiler \ --enable-lld \ --set target.x86_64-unknown-linux-musl.crt-static=false \ diff --git a/src/doc/book b/src/doc/book -Subproject b54090a99ec7c4b46a5203a9c927fdbc311bb1f +Subproject 50dd06cb71beb27fdc0eebade5509cdcc1f821e diff --git a/src/doc/reference b/src/doc/reference -Subproject e1abb17cd94cd5a8a374b48e1bc8134a2208ed4 +Subproject d23f9da8469617e6c81121d9fd123443df70595 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject c80f0b09fc15b9251825343be910c08531938ab +Subproject e0a721f5202e6d9bec0aff99f10e44480c0da9e diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject a9bd2bbf31e4f92b5d3d8e80b22839d0cc7a202 +Subproject e72b43a64925ce053dc7830e21c1a57ba00499b diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7f57d476aa9..b3c67b84da6 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -6,43 +6,38 @@ } </style> -Support for different platforms are organized into three tiers, each with a -different set of guarantees. For more information on the policies for targets -at each tier, see the [Target Tier Policy](target-tier-policy.md). +Support for different platforms ("targets") are organized into three tiers, +each with a different set of guarantees. For more information on the policies +for targets at each tier, see the [Target Tier Policy](target-tier-policy.md). -Platforms are identified by their "target triple" which is the string to -inform the compiler what kind of output should be produced. The columns in the -tables below have the following meanings: +Targets are identified by their "target triple" which is the string to inform +the compiler what kind of output should be produced. -* std: - * ✓ indicates the full standard library is available. - * \* indicates the target only supports [`no_std`] development. - * ? indicates the standard library support is unknown or a work-in-progress. -* host: A ✓ indicates that `rustc` and `cargo` can run on the host platform. +## Tier 1 with Host Tools -[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html - -## Tier 1 +Tier 1 targets can be thought of as "guaranteed to work". The Rust project +builds official binary releases for each tier 1 target, and automated testing +ensures that each tier 1 target builds and passes tests after each change. -Tier 1 platforms can be thought of as "guaranteed to work". -Specifically they will each satisfy the following requirements: +Tier 1 targets with host tools additionally support running tools like `rustc` +and `cargo` natively on the target, and automated testing ensures that tests +pass for the host tools as well. This allows the target to be used as a +development platform, not just a compilation target. For the full requirements, +see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in +the Target Tier Policy. -* Official binary releases are provided for the platform. -* Automated testing is set up to run tests for the platform. -* Landing changes to the `rust-lang/rust` repository's master branch is gated - on tests passing. -* Documentation for how to use and how to build the platform is available. +All tier 1 targets with host tools support the full standard library. -target | std | host | notes --------|-----|------|------- -`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes] -`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+) -`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+) -`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) -`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+) -`x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+) -`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+) -`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) +target | notes +-------|------- +`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes] +`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) +`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) +`x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+) +`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) +`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) +`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) [^missing-stack-probes]: Stack probes support is missing on `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near @@ -50,105 +45,153 @@ target | std | host | notes [77071]: https://github.com/rust-lang/rust/issues/77071 +## Tier 1 + +Tier 1 targets can be thought of as "guaranteed to work". The Rust project +builds official binary releases for each tier 1 target, and automated testing +ensures that each tier 1 target builds and passes tests after each change. For +the full requirements, see [Tier 1 target +policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy. + +At this time, all Tier 1 targets are [Tier 1 with Host +Tools](#tier-1-with-host-tools). + +## Tier 2 with Host Tools + +Tier 2 targets can be thought of as "guaranteed to build". The Rust project +builds official binary releases for each tier 2 target, and automated builds +ensure that each tier 2 target builds after each change. Automated tests are +not always run so it's not guaranteed to produce a working build, but tier 2 +targets often work to quite a good degree and patches are always welcome! + +Tier 2 targets with host tools additionally support running tools like `rustc` +and `cargo` natively on the target, and automated builds ensure that the host +tools build as well. This allows the target to be used as a development +platform, not just a compilation target. For the full requirements, see [Tier 2 +with Host Tools](target-tier-policy.md#tier-2-with-host-tools) in the Target +Tier Policy. + +All tier 2 targets with host tools support the full standard library. + +target | notes +-------|------- +`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+) +`aarch64-pc-windows-msvc` | ARM64 Windows MSVC +`aarch64-unknown-linux-musl` | ARM64 Linux with MUSL +`arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17) +`arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) +`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23) +`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) +`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23) +`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23) +`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11) +`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11) +`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) +`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29) +`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.11) +`x86_64-unknown-freebsd` | 64-bit FreeBSD +`x86_64-unknown-illumos` | illumos +`x86_64-unknown-linux-musl` | 64-bit Linux with MUSL +`x86_64-unknown-netbsd` | NetBSD/amd64 + ## Tier 2 -Tier 2 platforms can be thought of as "guaranteed to build". Automated tests -are not run so it's not guaranteed to produce a working build, but platforms -often work to quite a good degree and patches are always welcome! -Specifically, these platforms are required to have each of the following: +Tier 2 targets can be thought of as "guaranteed to build". The Rust project +builds official binary releases for each tier 2 target, and automated builds +ensure that each tier 2 target builds after each change. Automated tests are +not always run so it's not guaranteed to produce a working build, but tier 2 +targets often work to quite a good degree and patches are always welcome! For +the full requirements, see [Tier 2 target +policy](target-tier-policy.md#tier-2-target-policy) in the Target Tier Policy. -* Official binary releases are provided for the platform. -* Automated building is set up, but may not be running tests. -* Landing changes to the `rust-lang/rust` repository's master branch is gated on - platforms **building**. For some platforms only the standard library is - compiled, but for others `rustc` and `cargo` are too. +The `std` column in the table below has the following meanings: -target | std | host | notes --------|-----|------|------- -`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+) -`aarch64-apple-ios` | ✓ | | ARM64 iOS -`aarch64-fuchsia` | ✓ | | ARM64 Fuchsia -`aarch64-linux-android` | ✓ | | ARM64 Android -`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC -`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL -`aarch64-unknown-none` | * | | Bare ARM64, hardfloat -`aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat -`arm-linux-androideabi` | ✓ | | ARMv7 Android -`arm-unknown-linux-gnueabi` | ✓ | ✓ | ARMv6 Linux (kernel 3.2, glibc 2.17) -`arm-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`arm-unknown-linux-musleabi` | ✓ | | ARMv6 Linux with MUSL -`arm-unknown-linux-musleabihf` | ✓ | | ARMv6 Linux with MUSL, hardfloat -`armebv7r-none-eabi` | * | | Bare ARMv7-R, Big Endian -`armebv7r-none-eabihf` | * | | Bare ARMv7-R, Big Endian, hardfloat -`armv5te-unknown-linux-gnueabi` | ✓ | | ARMv5TE Linux (kernel 4.4, glibc 2.23) -`armv5te-unknown-linux-musleabi` | ✓ | | ARMv5TE Linux with MUSL -`armv7-linux-androideabi` | ✓ | | ARMv7a Android -`armv7a-none-eabi` | * | | Bare ARMv7-A -`armv7r-none-eabi` | * | | Bare ARMv7-R -`armv7r-none-eabihf` | * | | Bare ARMv7-R, hardfloat -`armv7-unknown-linux-gnueabi` | ✓ | | ARMv7 Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-musleabi` | ✓ | | ARMv7 Linux, MUSL -`armv7-unknown-linux-musleabihf` | ✓ | | ARMv7 Linux with MUSL -`asmjs-unknown-emscripten` | ✓ | | asm.js via Emscripten -`i586-pc-windows-msvc` | ✓ | | 32-bit Windows w/o SSE -`i586-unknown-linux-gnu` | ✓ | | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23) -`i586-unknown-linux-musl` | ✓ | | 32-bit Linux w/o SSE, MUSL -`i686-linux-android` | ✓ | | 32-bit x86 Android -`i686-unknown-freebsd` | ✓ | | 32-bit FreeBSD -`i686-unknown-linux-musl` | ✓ | | 32-bit Linux with MUSL -`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23) -`mips-unknown-linux-musl` | ✓ | | MIPS Linux with MUSL -`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) -`mips64-unknown-linux-muslabi64` | ✓ | | MIPS64 Linux, n64 ABI, MUSL -`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23) -`mips64el-unknown-linux-muslabi64` | ✓ | | MIPS64 (LE) Linux, n64 ABI, MUSL -`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (LE) Linux (kernel 4.4, glibc 2.23) -`mipsel-unknown-linux-musl` | ✓ | | MIPS (LE) Linux with MUSL -`nvptx64-nvidia-cuda` | ✓ | | --emit=asm generates PTX code that [runs on NVIDIA GPUs] -`powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11) -`powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11) -`powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17) -`riscv32i-unknown-none-elf` | * | | Bare RISC-V (RV32I ISA) -`riscv32imac-unknown-none-elf` | * | | Bare RISC-V (RV32IMAC ISA) -`riscv32imc-unknown-none-elf` | * | | Bare RISC-V (RV32IMC ISA) -`riscv64gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 4.20, glibc 2.29) -`riscv64gc-unknown-none-elf` | * | | Bare RISC-V (RV64IMAFDC ISA) -`riscv64imac-unknown-none-elf` | * | | Bare RISC-V (RV64IMAC ISA) -`s390x-unknown-linux-gnu` | ✓ | ✓ | S390x Linux (kernel 2.6.32, glibc 2.11) -`sparc64-unknown-linux-gnu` | ✓ | | SPARC Linux (kernel 4.4, glibc 2.23) -`sparcv9-sun-solaris` | ✓ | | SPARC Solaris 10/11, illumos -`thumbv6m-none-eabi` | * | | Bare Cortex-M0, M0+, M1 -`thumbv7em-none-eabi` | * | | Bare Cortex-M4, M7 -`thumbv7em-none-eabihf` | * | | Bare Cortex-M4F, M7F, FPU, hardfloat -`thumbv7m-none-eabi` | * | | Bare Cortex-M3 -`thumbv7neon-linux-androideabi` | ✓ | | Thumb2-mode ARMv7a Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) -`thumbv8m.base-none-eabi` | * | | ARMv8-M Baseline -`thumbv8m.main-none-eabi` | * | | ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | | ARMv8-M Mainline, hardfloat -`wasm32-unknown-emscripten` | ✓ | | WebAssembly via Emscripten -`wasm32-unknown-unknown` | ✓ | | WebAssembly -`wasm32-wasi` | ✓ | | WebAssembly with WASI -`x86_64-apple-ios` | ✓ | | 64-bit x86 iOS -`x86_64-fortanix-unknown-sgx` | ✓ | | [Fortanix ABI] for 64-bit Intel SGX -`x86_64-fuchsia` | ✓ | | 64-bit Fuchsia -`x86_64-linux-android` | ✓ | | 64-bit x86 Android -`x86_64-pc-solaris` | ✓ | | 64-bit Solaris 10/11, illumos -`x86_64-unknown-freebsd` | ✓ | ✓ | 64-bit FreeBSD -`x86_64-unknown-illumos` | ✓ | ✓ | illumos -`x86_64-unknown-linux-gnux32` | ✓ | | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) -`x86_64-unknown-linux-musl` | ✓ | ✓ | 64-bit Linux with MUSL -`x86_64-unknown-netbsd` | ✓ | ✓ | NetBSD/amd64 -`x86_64-unknown-redox` | ✓ | | Redox OS +* ✓ indicates the full standard library is available. +* \* indicates the target only supports [`no_std`] development. + +[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html + +target | std | notes +-------|-----|------- +`aarch64-apple-ios` | ✓ | ARM64 iOS +`aarch64-fuchsia` | ✓ | ARM64 Fuchsia +`aarch64-linux-android` | ✓ | ARM64 Android +`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat +`aarch64-unknown-none` | * | Bare ARM64, hardfloat +`arm-linux-androideabi` | ✓ | ARMv7 Android +`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL +`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat +`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian +`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat +`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23) +`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL +`armv7-linux-androideabi` | ✓ | ARMv7a Android +`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27) +`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL +`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL +`armv7a-none-eabi` | * | Bare ARMv7-A +`armv7r-none-eabi` | * | Bare ARMv7-R +`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat +`asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten +`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE +`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23) +`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL +`i686-linux-android` | ✓ | 32-bit x86 Android +`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD +`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL +`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL +`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL +`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL +`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL +`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs] +`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA) +`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA) +`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA) +`riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) +`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) +`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) +`sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos +`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1 +`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7 +`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat +`thumbv7m-none-eabi` | * | Bare Cortex-M3 +`thumbv7neon-linux-androideabi` | ✓ | Thumb2-mode ARMv7a Android with NEON +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) +`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline +`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline +`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat +`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten +`wasm32-unknown-unknown` | ✓ | WebAssembly +`wasm32-wasi` | ✓ | WebAssembly with WASI +`x86_64-apple-ios` | ✓ | 64-bit x86 iOS +`x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX +`x86_64-fuchsia` | ✓ | 64-bit Fuchsia +`x86_64-linux-android` | ✓ | 64-bit x86 Android +`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos +`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) +`x86_64-unknown-redox` | ✓ | Redox OS [Fortanix ABI]: https://edp.fortanix.com/ ## Tier 3 -Tier 3 platforms are those which the Rust codebase has support for, but which -are not built or tested automatically, and may not work. Official builds are -not available. +Tier 3 targets are those which the Rust codebase has support for, but which the +Rust project does not build or test automatically, so they may or may not work. +Official builds are not available. For the full requirements, see [Tier 3 +target policy](target-tier-policy.md#tier-3-target-policy) in the Target Tier +Policy. + +The `std` column in the table below has the following meanings: + +* ✓ indicates the full standard library is available. +* \* indicates the target only supports [`no_std`] development. +* ? indicates the standard library support is unknown or a work-in-progress. + +[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html + +The `host` column indicates whether the codebase includes support for building +host tools. target | std | host | notes -------|-----|------|------- @@ -163,8 +206,8 @@ target | std | host | notes `aarch64-unknown-redox` | ? | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ? | | `aarch64-wrs-vxworks` | ? | | -`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) +`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `armv4t-unknown-linux-gnueabi` | ? | | `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD @@ -175,22 +218,22 @@ target | std | host | notes `armv7-wrs-vxworks-eabihf` | ? | | `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | -`avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core` +`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support -`i686-unknown-uefi` | * | | 32-bit UEFI `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD +`i686-unknown-uefi` | * | | 32-bit UEFI `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc +`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP) `mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc `mipsel-unknown-none` | * | | Bare MIPS (LE) softfloat -`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP) `mipsisa32r6-unknown-linux-gnu` | ? | | `mipsisa32r6el-unknown-linux-gnu` | ? | | `mipsisa64r6-unknown-linux-gnuabi64` | ? | | @@ -200,34 +243,34 @@ target | std | host | notes `powerpc-unknown-linux-musl` | ? | | `powerpc-unknown-netbsd` | ✓ | ✓ | `powerpc-unknown-openbsd` | ? | | -`powerpc-wrs-vxworks` | ? | | `powerpc-wrs-vxworks-spe` | ? | | +`powerpc-wrs-vxworks` | ? | | `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | -`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) +`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) `s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | +`thumbv4t-none-eabi` | * | | ARMv4T T32 `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL -`thumbv4t-none-eabi` | * | | ARMv4T T32 `wasm64-unknown-unknown` | * | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS -`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules -`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos `x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support +`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku `x86_64-unknown-hermit` | ? | | -`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel `x86_64-unknown-l4re-uclibc` | ? | | +`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel +`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD `x86_64-unknown-uefi` | * | | 64-bit UEFI `x86_64-uwp-windows-gnu` | ✓ | | diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 463f56099f6..a2cb0351916 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -1,5 +1,16 @@ # Target Tier Policy +## Table of Contents + +* [General](#general) +* [Tier 3 target policy](#tier-3-target-policy) +* [Tier 2 target policy](#tier-2-target-policy) + * [Tier 2 with host tools](#tier-2-with-host-tools) +* [Tier 1 target policy](#tier-1-target-policy) + * [Tier 1 with host tools](#tier-1-with-host-tools) + +## General + Rust provides three tiers of target support: - Rust provides no guarantees about tier 3 targets; they exist in the codebase, diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 0d05b80e211..f0ecb6871b1 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -200,7 +200,7 @@ running 31 tests test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` -You should have one ore more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them: +You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them: ```shell $ cargo profdata -- merge \ diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 4f9033cedc3..fa96e47ee03 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -535,20 +535,20 @@ Here is the list of currently supported register classes: | Architecture | Register class | Registers | LLVM constraint code | | ------------ | -------------- | --------- | -------------------- | -| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` | +| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` | | x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` | | x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` | -| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` | +| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` | | x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` | | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` | | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` | | x86 | `kreg` | `k[1-7]` | `Yk` | -| AArch64 | `reg` | `x[0-28]`, `x30` | `r` | +| AArch64 | `reg` | `x[0-30]` | `r` | | AArch64 | `vreg` | `v[0-31]` | `w` | | AArch64 | `vreg_low16` | `v[0-15]` | `x` | -| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` | +| ARM | `reg` | `r[0-12]`, `r14` | `r` | | ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` | -| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` | +| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` | | ARM | `sreg` | `s[0-31]` | `t` | | ARM | `sreg_low16` | `s[0-15]` | `x` | | ARM | `dreg` | `d[0-31]` | `w` | @@ -573,9 +573,7 @@ Here is the list of currently supported register classes: > > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported. > -> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform. -> -> Note #5: WebAssembly doesn't have registers, so named registers are not supported. +> Note #4: WebAssembly doesn't have registers, so named registers are not supported. Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc). @@ -677,13 +675,14 @@ Some registers cannot be used for input or output operands: | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | | All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | -| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. | +| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | x86 | `k0` | This is a constant zero register which can't be modified. | | x86 | `ip` | This is the program counter, not a real register. | | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). | | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | +| ARM | `r9` | This is a reserved register on some ARM targets. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | @@ -693,9 +692,10 @@ Some registers cannot be used for input or output operands: | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | -In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are: -- The frame pointer on all architectures. -- `r6` on ARM. +In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer +- The frame pointer and LLVM base pointer on all architectures. +- `r9` on ARM. +- `x18` on AArch64. ## Template modifiers diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 92eb6214f79..dbdf2e4bbb0 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -118,7 +118,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { span: Span::dummy(), unsafety: hir::Unsafety::Normal, generics: new_generics, - provided_trait_methods: Default::default(), trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), for_: ty.clean(self.cx), items: Vec::new(), diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 3a14a1d23f2..f5c4034a61d 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -92,12 +92,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { } self.cx.generated_synthetics.insert((ty, trait_def_id)); - let provided_trait_methods = self - .cx - .tcx - .provided_trait_methods(trait_def_id) - .map(|meth| meth.ident.name) - .collect(); impls.push(Item { name: None, @@ -112,7 +106,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { self.cx.tcx.explicit_predicates_of(impl_def_id), ) .clean(self.cx), - provided_trait_methods, // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3e89c1ac4c5..5dd9f3f1ebd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -414,16 +414,10 @@ crate fn build_impl( record_extern_trait(cx, trait_did); } - let provided = trait_ - .def_id() - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) - .unwrap_or_default(); - - debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); - let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); debug!("merged_attrs={:?}", merged_attrs); + debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); ret.push(clean::Item::from_def_id_and_attrs_and_parts( did, None, @@ -431,7 +425,6 @@ crate fn build_impl( span: clean::types::rustc_span(did, cx.tcx), unsafety: hir::Unsafety::Normal, generics, - provided_trait_methods: provided, trait_, for_, items: trait_items, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 12f03d00a65..78b76b05018 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1931,11 +1931,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_> build_deref_target_impls(cx, &items, &mut ret); } - let provided: FxHashSet<Symbol> = trait_ - .def_id() - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) - .unwrap_or_default(); - let for_ = impl_.self_ty.clean(cx); let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) { DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), @@ -1946,7 +1941,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_> span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx), unsafety: impl_.unsafety, generics: impl_.generics.clean(cx), - provided_trait_methods: provided.clone(), trait_, for_, items, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5e47144588b..33cb11e539b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -4,6 +4,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::lazy::SyncOnceCell as OnceCell; +use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; use std::{slice, vec}; @@ -90,6 +91,58 @@ impl ExternalCrate { tcx.crate_name(self.crate_num) } + crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf { + match self.src(tcx) { + FileName::Real(ref p) => match p.local_path().parent() { + Some(p) => p.to_path_buf(), + None => PathBuf::new(), + }, + _ => PathBuf::new(), + } + } + + /// Attempts to find where an external crate is located, given that we're + /// rendering in to the specified source destination. + crate fn location( + &self, + extern_url: Option<&str>, + dst: &std::path::Path, + tcx: TyCtxt<'_>, + ) -> ExternalLocation { + use ExternalLocation::*; + + fn to_remote(url: impl ToString) -> ExternalLocation { + let mut url = url.to_string(); + if !url.ends_with('/') { + url.push('/'); + } + Remote(url) + } + + // See if there's documentation generated into the local directory + // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts. + // Make sure to call `location()` by that time. + let local_location = dst.join(&*self.name(tcx).as_str()); + if local_location.is_dir() { + return Local; + } + + if let Some(url) = extern_url { + return to_remote(url); + } + + // Failing that, see if there's an attribute specifying where to find this + // external crate + let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }; + tcx.get_attrs(did) + .lists(sym::doc) + .filter(|a| a.has_name(sym::html_root_url)) + .filter_map(|a| a.value_str()) + .map(to_remote) + .next() + .unwrap_or(Unknown) // Well, at least we tried. + } + crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { let root = self.def_id(); @@ -381,7 +434,7 @@ impl Item { let relative_to = &cx.current; if let Some(ref fragment) = *fragment { let url = match cx.cache().extern_locations.get(&self.def_id.krate) { - Some(&(_, _, ExternalLocation::Local)) => { + Some(ExternalLocation::Local) => { if relative_to[0] == "std" { let depth = relative_to.len() - 1; "../".repeat(depth) @@ -390,10 +443,10 @@ impl Item { format!("{}std/", "../".repeat(depth)) } } - Some(&(_, _, ExternalLocation::Remote(ref s))) => { + Some(ExternalLocation::Remote(ref s)) => { format!("{}/std/", s.trim_end_matches('/')) } - Some(&(_, _, ExternalLocation::Unknown)) | None => format!( + Some(ExternalLocation::Unknown) | None => format!( "https://doc.rust-lang.org/{}/std/", crate::doc_rust_lang_org_channel(), ), @@ -2150,7 +2203,6 @@ crate struct Impl { crate span: Span, crate unsafety: hir::Unsafety, crate generics: Generics, - crate provided_trait_methods: FxHashSet<Symbol>, crate trait_: Option<Type>, crate for_: Type, crate items: Vec<Item>, @@ -2159,6 +2211,15 @@ crate struct Impl { crate blanket_impl: Option<Type>, } +impl Impl { + crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> { + self.trait_ + .def_id() + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) + .unwrap_or_default() + } +} + #[derive(Clone, Debug)] crate struct Import { crate kind: ImportKind, diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 8f10ab2d3ac..48eb14ed291 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -120,6 +120,8 @@ crate struct Options { /// For example, using ignore-foo to ignore running the doctest on any target that /// contains "foo" as a substring crate enable_per_target_ignores: bool, + /// Do not run doctests, compile them if should_test is active. + crate no_run: bool, /// The path to a rustc-like binary to build tests with. If not set, we /// default to loading from `$sysroot/bin/rustc`. @@ -197,6 +199,7 @@ impl fmt::Debug for Options { .field("runtool_args", &self.runtool_args) .field("enable-per-target-ignores", &self.enable_per_target_ignores) .field("run_check", &self.run_check) + .field("no_run", &self.no_run) .finish() } } @@ -466,6 +469,12 @@ impl Options { test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); let should_test = matches.opt_present("test"); + let no_run = matches.opt_present("no-run"); + + if !should_test && no_run { + diag.err("the `--test` flag must be passed to enable `--no-run`"); + return Err(1); + } let output = matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc")); @@ -666,6 +675,7 @@ impl Options { enable_per_target_ignores, test_builder, run_check, + no_run, render_options: RenderOptions { output, external_html, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 466d1b65406..c0157121e19 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -940,13 +940,14 @@ impl Tester for Collector { 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, line, options, config.should_panic, - config.no_run, + no_run, config.test_harness, runtool, runtool_args, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8f8bca64e14..8723e47586e 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,21 +1,19 @@ use std::collections::BTreeMap; use std::mem; -use std::path::{Path, PathBuf}; +use std::path::Path; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::TyCtxt; -use rustc_span::source_map::FileName; use rustc_span::symbol::sym; -use rustc_span::Symbol; use crate::clean::{self, GetDefId}; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::markdown::short_markdown_summary; -use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; +use crate::html::render::cache::{get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; /// This cache is used to store information about the [`clean::Crate`] being @@ -72,7 +70,7 @@ crate struct Cache { crate implementors: FxHashMap<DefId, Vec<Impl>>, /// Cache of where external crate documentation can be found. - crate extern_locations: FxHashMap<CrateNum, (Symbol, PathBuf, ExternalLocation)>, + crate extern_locations: FxHashMap<CrateNum, ExternalLocation>, /// Cache of where documentation for primitives can be found. crate primitive_locations: FxHashMap<clean::PrimitiveType, DefId>, @@ -155,21 +153,10 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code for &(n, ref e) in &krate.externs { - let src_root = match e.src(tcx) { - FileName::Real(ref p) => match p.local_path().parent() { - Some(p) => p.to_path_buf(), - None => PathBuf::new(), - }, - _ => PathBuf::new(), - }; let name = e.name(tcx); let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.extern_locations.insert( - n, - (name, src_root, extern_location(e, extern_url, tcx.get_attrs(did), &dst, tcx)), - ); - + self.extern_locations.insert(n, e.location(extern_url, &dst, tcx)); self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e39652c6dd5..f211a5acf5e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::spec::abi::Abi; -use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType}; +use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, PrimitiveType}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::render::cache::ExternalLocation; @@ -82,6 +82,10 @@ impl Buffer { self.buffer.push_str(s); } + crate fn push_buffer(&mut self, other: Buffer) { + self.buffer.push_str(&other.buffer); + } + // Intended for consumption by write! and writeln! (std::fmt) but without // the fmt::Result return type imposed by fmt::Write (and avoiding the trait // import). @@ -461,14 +465,14 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Option<(String, ItemType, Vec<Str fqp, shortty, match cache.extern_locations[&did.krate] { - (.., ExternalLocation::Remote(ref s)) => { + ExternalLocation::Remote(ref s) => { let s = s.trim_end_matches('/'); let mut s = vec![&s[..]]; s.extend(module_fqp[..].iter().map(String::as_str)); s } - (.., ExternalLocation::Local) => href_relative_parts(module_fqp, relative_to), - (.., ExternalLocation::Unknown) => return None, + ExternalLocation::Local => href_relative_parts(module_fqp, relative_to), + ExternalLocation::Unknown => return None, }, ) } @@ -574,12 +578,14 @@ fn primitive_link( Some(&def_id) => { let cname_str; let loc = match m.extern_locations[&def_id.krate] { - (ref cname, _, ExternalLocation::Remote(ref s)) => { - cname_str = cname.as_str(); + ExternalLocation::Remote(ref s) => { + cname_str = + ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str(); Some(vec![s.trim_end_matches('/'), &cname_str[..]]) } - (ref cname, _, ExternalLocation::Local) => { - cname_str = cname.as_str(); + ExternalLocation::Local => { + cname_str = + ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str(); Some(if cx.current.first().map(|x| &x[..]) == Some(&cname_str[..]) { iter::repeat("..").take(cx.current.len() - 1).collect() } else { @@ -587,7 +593,7 @@ fn primitive_link( iter::repeat("..").take(cx.current.len()).chain(cname).collect() }) } - (.., ExternalLocation::Unknown) => None, + ExternalLocation::Unknown => None, }; if let Some(loc) = loc { write!( diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index f4296a04e59..27a8065afb6 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -1,15 +1,13 @@ use std::collections::BTreeMap; -use std::path::Path; -use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; use crate::clean::types::{ - AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate, + FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate, }; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -26,47 +24,6 @@ crate enum ExternalLocation { Unknown, } -/// Attempts to find where an external crate is located, given that we're -/// rendering in to the specified source destination. -crate fn extern_location( - e: &clean::ExternalCrate, - extern_url: Option<&str>, - ast_attrs: &[ast::Attribute], - dst: &Path, - tcx: TyCtxt<'_>, -) -> ExternalLocation { - use ExternalLocation::*; - // See if there's documentation generated into the local directory - let local_location = dst.join(&*e.name(tcx).as_str()); - if local_location.is_dir() { - return Local; - } - - if let Some(url) = extern_url { - let mut url = url.to_string(); - if !url.ends_with('/') { - url.push('/'); - } - return Remote(url); - } - - // Failing that, see if there's an attribute specifying where to find this - // external crate - ast_attrs - .lists(sym::doc) - .filter(|a| a.has_name(sym::html_root_url)) - .filter_map(|a| a.value_str()) - .map(|url| { - let mut url = url.to_string(); - if !url.ends_with('/') { - url.push('/') - } - Remote(url) - }) - .next() - .unwrap_or(Unknown) // Well, at least we tried. -} - /// Builds the search index from the collected metadata crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String { let mut defid_to_pathid = FxHashMap::default(); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4c8ba0e7b49..293c0a40fa7 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -18,7 +18,7 @@ use super::print_item::{full_path, item_path, print_item}; use super::write_shared::write_shared; use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS}; -use crate::clean; +use crate::clean::{self, ExternalCrate}; use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; @@ -304,12 +304,16 @@ impl<'tcx> Context<'tcx> { } } else { let (krate, src_root) = match *self.cache.extern_locations.get(&cnum)? { - (name, ref src, ExternalLocation::Local) => (name, src), - (name, ref src, ExternalLocation::Remote(ref s)) => { + ExternalLocation::Local => { + let e = ExternalCrate { crate_num: cnum }; + (e.name(self.tcx()), e.src_root(self.tcx())) + } + ExternalLocation::Remote(ref s) => { root = s.to_string(); - (name, src) + let e = ExternalCrate { crate_num: cnum }; + (e.name(self.tcx()), e.src_root(self.tcx())) } - (_, _, ExternalLocation::Unknown) => return None, + ExternalLocation::Unknown => return None, }; sources::clean_path(&src_root, file, false, |component| { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 19b8dd15ad0..0a8026ef942 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -726,7 +726,8 @@ fn render_impls( .iter() .map(|i| { let did = i.trait_did_full(cache).unwrap(); - let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); + let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); + let assoc_link = AssocItemLink::GotoSource(did, &provided_trait_methods); let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; render_impl( &mut buffer, @@ -1281,99 +1282,6 @@ fn render_impl( let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); let mut close_tags = String::new(); - if render_mode == RenderMode::Normal { - let id = cx.derive_id(match i.inner_impl().trait_ { - Some(ref t) => { - if is_on_foreign_type { - get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) - } else { - format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) - } - } - None => "impl".to_string(), - }); - let aliases = if aliases.is_empty() { - String::new() - } else { - format!(" aliases=\"{}\"", aliases.join(",")) - }; - if let Some(use_absolute) = use_absolute { - write!( - w, - "<details class=\"rustdoc-toggle implementors-toggle\" open>\ - <summary>\ - <h3 id=\"{}\" class=\"impl\"{}>\ - <code class=\"in-band\">", - id, aliases - ); - close_tags.insert_str(0, "</details>"); - write!(w, "{}", i.inner_impl().print(use_absolute, cx)); - if show_def_docs { - for it in &i.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { - w.write_str("<span class=\"where fmt-newline\"> "); - assoc_type( - w, - it, - &[], - Some(&tydef.type_), - AssocItemLink::Anchor(None), - "", - cx, - ); - w.write_str(";</span>"); - } - } - } - w.write_str("</code>"); - } else { - write!( - w, - "<details class=\"rustdoc-toggle implementors-toggle\" open>\ - <summary>\ - <h3 id=\"{}\" class=\"impl\"{}>\ - <code class=\"in-band\">{}</code>", - id, - aliases, - i.inner_impl().print(false, cx) - ); - close_tags.insert_str(0, "</details>"); - } - write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - render_stability_since_raw( - w, - i.impl_item.stable_since(tcx).as_deref(), - i.impl_item.const_stable_since(tcx).as_deref(), - outer_version, - outer_const_version, - ); - write_srclink(cx, &i.impl_item, w); - w.write_str("</h3></summary>"); - - if trait_.is_some() { - if let Some(portability) = portability(&i.impl_item, Some(parent)) { - write!(w, "<div class=\"item-info\">{}</div>", portability); - } - } - - if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { - let mut ids = cx.id_map.borrow_mut(); - write!( - w, - "<div class=\"docblock\">{}</div>", - Markdown( - &*dox, - &i.impl_item.links(cx), - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) - .into_string() - ); - } - } - fn doc_impl_item( w: &mut Buffer, cx: &Context<'_>, @@ -1549,11 +1457,10 @@ fn render_impl( } } - w.write_str("<div class=\"impl-items\">"); - close_tags.insert_str(0, "</div>"); + let mut impl_items = Buffer::empty_from(w); for trait_item in &i.inner_impl().items { doc_impl_item( - w, + &mut impl_items, cx, trait_item, if trait_.is_some() { &i.impl_item } else { parent }, @@ -1584,7 +1491,8 @@ fn render_impl( continue; } let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap(); - let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods); + let provided_methods = i.provided_trait_methods(cx.tcx()); + let assoc_link = AssocItemLink::GotoSource(did, &provided_methods); doc_impl_item( w, @@ -1609,7 +1517,7 @@ fn render_impl( if show_default_items { if let Some(t) = trait_ { render_default_items( - w, + &mut impl_items, cx, &t.trait_, &i.inner_impl(), @@ -1621,6 +1529,111 @@ fn render_impl( ); } } + let details_str = if impl_items.is_empty() { + "" + } else { + "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>" + }; + if render_mode == RenderMode::Normal { + let id = cx.derive_id(match i.inner_impl().trait_ { + Some(ref t) => { + if is_on_foreign_type { + get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) + } else { + format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) + } + } + None => "impl".to_string(), + }); + let aliases = if aliases.is_empty() { + String::new() + } else { + format!(" data-aliases=\"{}\"", aliases.join(",")) + }; + if let Some(use_absolute) = use_absolute { + write!( + w, + "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", + details_str, id, aliases + ); + if !impl_items.is_empty() { + close_tags.insert_str(0, "</details>"); + } + write!(w, "{}", i.inner_impl().print(use_absolute, cx)); + if show_def_docs { + for it in &i.inner_impl().items { + if let clean::TypedefItem(ref tydef, _) = *it.kind { + w.write_str("<span class=\"where fmt-newline\"> "); + assoc_type( + w, + it, + &[], + Some(&tydef.type_), + AssocItemLink::Anchor(None), + "", + cx, + ); + w.write_str(";</span>"); + } + } + } + w.write_str("</code>"); + } else { + write!( + w, + "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", + details_str, + id, + aliases, + i.inner_impl().print(false, cx) + ); + if !impl_items.is_empty() { + close_tags.insert_str(0, "</details>"); + } + } + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + render_stability_since_raw( + w, + i.impl_item.stable_since(tcx).as_deref(), + i.impl_item.const_stable_since(tcx).as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, &i.impl_item, w); + if impl_items.is_empty() { + w.write_str("</h3>"); + } else { + w.write_str("</h3></summary>"); + } + + if trait_.is_some() { + if let Some(portability) = portability(&i.impl_item, Some(parent)) { + write!(w, "<div class=\"item-info\">{}</div>", portability); + } + } + + if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { + let mut ids = cx.id_map.borrow_mut(); + write!( + w, + "<div class=\"docblock\">{}</div>", + Markdown( + &*dox, + &i.impl_item.links(cx), + &mut ids, + cx.shared.codes, + cx.shared.edition(), + &cx.shared.playground + ) + .into_string() + ); + } + } + if !impl_items.is_empty() { + w.write_str("<div class=\"impl-items\">"); + w.push_buffer(impl_items); + close_tags.insert_str(0, "</div>"); + } w.write_str(&close_tags); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 1bb1db00e88..1bf726dd31a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -669,10 +669,9 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { - let assoc_link = AssocItemLink::GotoSource( - implementor.impl_item.def_id, - &implementor.inner_impl().provided_trait_methods, - ); + let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx()); + let assoc_link = + AssocItemLink::GotoSource(implementor.impl_item.def_id, &provided_methods); render_impl( w, cx, diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 7fbb97beae7..e81eaca8f0e 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -834,7 +834,7 @@ function hideThemeButtonState() { // (like "Send" and "Sync"). var inlined_types = new Set(); onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) { - var aliases = el.getAttribute("aliases"); + var aliases = el.getAttribute("data-aliases"); if (!aliases) { return; } @@ -1490,27 +1490,42 @@ function hideThemeButtonState() { searchState.setup(); }()); -function copy_path(but) { - var parent = but.parentElement; - var path = []; +(function () { + var reset_button_timeout = null; - onEach(parent.childNodes, function(child) { - if (child.tagName === 'A') { - path.push(child.textContent); - } - }); + window.copy_path = function(but) { + var parent = but.parentElement; + var path = []; - var el = document.createElement('textarea'); - el.value = 'use ' + path.join('::') + ';'; - el.setAttribute('readonly', ''); - // To not make it appear on the screen. - el.style.position = 'absolute'; - el.style.left = '-9999px'; + onEach(parent.childNodes, function(child) { + if (child.tagName === 'A') { + path.push(child.textContent); + } + }); - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); + var el = document.createElement('textarea'); + el.value = 'use ' + path.join('::') + ';'; + el.setAttribute('readonly', ''); + // To not make it appear on the screen. + el.style.position = 'absolute'; + el.style.left = '-9999px'; - but.textContent = '✓'; -} + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + + but.textContent = '✓'; + + if (reset_button_timeout !== null) { + window.clearTimeout(reset_button_timeout); + } + + function reset_button() { + but.textContent = '⎘'; + reset_button_timeout = null; + } + + reset_button_timeout = window.setTimeout(reset_button, 1000); + }; +}()); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index a024fa49b0e..a95c90e999f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -117,9 +117,12 @@ h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { } h1.fqn { display: flex; - width: 100%; border-bottom: 1px dashed; margin-top: 0; + + /* workaround to keep flex from breaking below 700 px width due to the float: right on the nav + above the h1 */ + padding-left: 1px; } h1.fqn > .in-band > a:hover { text-decoration: underline; @@ -385,17 +388,9 @@ nav.sub { position: relative; } -#results { - position: absolute; - right: 0; - left: 0; - overflow: auto; -} - #results > table { width: 100%; table-layout: fixed; - margin-bottom: 40px; } .content pre.line-numbers { @@ -453,20 +448,14 @@ nav.sub { } .content .out-of-band { - float: right; + flex-grow: 0; + text-align: right; font-size: 23px; margin: 0px; - padding: 0px; + padding: 0 0 0 12px; font-weight: normal; } -h1.fqn > .out-of-band { - float: unset; - flex: 1; - text-align: right; - margin-left: 8px; -} - h3.impl > .out-of-band { font-size: 21px; } @@ -486,6 +475,7 @@ h4 > code, h3 > code, .invisible > code { } .content .in-band { + flex-grow: 1; margin: 0px; padding: 0px; } @@ -1484,10 +1474,6 @@ h4 > .notable-traits { display: none !important; } - h1.fqn { - overflow: initial; - } - .theme-picker { left: 10px; top: 54px; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 2d8c347c3c1..8ca6342462f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -453,10 +453,10 @@ impl FromWithTcx<clean::Trait> for Trait { impl FromWithTcx<clean::Impl> for Impl { fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { + let provided_trait_methods = impl_.provided_trait_methods(tcx); let clean::Impl { unsafety, generics, - provided_trait_methods, trait_, for_, items, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 96ea4b6c3b8..ae4d1be3ec2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -17,7 +17,7 @@ use rustc_session::Session; use rustdoc_json_types as types; -use crate::clean; +use crate::clean::{self, ExternalCrate}; use crate::config::RenderOptions; use crate::error::Error; use crate::formats::cache::Cache; @@ -218,12 +218,13 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { .cache .extern_locations .iter() - .map(|(k, v)| { + .map(|(crate_num, external_location)| { + let e = ExternalCrate { crate_num: *crate_num }; ( - k.as_u32(), + crate_num.as_u32(), types::ExternalCrate { - name: v.0.to_string(), - html_root_url: match &v.2 { + name: e.name(self.tcx).to_string(), + html_root_url: match external_location { ExternalLocation::Remote(s) => Some(s.clone()), _ => None, }, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 26aaf0db6f6..2a25b595625 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,7 +16,7 @@ #![feature(type_ascription)] #![feature(iter_intersperse)] #![recursion_limit = "256"] -#![deny(rustc::internal)] +#![warn(rustc::internal)] #[macro_use] extern crate lazy_static; @@ -595,6 +595,7 @@ fn opts() -> Vec<RustcOptGroup> { "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]", ) }), + unstable("no-run", |o| o.optflag("", "no-run", "Compile doctests without running them")), ] } diff --git a/src/llvm-project b/src/llvm-project -Subproject 0ed6038a318e34e3d76a9e55bdebc4cfd17f902 +Subproject b61c24f3521303d442fa86fe691bc8e6acc1510 diff --git a/src/test/assembly/stack-probes.rs b/src/test/assembly/stack-probes.rs deleted file mode 100644 index 9597e242f1b..00000000000 --- a/src/test/assembly/stack-probes.rs +++ /dev/null @@ -1,42 +0,0 @@ -// min-llvm-version: 11.0.1 -// revisions: x86_64 i686 -// assembly-output: emit-asm -//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//[i686] compile-flags: --target i686-unknown-linux-gnu -// compile-flags: -C llvm-args=--x86-asm-syntax=intel - -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} - -impl Copy for u8 {} - -// Check that inline-asm stack probes are generated correctly. -// To avoid making this test fragile to slight asm changes, -// we only check that the stack pointer is decremented by a page at a time, -// instead of matching the whole probe sequence. - -// CHECK-LABEL: small_stack_probe: -#[no_mangle] -pub fn small_stack_probe(x: u8, f: fn([u8; 8192])) { - // CHECK-NOT: __rust_probestack - // x86_64: sub rsp, 4096 - // i686: sub esp, 4096 - let a = [x; 8192]; - f(a); -} - -// CHECK-LABEL: big_stack_probe: -#[no_mangle] -pub fn big_stack_probe(x: u8, f: fn([u8; 65536])) { - // CHECK-NOT: __rust_probestack - // x86_64: sub rsp, 4096 - // i686: sub esp, 4096 - let a = [x; 65536]; - f(a); -} diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs index c702742bf1a..baf9f3e9bd1 100644 --- a/src/test/codegen/asm-multiple-options.rs +++ b/src/test/codegen/asm-multiple-options.rs @@ -10,7 +10,7 @@ #[no_mangle] pub unsafe fn pure(x: i32) { let y: i32; - asm!("", out("ax") y, in("bx") x, options(pure), options(nomem)); + asm!("", out("ax") y, in("cx") x, options(pure), options(nomem)); } pub static mut VAR: i32 = 0; diff --git a/src/test/codegen/asm-options.rs b/src/test/codegen/asm-options.rs index 21e7eb43796..70391661b0c 100644 --- a/src/test/codegen/asm-options.rs +++ b/src/test/codegen/asm-options.rs @@ -10,7 +10,7 @@ #[no_mangle] pub unsafe fn pure(x: i32) { let y: i32; - asm!("", out("ax") y, in("bx") x, options(pure, nomem)); + asm!("", out("ax") y, in("cx") x, options(pure, nomem)); } // CHECK-LABEL: @noreturn diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index 2b8c0dfc229..f2641404aae 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -1,7 +1,7 @@ // Verify debuginfo for generators: // - Each variant points to the file and line of its yield point -// - The generator types and variants are marked artificial -// - Captured vars from the source are not marked artificial +// - The discriminants are marked artificial +// - Other fields are not marked artificial // // // compile-flags: -C debuginfo=2 --edition=2018 @@ -17,26 +17,32 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 12, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 14, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] diff --git a/src/test/codegen/async-fn-debug.rs b/src/test/codegen/async-fn-debug.rs index e9b774b48c3..7de115f7e91 100644 --- a/src/test/codegen/async-fn-debug.rs +++ b/src/test/codegen/async-fn-debug.rs @@ -1,7 +1,7 @@ // Verify debuginfo for async fn: // - Each variant points to the file and line of its yield point -// - The generator types and variants are marked artificial -// - Captured vars from the source are not marked artificial +// - The discriminants are marked artificial +// - Other fields are not marked artificial // // // compile-flags: -C debuginfo=2 --edition=2018 @@ -17,29 +17,36 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]] // CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 12, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 14, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 4f8a320ee9b..44be71f3b9b 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -1,7 +1,7 @@ // Verify debuginfo for generators: // - Each variant points to the file and line of its yield point -// - The generator types and variants are marked artificial -// - Captured vars from the source are not marked artificial +// - The discriminants are marked artificial +// - Other fields are not marked artificial // // // compile-flags: -C debuginfo=2 @@ -21,26 +21,32 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 17, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs index 86ac6db702a..8b87a2f0646 100644 --- a/src/test/codegen/generator-debug.rs +++ b/src/test/codegen/generator-debug.rs @@ -1,7 +1,7 @@ // Verify debuginfo for generators: // - Each variant points to the file and line of its yield point -// - The generator types and variants are marked artificial -// - Captured vars from the source are not marked artificial +// - The discriminants are marked artificial +// - Other fields are not marked artificial // // // compile-flags: -C debuginfo=2 --edition=2018 @@ -21,29 +21,36 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]] // CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: discriminator: [[DISC:![0-9]*]] // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 18, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 18, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 15, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]], // CHECK-SAME: file: [[FILE]], line: 17, -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], -// CHECK-SAME: flags: DIFlagArtificial +// CHECK-NOT: flags: DIFlagArtificial +// CHECK-SAME: ) // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index b05787df8e3..9bd351df3ea 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -13,12 +13,10 @@ // ignore-emscripten // ignore-windows // compile-flags: -C no-prepopulate-passes -// min-llvm-version: 11.0.1 #![crate_type = "lib"] #[no_mangle] pub fn foo() { // CHECK: @foo() unnamed_addr #0 -// CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} } } diff --git a/src/test/debuginfo/extern-c-fn.rs b/src/test/debuginfo/extern-c-fn.rs index 5043e7d9b8a..17a452ec634 100644 --- a/src/test/debuginfo/extern-c-fn.rs +++ b/src/test/debuginfo/extern-c-fn.rs @@ -5,17 +5,16 @@ // === GDB TESTS =================================================================================== // gdb-command:run -// gdb-command:print s -// gdbg-check:$1 = [...]"abcd" -// gdbr-check:$1 = [...]"abcd\000" +// gdb-command:printf "s = \"%s\"\n", s +// gdb-check:s = "abcd" // gdb-command:print len -// gdb-check:$2 = 20 +// gdb-check:$1 = 20 // gdb-command:print local0 -// gdb-check:$3 = 19 +// gdb-check:$2 = 19 // gdb-command:print local1 -// gdb-check:$4 = true +// gdb-check:$3 = true // gdb-command:print local2 -// gdb-check:$5 = 20.5 +// gdb-check:$4 = 20.5 // gdb-command:continue diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index b65471011fd..1beed1c835d 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -1,37 +1,41 @@ // Require a gdb that can read DW_TAG_variant_part. // min-gdb-version: 8.2 +// LLDB without native Rust support cannot read DW_TAG_variant_part, +// so it prints nothing for generators. But those tests are kept to +// ensure that LLDB won't crash at least (like #57822). + // compile-flags:-g // === GDB TESTS =================================================================================== // gdb-command:run // gdb-command:print b -// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} +// gdb-check:$1 = generator_objects::main::generator-0::Unresumed(0x[...]) // gdb-command:continue // gdb-command:print b -// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} +// gdb-check:$2 = generator_objects::main::generator-0::Suspend0{c: 6, d: 7, __0: 0x[...]} // gdb-command:continue // gdb-command:print b -// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}} +// gdb-check:$3 = generator_objects::main::generator-0::Suspend1{c: 7, d: 8, __0: 0x[...]} // gdb-command:continue // gdb-command:print b -// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} +// gdb-check:$4 = generator_objects::main::generator-0::Returned(0x[...]) // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print b -// lldbg-check:(generator_objects::main::generator-0) $0 = { 0 = 0x[...] } +// lldbg-check:(generator_objects::main::generator-0) $0 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator-0) $1 = { 0 = 0x[...] } +// lldbg-check:(generator_objects::main::generator-0) $1 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator-0) $2 = { 0 = 0x[...] } +// lldbg-check:(generator_objects::main::generator-0) $2 = // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator-0) $3 = { 0 = 0x[...] } +// lldbg-check:(generator_objects::main::generator-0) $3 = #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs index a68e4c0a556..6b2b12edda5 100644 --- a/src/test/debuginfo/issue-57822.rs +++ b/src/test/debuginfo/issue-57822.rs @@ -14,7 +14,7 @@ // gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1)) // gdb-command:print b -// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <<variant>>: {[...]}}, <<variant>>: {[...]}} +// gdb-check:$2 = issue_57822::main::generator-3::Unresumed(issue_57822::main::generator-2::Unresumed(2)) // === LLDB TESTS ================================================================================== @@ -24,7 +24,7 @@ // lldbg-check:(issue_57822::main::closure-1) $0 = { 0 = { 0 = 1 } } // lldb-command:print b -// lldbg-check:(issue_57822::main::generator-3) $1 = { 0 = { 0 = 2 } } +// lldbg-check:(issue_57822::main::generator-3) $1 = #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/pretty-huge-vec.rs b/src/test/debuginfo/pretty-huge-vec.rs index cbd2278f7e2..67155b4e9f0 100644 --- a/src/test/debuginfo/pretty-huge-vec.rs +++ b/src/test/debuginfo/pretty-huge-vec.rs @@ -13,7 +13,7 @@ // gdb-check:$1 = Vec(size=1000000000) = {[...]...} // gdb-command: print slice -// gdb-check:$2 = &[u8] {data_ptr: [...]"\000", length: 1000000000} +// gdb-check:$2 = &[u8] {data_ptr: [...], length: 1000000000} #![allow(unused_variables)] diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs index 08a0232f661..35b7183db7f 100644 --- a/src/test/incremental/commandline-args.rs +++ b/src/test/incremental/commandline-args.rs @@ -2,20 +2,23 @@ // the cache while changing an untracked one doesn't. // ignore-asmjs wasm2js does not support source maps yet -// revisions:rpass1 rpass2 rpass3 +// revisions:rpass1 rpass2 rpass3 rpass4 // compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![rustc_partition_codegened(module="commandline_args", cfg="rpass2")] #![rustc_partition_reused(module="commandline_args", cfg="rpass3")] +#![rustc_partition_codegened(module="commandline_args", cfg="rpass4")] // Between revisions 1 and 2, we are changing the debuginfo-level, which should // invalidate the cache. Between revisions 2 and 3, we are adding `--verbose` -// which should have no effect on the cache: +// which should have no effect on the cache. Between revisions, we are adding +// `--remap-path-prefix` which should invalidate the cache: //[rpass1] compile-flags: -C debuginfo=0 //[rpass2] compile-flags: -C debuginfo=2 //[rpass3] compile-flags: -C debuginfo=2 --verbose +//[rpass4] compile-flags: -C debuginfo=2 --verbose --remap-path-prefix=/home/bors/rust=src pub fn main() { // empty diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index ee7b258cec4..70ce81bd473 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -23,7 +23,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -85,7 +85,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")] @@ -100,7 +100,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")] @@ -135,7 +135,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -468,7 +468,7 @@ impl Bar<u32> { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] impl Bar<u64> { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")] diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs index 495445670c0..d874be060c2 100644 --- a/src/test/incremental/hashes/type_defs.rs +++ b/src/test/incremental/hashes/type_defs.rs @@ -24,7 +24,7 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -35,7 +35,7 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -60,7 +60,7 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -91,7 +91,7 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs index 4f5f6169f36..8df54467e5e 100644 --- a/src/test/incremental/ich_nested_items.rs +++ b/src/test/incremental/ich_nested_items.rs @@ -14,10 +14,7 @@ pub fn foo() { #[cfg(cfail1)] pub fn baz() {} // order is different... - // FIXME: Make "hir_owner" use `rustc_clean` here. Currently "hir_owner" includes a reference to - // the parent node, which is the statement holding this item. Changing the position of - // `bar` in `foo` will update that reference and make `hir_owner(bar)` dirty. - #[rustc_dirty(label = "hir_owner", cfg = "cfail2")] + #[rustc_clean(label = "hir_owner", cfg = "cfail2")] #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")] pub fn bar() {} // but that doesn't matter. diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp index c86d8a11971..a2065039692 100644 --- a/src/test/pretty/asm.pp +++ b/src/test/pretty/asm.pp @@ -21,7 +21,7 @@ pub fn main() { asm!("{0}", out(reg) a); asm!("{0}", inout(reg) b); asm!("{0} {1}", out(reg) _, inlateout(reg) b => _); - asm!("", out("al") _, lateout("rbx") _); + asm!("", out("al") _, lateout("rcx") _); asm!("inst1\ninst2"); asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b); asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b); diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs index 33f25e5216b..1156ab769a0 100644 --- a/src/test/pretty/asm.rs +++ b/src/test/pretty/asm.rs @@ -15,7 +15,7 @@ pub fn main() { asm!("{0}", out(reg) a); asm!("{name}", name = inout(reg) b); asm!("{} {}", out(reg) _, inlateout(reg) b => _); - asm!("", out("al") _, lateout("rbx") _); + asm!("", out("al") _, lateout("rcx") _); asm!("inst1", "inst2"); asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b); asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b); diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt new file mode 100644 index 00000000000..a030035f13b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt @@ -0,0 +1,42 @@ + 1| |// compile-flags: --edition=2018 + 2| |#![feature(no_coverage)] + 3| | + 4| |macro_rules! bail { + 5| | ($msg:literal $(,)?) => { + 6| | if $msg.len() > 0 { + 7| | println!("no msg"); + 8| | } else { + 9| | println!($msg); + 10| | } + 11| | return Err(String::from($msg)); + 12| | }; + 13| |} + 14| | + 15| |macro_rules! on_error { + 16| | ($value:expr, $error_message:expr) => { + 17| 0| $value.or_else(|e| { + 18| 0| let message = format!($error_message, e); + 19| 0| if message.len() > 0 { + 20| 0| println!("{}", message); + 21| 0| Ok(String::from("ok")) + 22| | } else { + 23| 0| bail!("error"); + 24| | } + 25| 0| }) + 26| | }; + 27| |} + 28| | + 29| 1|fn load_configuration_files() -> Result<String, String> { + 30| 1| Ok(String::from("config")) + 31| 1|} + 32| | + 33| 1|pub fn main() -> Result<(), String> { + 34| 1| println!("Starting service"); + 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + ^0 + 36| | + 37| 1| let startup_delay_duration = String::from("arg"); + 38| 1| let _ = (config, startup_delay_duration); + 39| 1| Ok(()) + 40| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt new file mode 100644 index 00000000000..a954eb30378 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt @@ -0,0 +1,83 @@ + 1| |// compile-flags: --edition=2018 + 2| |#![feature(no_coverage)] + 3| | + 4| |macro_rules! bail { + 5| | ($msg:literal $(,)?) => { + 6| | if $msg.len() > 0 { + 7| | println!("no msg"); + 8| | } else { + 9| | println!($msg); + 10| | } + 11| | return Err(String::from($msg)); + 12| | }; + 13| |} + 14| | + 15| |macro_rules! on_error { + 16| | ($value:expr, $error_message:expr) => { + 17| 0| $value.or_else(|e| { + 18| 0| let message = format!($error_message, e); + 19| 0| if message.len() > 0 { + 20| 0| println!("{}", message); + 21| 0| Ok(String::from("ok")) + 22| | } else { + 23| 0| bail!("error"); + 24| | } + 25| 0| }) + 26| | }; + 27| |} + 28| | + 29| 1|fn load_configuration_files() -> Result<String, String> { + 30| 1| Ok(String::from("config")) + 31| 1|} + 32| | + 33| 1|pub async fn test() -> Result<(), String> { + 34| 1| println!("Starting service"); + 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + ^0 + 36| | + 37| 1| let startup_delay_duration = String::from("arg"); + 38| 1| let _ = (config, startup_delay_duration); + 39| 1| Ok(()) + 40| 1|} + 41| | + 42| |#[no_coverage] + 43| |fn main() { + 44| | executor::block_on(test()); + 45| |} + 46| | + 47| |mod executor { + 48| | use core::{ + 49| | future::Future, + 50| | pin::Pin, + 51| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 52| | }; + 53| | + 54| | #[no_coverage] + 55| | pub fn block_on<F: Future>(mut future: F) -> F::Output { + 56| | let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 57| | use std::hint::unreachable_unchecked; + 58| | static VTABLE: RawWakerVTable = RawWakerVTable::new( + 59| | + 60| | #[no_coverage] + 61| | |_| unsafe { unreachable_unchecked() }, // clone + 62| | + 63| | #[no_coverage] + 64| | |_| unsafe { unreachable_unchecked() }, // wake + 65| | + 66| | #[no_coverage] + 67| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref + 68| | + 69| | #[no_coverage] + 70| | |_| (), + 71| | ); + 72| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 73| | let mut context = Context::from_waker(&waker); + 74| | + 75| | loop { + 76| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 77| | break val; + 78| | } + 79| | } + 80| | } + 81| |} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt index f5b5184044f..883254a09ba 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt @@ -1,9 +1,9 @@ 1| |#![allow(unused_assignments, unused_variables, dead_code)] 2| | 3| 1|fn main() { - 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| | // dependent conditions. + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. 7| 1| let is_true = std::env::args().len() == 1; 8| 1| 9| 1| let mut countdown = 0; diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt new file mode 100644 index 00000000000..de32c88b725 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt @@ -0,0 +1,22 @@ + 1| |// Shows that rust-lang/rust/83601 is resolved + 2| | + 3| 3|#[derive(Debug, PartialEq, Eq)] + ^2 + ------------------ + | <issue_83601::Foo as core::cmp::PartialEq>::eq: + | 3| 2|#[derive(Debug, PartialEq, Eq)] + ------------------ + | Unexecuted instantiation: <issue_83601::Foo as core::cmp::PartialEq>::ne + ------------------ + 4| |struct Foo(u32); + 5| | + 6| 1|fn main() { + 7| 1| let bar = Foo(1); + 8| 1| assert_eq!(bar, Foo(1)); + 9| 1| let baz = Foo(0); + 10| 1| assert_ne!(baz, Foo(1)); + 11| 1| println!("{:?}", Foo(1)); + 12| 1| println!("{:?}", bar); + 13| 1| println!("{:?}", baz); + 14| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt new file mode 100644 index 00000000000..f24f7c69404 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt @@ -0,0 +1,195 @@ + 1| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + 2| | + 3| |// expect-exit-status-101 + 4| 21|#[derive(PartialEq, Eq)] + ------------------ + | <issue_84561::Foo as core::cmp::PartialEq>::eq: + | 4| 21|#[derive(PartialEq, Eq)] + ------------------ + | Unexecuted instantiation: <issue_84561::Foo as core::cmp::PartialEq>::ne + ------------------ + 5| |struct Foo(u32); + 6| 1|fn test3() { + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| let bar = Foo(1); + 9| 1| assert_eq!(bar, Foo(1)); + 10| 1| let baz = Foo(0); + 11| 1| assert_ne!(baz, Foo(1)); + 12| 1| println!("{:?}", Foo(1)); + 13| 1| println!("{:?}", bar); + 14| 1| println!("{:?}", baz); + 15| 1| + 16| 1| assert_eq!(Foo(1), Foo(1)); + 17| 1| assert_ne!(Foo(0), Foo(1)); + 18| 1| assert_eq!(Foo(2), Foo(2)); + 19| 1| let bar = Foo(0); + 20| 1| assert_ne!(bar, Foo(3)); + 21| 1| assert_ne!(Foo(0), Foo(4)); + 22| 1| assert_eq!(Foo(3), Foo(3), "with a message"); + ^0 + 23| 1| println!("{:?}", bar); + 24| 1| println!("{:?}", Foo(1)); + 25| 1| + 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + ^0 ^0 ^0 + 27| 1| assert_ne!( + 28| | Foo(0) + 29| | , + 30| | Foo(5) + 31| | , + 32| 0| "{}" + 33| 0| , + 34| 0| if + 35| 0| is_true + 36| | { + 37| 0| "true message" + 38| | } else { + 39| 0| "false message" + 40| | } + 41| | ); + 42| | + 43| 1| let is_true = std::env::args().len() == 1; + 44| 1| + 45| 1| assert_eq!( + 46| 1| Foo(1), + 47| 1| Foo(1) + 48| 1| ); + 49| 1| assert_ne!( + 50| 1| Foo(0), + 51| 1| Foo(1) + 52| 1| ); + 53| 1| assert_eq!( + 54| 1| Foo(2), + 55| 1| Foo(2) + 56| 1| ); + 57| 1| let bar = Foo(1); + 58| 1| assert_ne!( + 59| 1| bar, + 60| 1| Foo(3) + 61| 1| ); + 62| 1| if is_true { + 63| 1| assert_ne!( + 64| 1| Foo(0), + 65| 1| Foo(4) + 66| 1| ); + 67| | } else { + 68| 0| assert_eq!( + 69| 0| Foo(3), + 70| 0| Foo(3) + 71| 0| ); + 72| | } + 73| 1| if is_true { + 74| 1| assert_ne!( + 75| | Foo(0), + 76| | Foo(4), + 77| 0| "with a message" + 78| | ); + 79| | } else { + 80| 0| assert_eq!( + 81| | Foo(3), + 82| | Foo(3), + 83| 0| "with a message" + 84| | ); + 85| | } + 86| 1| assert_ne!( + 87| 1| if is_true { + 88| 1| Foo(0) + 89| | } else { + 90| 0| Foo(1) + 91| | }, + 92| | Foo(5) + 93| | ); + 94| 1| assert_ne!( + 95| 1| Foo(5), + 96| 1| if is_true { + 97| 1| Foo(0) + 98| | } else { + 99| 0| Foo(1) + 100| | } + 101| | ); + 102| 1| assert_ne!( + 103| 1| if is_true { + 104| 1| assert_eq!( + 105| 1| Foo(3), + 106| 1| Foo(3) + 107| 1| ); + 108| 1| Foo(0) + 109| | } else { + 110| 0| assert_ne!( + 111| 0| if is_true { + 112| 0| Foo(0) + 113| | } else { + 114| 0| Foo(1) + 115| | }, + 116| | Foo(5) + 117| | ); + 118| 0| Foo(1) + 119| | }, + 120| | Foo(5), + 121| 0| "with a message" + 122| | ); + 123| 1| assert_eq!( + 124| | Foo(1), + 125| | Foo(3), + 126| 1| "this assert should fail" + 127| | ); + 128| 0| assert_eq!( + 129| | Foo(3), + 130| | Foo(3), + 131| 0| "this assert should not be reached" + 132| | ); + 133| 0|} + 134| | + 135| |impl std::fmt::Debug for Foo { + 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 137| 7| write!(f, "try and succeed")?; + ^0 + 138| 7| Ok(()) + 139| 7| } + 140| |} + 141| | + 142| |static mut DEBUG_LEVEL_ENABLED: bool = false; + 143| | + 144| |macro_rules! debug { + 145| | ($($arg:tt)+) => ( + 146| | if unsafe { DEBUG_LEVEL_ENABLED } { + 147| | println!($($arg)+); + 148| | } + 149| | ); + 150| |} + 151| | + 152| 1|fn test1() { + 153| 1| debug!("debug is enabled"); + ^0 + 154| 1| debug!("debug is enabled"); + ^0 + 155| 1| let _ = 0; + 156| 1| debug!("debug is enabled"); + ^0 + 157| 1| unsafe { + 158| 1| DEBUG_LEVEL_ENABLED = true; + 159| 1| } + 160| 1| debug!("debug is enabled"); + 161| 1|} + 162| | + 163| |macro_rules! call_debug { + 164| | ($($arg:tt)+) => ( + 165| 1| fn call_print(s: &str) { + 166| 1| print!("{}", s); + 167| 1| } + 168| | + 169| | call_print("called from call_debug: "); + 170| | debug!($($arg)+); + 171| | ); + 172| |} + 173| | + 174| 1|fn test2() { + 175| 1| call_debug!("debug is enabled"); + 176| 1|} + 177| | + 178| 1|fn main() { + 179| 1| test1(); + 180| 1| test2(); + 181| 1| test3(); + 182| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt new file mode 100644 index 00000000000..c4a7b0cc7e9 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt @@ -0,0 +1,18 @@ + 1| |// Enables `no_coverage` on the entire crate + 2| |#![feature(no_coverage)] + 3| | + 4| |#[no_coverage] + 5| |fn do_not_add_coverage_1() { + 6| | println!("called but not covered"); + 7| |} + 8| | + 9| |#[no_coverage] + 10| |fn do_not_add_coverage_2() { + 11| | println!("called but not covered"); + 12| |} + 13| | + 14| 1|fn main() { + 15| 1| do_not_add_coverage_1(); + 16| 1| do_not_add_coverage_2(); + 17| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt new file mode 100644 index 00000000000..16eaf7c858c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt @@ -0,0 +1,19 @@ + 1| |// Enables `no_coverage` on individual functions + 2| | + 3| |#[feature(no_coverage)] + 4| |#[no_coverage] + 5| |fn do_not_add_coverage_1() { + 6| | println!("called but not covered"); + 7| |} + 8| | + 9| |#[no_coverage] + 10| |#[feature(no_coverage)] + 11| |fn do_not_add_coverage_2() { + 12| | println!("called but not covered"); + 13| |} + 14| | + 15| 1|fn main() { + 16| 1| do_not_add_coverage_1(); + 17| 1| do_not_add_coverage_2(); + 18| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt index 4e4dde46b34..fc266653349 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt @@ -2,7 +2,7 @@ 2| |// structure of this test. 3| | 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^0 ^0 ^0 ^0 ^1 ^1 ^0^0 + ^0 ^0 ^0 ^1 ^1 ^0^0 ------------------ | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialEq>::ne ------------------ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt index c9ebffde039..9fca52451ed 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt @@ -9,7 +9,7 @@ 9| | } 10| 6|} 11| | - 12| 1|fn main() -> Result<(),()> { + 12| 1|fn test1() -> Result<(),()> { 13| 1| let mut 14| 1| countdown = 10 15| | ; @@ -35,4 +35,91 @@ 34| | } 35| 0| Ok(()) 36| 1|} + 37| | + 38| |struct Thing1; + 39| |impl Thing1 { + 40| 18| fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> { + 41| 18| if return_error { + 42| 1| Err(()) + 43| | } else { + 44| 17| Ok(Thing2{}) + 45| | } + 46| 18| } + 47| |} + 48| | + 49| |struct Thing2; + 50| |impl Thing2 { + 51| 17| fn call(&self, return_error: bool) -> Result<u32,()> { + 52| 17| if return_error { + 53| 2| Err(()) + 54| | } else { + 55| 15| Ok(57) + 56| | } + 57| 17| } + 58| |} + 59| | + 60| 1|fn test2() -> Result<(),()> { + 61| 1| let thing1 = Thing1{}; + 62| 1| let mut + 63| 1| countdown = 10 + 64| | ; + 65| | for + 66| 6| _ + 67| | in + 68| 6| 0..10 + 69| | { + 70| 6| countdown + 71| 6| -= 1 + 72| 6| ; + 73| 6| if + 74| 6| countdown < 5 + 75| | { + 76| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + ^0 + 77| 1| thing1 + 78| 1| . + 79| 1| get_thing_2(/*return_error=*/ false) + 80| 0| ? + 81| | . + 82| 1| call(/*return_error=*/ true) + 83| 1| . + 84| 1| expect_err( + 85| 1| "call should fail" + 86| 1| ); + 87| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + ^0 ^0 ^0 + 88| 0| assert_eq!(val, 57); + 89| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + 90| 0| assert_eq!(val, 57); + 91| | } + 92| | else + 93| | { + 94| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + ^0 ^0 + 95| 5| assert_eq!(val, 57); + 96| 5| let val = thing1 + 97| 5| .get_thing_2(/*return_error=*/ false)? + ^0 + 98| 5| .call(/*return_error=*/ false)?; + ^0 + 99| 5| assert_eq!(val, 57); + 100| 5| let val = thing1 + 101| 5| .get_thing_2(/*return_error=*/ false) + 102| 0| ? + 103| 5| .call(/*return_error=*/ false) + 104| 0| ? + 105| | ; + 106| 5| assert_eq!(val, 57); + 107| | } + 108| | } + 109| 0| Ok(()) + 110| 1|} + 111| | + 112| 1|fn main() -> Result<(),()> { + 113| 1| test1().expect_err("test1 should fail"); + 114| 1| test2() + 115| 1| ? + 116| | ; + 117| 0| Ok(()) + 118| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index f5beb9ef24a..018d2642344 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -3,9 +3,9 @@ 3| |use std::fmt::Debug; 4| | 5| 1|pub fn used_function() { - 6| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 7| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 8| | // dependent conditions. + 6| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 7| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 8| 1| // dependent conditions. 9| 1| let is_true = std::env::args().len() == 1; 10| 1| let mut countdown = 0; 11| 1| if is_true { @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index cc98956e307..dab31cbf4ac 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -5,9 +5,9 @@ 5| |use std::fmt::Debug; 6| | 7| 1|pub fn used_function() { - 8| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 9| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 10| | // dependent conditions. + 8| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 9| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 10| 1| // dependent conditions. 11| 1| let is_true = std::env::args().len() == 1; 12| 1| let mut countdown = 0; 13| 1| if is_true { @@ -19,9 +19,9 @@ 18| | 19| |#[inline(always)] 20| 1|pub fn used_inline_function() { - 21| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - 22| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 23| | // dependent conditions. + 21| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 22| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 23| 1| // dependent conditions. 24| 1| let is_true = std::env::args().len() == 1; 25| 1| let mut countdown = 0; 26| 1| if is_true { diff --git a/src/test/run-make-fulldeps/coverage/closure_macro.rs b/src/test/run-make-fulldeps/coverage/closure_macro.rs new file mode 100644 index 00000000000..10e434007b8 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/closure_macro.rs @@ -0,0 +1,40 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result<String, String> { + Ok(String::from("config")) +} + +pub fn main() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} diff --git a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs new file mode 100644 index 00000000000..bcdfd11f899 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs @@ -0,0 +1,81 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result<String, String> { + Ok(String::from("config")) +} + +pub async fn test() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} + +#[no_coverage] +fn main() { + executor::block_on(test()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + #[no_coverage] + pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // clone + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + + #[no_coverage] + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/src/test/run-make-fulldeps/coverage/issue-83601.rs b/src/test/run-make-fulldeps/coverage/issue-83601.rs new file mode 100644 index 00000000000..0b72a81947c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/issue-83601.rs @@ -0,0 +1,14 @@ +// Shows that rust-lang/rust/83601 is resolved + +#[derive(Debug, PartialEq, Eq)] +struct Foo(u32); + +fn main() { + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); +} diff --git a/src/test/run-make-fulldeps/coverage/issue-84561.rs b/src/test/run-make-fulldeps/coverage/issue-84561.rs new file mode 100644 index 00000000000..b39a289c45e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/issue-84561.rs @@ -0,0 +1,182 @@ +// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + +// expect-exit-status-101 +#[derive(PartialEq, Eq)] +struct Foo(u32); +fn test3() { + let is_true = std::env::args().len() == 1; + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); + + assert_eq!(Foo(1), Foo(1)); + assert_ne!(Foo(0), Foo(1)); + assert_eq!(Foo(2), Foo(2)); + let bar = Foo(0); + assert_ne!(bar, Foo(3)); + assert_ne!(Foo(0), Foo(4)); + assert_eq!(Foo(3), Foo(3), "with a message"); + println!("{:?}", bar); + println!("{:?}", Foo(1)); + + assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + assert_ne!( + Foo(0) + , + Foo(5) + , + "{}" + , + if + is_true + { + "true message" + } else { + "false message" + } + ); + + let is_true = std::env::args().len() == 1; + + assert_eq!( + Foo(1), + Foo(1) + ); + assert_ne!( + Foo(0), + Foo(1) + ); + assert_eq!( + Foo(2), + Foo(2) + ); + let bar = Foo(1); + assert_ne!( + bar, + Foo(3) + ); + if is_true { + assert_ne!( + Foo(0), + Foo(4) + ); + } else { + assert_eq!( + Foo(3), + Foo(3) + ); + } + if is_true { + assert_ne!( + Foo(0), + Foo(4), + "with a message" + ); + } else { + assert_eq!( + Foo(3), + Foo(3), + "with a message" + ); + } + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + assert_ne!( + Foo(5), + if is_true { + Foo(0) + } else { + Foo(1) + } + ); + assert_ne!( + if is_true { + assert_eq!( + Foo(3), + Foo(3) + ); + Foo(0) + } else { + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + Foo(1) + }, + Foo(5), + "with a message" + ); + assert_eq!( + Foo(1), + Foo(3), + "this assert should fail" + ); + assert_eq!( + Foo(3), + Foo(3), + "this assert should not be reached" + ); +} + +impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "try and succeed")?; + Ok(()) + } +} + +static mut DEBUG_LEVEL_ENABLED: bool = false; + +macro_rules! debug { + ($($arg:tt)+) => ( + if unsafe { DEBUG_LEVEL_ENABLED } { + println!($($arg)+); + } + ); +} + +fn test1() { + debug!("debug is enabled"); + debug!("debug is enabled"); + let _ = 0; + debug!("debug is enabled"); + unsafe { + DEBUG_LEVEL_ENABLED = true; + } + debug!("debug is enabled"); +} + +macro_rules! call_debug { + ($($arg:tt)+) => ( + fn call_print(s: &str) { + print!("{}", s); + } + + call_print("called from call_debug: "); + debug!($($arg)+); + ); +} + +fn test2() { + call_debug!("debug is enabled"); +} + +fn main() { + test1(); + test2(); + test3(); +} diff --git a/src/test/run-make-fulldeps/coverage/no_cov_crate.rs b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs new file mode 100644 index 00000000000..300570db7e8 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/no_cov_crate.rs @@ -0,0 +1,17 @@ +// Enables `no_coverage` on the entire crate +#![feature(no_coverage)] + +#[no_coverage] +fn do_not_add_coverage_1() { + println!("called but not covered"); +} + +#[no_coverage] +fn do_not_add_coverage_2() { + println!("called but not covered"); +} + +fn main() { + do_not_add_coverage_1(); + do_not_add_coverage_2(); +} diff --git a/src/test/run-make-fulldeps/coverage/no_cov_func.rs b/src/test/run-make-fulldeps/coverage/no_cov_func.rs new file mode 100644 index 00000000000..e19a2c4a872 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/no_cov_func.rs @@ -0,0 +1,18 @@ +// Enables `no_coverage` on individual functions + +#[feature(no_coverage)] +#[no_coverage] +fn do_not_add_coverage_1() { + println!("called but not covered"); +} + +#[no_coverage] +#[feature(no_coverage)] +fn do_not_add_coverage_2() { + println!("called but not covered"); +} + +fn main() { + do_not_add_coverage_1(); + do_not_add_coverage_2(); +} diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make-fulldeps/coverage/try_error_result.rs index 13c455172dd..cd0acf72302 100644 --- a/src/test/run-make-fulldeps/coverage/try_error_result.rs +++ b/src/test/run-make-fulldeps/coverage/try_error_result.rs @@ -9,7 +9,7 @@ fn call(return_error: bool) -> Result<(),()> { } } -fn main() -> Result<(),()> { +fn test1() -> Result<(),()> { let mut countdown = 10 ; @@ -34,3 +34,85 @@ fn main() -> Result<(),()> { } Ok(()) } + +struct Thing1; +impl Thing1 { + fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> { + if return_error { + Err(()) + } else { + Ok(Thing2{}) + } + } +} + +struct Thing2; +impl Thing2 { + fn call(&self, return_error: bool) -> Result<u32,()> { + if return_error { + Err(()) + } else { + Ok(57) + } + } +} + +fn test2() -> Result<(),()> { + let thing1 = Thing1{}; + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + thing1 + . + get_thing_2(/*return_error=*/ false) + ? + . + call(/*return_error=*/ true) + . + expect_err( + "call should fail" + ); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + assert_eq!(val, 57); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + } + else + { + let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false)? + .call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false) + ? + .call(/*return_error=*/ false) + ? + ; + assert_eq!(val, 57); + } + } + Ok(()) +} + +fn main() -> Result<(),()> { + test1().expect_err("test1 should fail"); + test2() + ? + ; + Ok(()) +} diff --git a/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile index 50ff3dd56ce..371f94715a8 100644 --- a/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile +++ b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk # rust-lang/rust#70924: Test that if we add rust-src component in between two -# incremetnal compiles, the compiler does not ICE on the second. +# incremental compiles, the compiler does not ICE on the second. # This test uses `ln -s` rather than copying to save testing time, but its # usage doesn't work on windows. So ignore windows. diff --git a/src/test/rustdoc-ui/no-run-flag-error.rs b/src/test/rustdoc-ui/no-run-flag-error.rs new file mode 100644 index 00000000000..4ead621482b --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag-error.rs @@ -0,0 +1,6 @@ +// test the behavior of the --no-run flag without the --test flag + +// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1 +// error-pattern: the `--test` flag must be passed + +pub fn f() {} diff --git a/src/test/rustdoc-ui/no-run-flag-error.stderr b/src/test/rustdoc-ui/no-run-flag-error.stderr new file mode 100644 index 00000000000..d032646c365 --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag-error.stderr @@ -0,0 +1,2 @@ +error: the `--test` flag must be passed to enable `--no-run` + diff --git a/src/test/rustdoc-ui/no-run-flag.rs b/src/test/rustdoc-ui/no-run-flag.rs new file mode 100644 index 00000000000..da1672c4a6e --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag.rs @@ -0,0 +1,38 @@ +// test the behavior of the --no-run flag + +// check-pass +// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +/// ``` +/// let a = true; +/// ``` +/// ```should_panic +/// panic!() +/// ``` +/// ```ignore (incomplete-code) +/// fn foo() { +/// ``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +/// fails to compile +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` +/// Ok the test does not run +/// ``` +/// panic!() +/// ``` +/// Ok the test does not run +/// ```should_panic +/// loop { +/// println!("Hello, world"); +/// panic!() +/// } +/// ``` +pub fn f() {} diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout new file mode 100644 index 00000000000..d92f5da8335 --- /dev/null +++ b/src/test/rustdoc-ui/no-run-flag.stdout @@ -0,0 +1,12 @@ + +running 7 tests +test $DIR/no-run-flag.rs - f (line 11) ... ok +test $DIR/no-run-flag.rs - f (line 14) ... ignored +test $DIR/no-run-flag.rs - f (line 17) ... ok +test $DIR/no-run-flag.rs - f (line 23) ... ok +test $DIR/no-run-flag.rs - f (line 28) ... ok +test $DIR/no-run-flag.rs - f (line 32) ... ok +test $DIR/no-run-flag.rs - f (line 8) ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs index b8f3527510c..56e0770ab5c 100644 --- a/src/test/rustdoc/auto_aliases.rs +++ b/src/test/rustdoc/auto_aliases.rs @@ -1,6 +1,6 @@ #![feature(auto_traits)] -// @has auto_aliases/trait.Bar.html '//h3[@aliases="auto_aliases::Foo"]' 'impl Bar for Foo' +// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo' pub struct Foo; pub auto trait Bar {} diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs new file mode 100644 index 00000000000..86dec32e625 --- /dev/null +++ b/src/test/rustdoc/empty-impls.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo' +pub struct Foo; + +pub trait EmptyTrait {} + +// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo' +impl EmptyTrait for Foo {} + +pub trait NotEmpty { + fn foo(&self); +} + +// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo' +impl NotEmpty for Foo { + fn foo(&self) {} +} diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs index daebe059f8e..ddc14e68675 100644 --- a/src/test/rustdoc/issue-53812.rs +++ b/src/test/rustdoc/issue-53812.rs @@ -12,9 +12,9 @@ macro_rules! array_impls { } } -// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>' +// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs index d8a9ae6ca20..5a6283e9f13 100644 --- a/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs +++ b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs @@ -2,8 +2,6 @@ // run-pass -#![feature(const_fn)] - #[derive(PartialEq, Debug, Clone)] struct N(u8); diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs index 18be201d640..634ef010e6f 100644 --- a/src/test/ui/asm/sym.rs +++ b/src/test/ui/asm/sym.rs @@ -1,6 +1,4 @@ // min-llvm-version: 10.0.1 -// FIXME(#84025): codegen-units=1 leads to linkage errors -// compile-flags: -C codegen-units=2 // only-x86_64 // only-linux // run-pass diff --git a/src/test/ui/associated-consts/associated-const-in-trait.rs b/src/test/ui/associated-consts/associated-const-in-trait.rs index cc3acd53956..f3024120df1 100644 --- a/src/test/ui/associated-consts/associated-const-in-trait.rs +++ b/src/test/ui/associated-consts/associated-const-in-trait.rs @@ -1,6 +1,6 @@ // #29924 -#![feature(const_fn, associated_consts)] +#![feature(associated_consts)] trait Trait { const N: usize; diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr index 193026541d0..599d0e13557 100644 --- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -21,9 +21,9 @@ error[E0373]: async block may outlive the current function, but it borrows `x`, --> $DIR/async-borrowck-escaping-block-error.rs:11:11 | LL | async { *x } - | ^^^-^^ - | | | - | | `x` is borrowed here + | ^^--^^ + | | | + | | `x` is borrowed here | may outlive borrowed value `x` | note: async block is returned here diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs index 718c597e712..7a67661a019 100644 --- a/src/test/ui/async-await/issue-68523.rs +++ b/src/test/ui/async-await/issue-68523.rs @@ -2,6 +2,5 @@ async fn main() -> Result<i32, ()> { //~^ ERROR `main` function is not allowed to be `async` -//~^^ ERROR `main` has invalid return type `impl Future` Ok(1) } diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr index 6f67af04cd4..dfdf078e303 100644 --- a/src/test/ui/async-await/issue-68523.stderr +++ b/src/test/ui/async-await/issue-68523.stderr @@ -1,18 +1,9 @@ -error[E0277]: `main` has invalid return type `impl Future` - --> $DIR/issue-68523.rs:3:20 - | -LL | async fn main() -> Result<i32, ()> { - | ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination` - | - = help: consider using `()`, or a `Result` - error[E0752]: `main` function is not allowed to be `async` --> $DIR/issue-68523.rs:3:1 | LL | async fn main() -> Result<i32, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0752. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0752`. diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr index edeb21c16d3..fadcd11a592 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr @@ -73,7 +73,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/borrowck-closures-mut-and-imm.rs:57:5 | LL | let c1 = || get(&*x); - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `*x` occurs here LL | *x = 5; @@ -86,7 +86,7 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed --> $DIR/borrowck-closures-mut-and-imm.rs:69:5 | LL | let c1 = || get(&*x.f); - | -- - borrow occurs due to use in closure + | -- ---- borrow occurs due to use in closure | | | borrow of `*x.f` occurs here LL | *x.f = 5; @@ -99,11 +99,11 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/borrowck-closures-mut-and-imm.rs:81:14 | LL | let c1 = || get(&*x.f); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | immutable borrow occurs here LL | let c2 = || *x.f = 5; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr index 784b903a589..537ec9895e1 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -14,12 +14,12 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-imm.rs:11:18 | LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | first closure is constructed here LL | LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | second closure is constructed here ... diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr index 471173e595f..e5ee5a40105 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -2,11 +2,11 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-mut.rs:14:18 | LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | first closure is constructed here LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | second closure is constructed here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr index 9e1e47a9241..411d85b8e05 100644 --- a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -45,7 +45,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut LL | let f = || { | -- immutable borrow occurs here LL | let [ref y, ref z @ ..] = *x; - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &mut *x; | ^^^^^^^ mutable borrow occurs here @@ -59,7 +59,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut f = || { | -- closure construction occurs here LL | let [ref mut y, ref mut z @ ..] = *x; - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &x; | ^^ second borrow occurs here @@ -86,7 +86,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut LL | let f = || { | -- immutable borrow occurs here LL | if let [ref y, ref z @ ..] = *x {} - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &mut *x; | ^^^^^^^ mutable borrow occurs here @@ -100,7 +100,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut f = || { | -- closure construction occurs here LL | if let [ref mut y, ref mut z @ ..] = *x {} - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &x; | ^^ second borrow occurs here diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr index 07f477d1786..fe8e7a29e24 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr @@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:53:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr index bffb1164074..21e329f4329 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr @@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut.rs:49:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 64c2f419ffa..23d3cc0e76f 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -20,7 +20,7 @@ LL | let c1 = || get(x); | | | borrow occurs here LL | let c2 = || { get(x); set(x); }; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | c1; diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr index f22b7da8119..a6dbcf36077 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure LL | }; LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.stderr index 796390c093b..a1ac45795fa 100644 --- a/src/test/ui/borrowck/borrowck-insert-during-each.stderr +++ b/src/test/ui/borrowck/borrowck-insert-during-each.stderr @@ -9,7 +9,7 @@ LL | | LL | | |a| { | | --- closure construction occurs here LL | | f.n.insert(*a); - | | - first borrow occurs due to use of `f` in closure + | | --- first borrow occurs due to use of `f` in closure LL | | }) | |__________^ second borrow occurs here @@ -24,7 +24,7 @@ LL | LL | |a| { | ^^^ closure construction occurs here LL | f.n.insert(*a); - | - second borrow occurs due to use of `f` in closure + | --- second borrow occurs due to use of `f` in closure error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index 2acbcd94f8b..ac25502ad05 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -7,7 +7,7 @@ LL | thread::spawn(move|| { | ^^^^^^ move out of `v` occurs here LL | LL | println!("v={}", *v); - | - move occurs due to use in closure + | -- move occurs due to use in closure LL | }); LL | w.use_ref(); | - borrow later used here @@ -21,7 +21,7 @@ LL | thread::spawn(move|| { | ^^^^^^ move out of `v` occurs here LL | LL | println!("v={}", *v); - | - move occurs due to use in closure + | -- move occurs due to use in closure LL | }); LL | w.use_ref(); | - borrow later used here diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr index ec3edc80323..489ec7d04ed 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr @@ -7,7 +7,7 @@ LL | p.blockm(|| { | | immutable borrow later used by call | immutable borrow occurs here LL | p.x = 10; - | - second borrow occurs due to use of `p` in closure + | --- second borrow occurs due to use of `p` in closure error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr.rs:34:5 diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 837bd08253b..628f206e0a8 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -5,10 +5,10 @@ LL | let bar: Box<_> = box 3; | --- captured outer variable LL | let _g = to_fn_mut(|| { LL | let _h = to_fn_once(move || -> isize { *bar }); - | ^^^^^^^^^^^^^^^^ --- - | | | - | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^^^^^^^^^^^^^^^ ---- + | | | + | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait + | | move occurs due to use in closure | move out of `bar` occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr index 44f423c2bd9..1ac4999e6e1 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -5,11 +5,11 @@ LL | let t: Box<_> = box 3; | - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); - | ------ - variable moved due to use in closure + | ------ -- variable moved due to use in closure | | | value moved into closure here LL | call_f(move|| { *t + 1 }); - | ^^^^^^ - use occurs due to use in closure + | ^^^^^^ -- use occurs due to use in closure | | | value used here after move diff --git a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr index f0a3151f4e1..dd46308d140 100644 --- a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr +++ b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr @@ -5,7 +5,7 @@ LL | match x { | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr index f0264b56ea5..48433432de1 100644 --- a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr +++ b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern g --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25 | LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })(); - | ^^ - mutable borrow occurs due to use of `r` in closure + | ^^ -- mutable borrow occurs due to use of `r` in closure | | | cannot borrow as mutable | diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs new file mode 100644 index 00000000000..6da88bed2c6 --- /dev/null +++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs @@ -0,0 +1,32 @@ +// rust-lang/rust#83309: The compiler tries to suggest potential +// methods that return `&mut` items. However, when it doesn't +// find such methods, it still tries to add suggestions +// which then fails an assertion later because there was +// no suggestions to make. + + +fn main() { + for v in Query.iter_mut() { + //~^ NOTE this iterator yields `&` references + *v -= 1; + //~^ ERROR cannot assign to `*v` which is behind a `&` reference + //~| NOTE `v` is a `&` reference, so the data it refers to cannot be written + } +} + +pub struct Query; +pub struct QueryIter<'a>(&'a i32); + +impl Query { + pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a> { + todo!(); + } +} + +impl<'a> Iterator for QueryIter<'a> { + type Item = &'a i32; + + fn next(&mut self) -> Option<Self::Item> { + todo!(); + } +} diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr new file mode 100644 index 00000000000..143b74c39ba --- /dev/null +++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to `*v` which is behind a `&` reference + --> $DIR/issue-83309-ice-immut-in-for-loop.rs:11:9 + | +LL | for v in Query.iter_mut() { + | ---------------- this iterator yields `&` references +LL | +LL | *v -= 1; + | ^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs new file mode 100644 index 00000000000..2f3358dcd8d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs @@ -0,0 +1,20 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn main() { + let mut p = Point {x: 1, y: 2 }; + + let y = &mut p.y; + let mut c = || { + //~^ ERROR cannot borrow `p` as mutable more than once at a time + let x = &mut p.x; + println!("{:?}", p); + }; + c(); + *y+=1; +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr new file mode 100644 index 00000000000..e15067b264d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr @@ -0,0 +1,28 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-1.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information + +error[E0499]: cannot borrow `p` as mutable more than once at a time + --> $DIR/borrowck-1.rs:13:17 + | +LL | let y = &mut p.y; + | -------- first mutable borrow occurs here +LL | let mut c = || { + | ^^ second mutable borrow occurs here +LL | +LL | let x = &mut p.x; + | --- capture is mutable because of use here +LL | println!("{:?}", p); + | - second borrow occurs due to use of `p` in closure +... +LL | *y+=1; + | ----- first borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs new file mode 100644 index 00000000000..06c6a87eb10 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs @@ -0,0 +1,20 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn main() { + let mut p = Point {x: 1, y: 2 }; + + let y = &p.y; + let mut c = || { + //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable + println!("{:?}", p); + let x = &mut p.x; + }; + c(); + println!("{}", y); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr new file mode 100644 index 00000000000..a195b981eaa --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr @@ -0,0 +1,28 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-2.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information + +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-2.rs:13:17 + | +LL | let y = &p.y; + | ---- immutable borrow occurs here +LL | let mut c = || { + | ^^ mutable borrow occurs here +LL | +LL | println!("{:?}", p); + | - second borrow occurs due to use of `p` in closure +LL | let x = &mut p.x; + | --- capture is mutable because of use here +... +LL | println!("{}", y); + | - immutable borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs new file mode 100644 index 00000000000..ba998f78c87 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs @@ -0,0 +1,19 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: String, + y: String, +} +fn main() { + let mut c = { + let mut p = Point {x: "1".to_string(), y: "2".to_string() }; + || { + let x = &mut p.x; + println!("{:?}", p); + //~^ ERROR `p` does not live long enough + } + }; + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr new file mode 100644 index 00000000000..b54c729a307 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr @@ -0,0 +1,27 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-3.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information + +error[E0597]: `p` does not live long enough + --> $DIR/borrowck-3.rs:14:29 + | +LL | let mut c = { + | ----- borrow later stored here +LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() }; +LL | || { + | -- value captured here +LL | let x = &mut p.x; +LL | println!("{:?}", p); + | ^ borrowed value does not live long enough +... +LL | }; + | - `p` dropped here while still borrowed + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs new file mode 100644 index 00000000000..4fab0189c27 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs @@ -0,0 +1,21 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn foo () -> impl FnMut()->() { + let mut p = Point {x: 1, y: 2 }; + let mut c = || { + //~^ ERROR closure may outlive the current function, but it borrows `p` + p.x+=5; + println!("{:?}", p); + }; + c +} +fn main() { + let c = foo(); + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr new file mode 100644 index 00000000000..905fa3475ed --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr @@ -0,0 +1,31 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-4.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information + +error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function + --> $DIR/borrowck-4.rs:11:17 + | +LL | let mut c = || { + | ^^ may outlive borrowed value `p` +... +LL | println!("{:?}", p); + | - `p` is borrowed here + | +note: closure is returned here + --> $DIR/borrowck-4.rs:9:14 + | +LL | fn foo () -> impl FnMut()->() { + | ^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword + | +LL | let mut c = move || { + | ^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs new file mode 100644 index 00000000000..b23947ad5d1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs @@ -0,0 +1,26 @@ +// Tests that two closures cannot simultaneously have mutable +// and immutable access to the variable. Issue #6801. + +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![feature(box_syntax)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +fn a() { + let mut p = Point {x: 3, y:4}; + let c2 = || p.y * 5; + let c1 = || { + //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable + dbg!(&p); + p.x = 4; + }; + drop(c2); +} + +fn main() { +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr new file mode 100644 index 00000000000..58975c6f46f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr @@ -0,0 +1,30 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-closures-mut-and-imm.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information + +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-mut-and-imm.rs:17:14 + | +LL | let c2 = || p.y * 5; + | -- --- first borrow occurs due to use of `p.y` in closure + | | + | immutable borrow occurs here +LL | let c1 = || { + | ^^ mutable borrow occurs here +LL | +LL | dbg!(&p); + | - second borrow occurs due to use of `p` in closure +LL | p.x = 4; + | --- capture is mutable because of use here +LL | }; +LL | drop(c2); + | -- immutable borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr index 17a9332fb3e..174faa33c49 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -13,7 +13,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed LL | let mut c = || { | -- borrow of `e.0.0.m.x` occurs here LL | e.0.0.m.x = format!("not-x"); - | - borrow occurs due to use in closure + | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here @@ -27,7 +27,7 @@ error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed LL | let mut c = || { | -- mutable borrow occurs here LL | e.0.0.m.x = format!("not-x"); - | - first borrow occurs due to use of `e.0.0.m.x` in closure + | --------- first borrow occurs due to use of `e.0.0.m.x` in closure ... LL | println!("{}", e.0.0.m.x); | ^^^^^^^^^ immutable borrow occurs here @@ -41,7 +41,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed LL | let c = || { | -- borrow of `e.0.0.m.x` occurs here LL | println!("{}", e.0.0.m.x); - | - borrow occurs due to use in closure + | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr index 861bc44b78d..39a11fb3327 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr @@ -14,7 +14,7 @@ LL | let mut c = || { | ^^ cannot borrow as mutable LL | LL | z.0.0.0 = format!("X1"); - | - mutable borrow occurs due to use of `z.0.0.0` in closure + | ------- mutable borrow occurs due to use of `z.0.0.0` in closure error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs index 997ecc7dddd..928c866726f 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs @@ -11,7 +11,7 @@ fn mut_error_struct() { let mut c = || { z.0.0.0 = 20; - //~^ ERROR: cannot assign to `z`, as it is not declared as mutable + //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable }; c(); @@ -23,7 +23,7 @@ fn mut_error_box() { let mut c = || { bx.0 = 20; - //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable + //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr index 5e15635ac6e..9fb8dd4a1c3 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr @@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information -error[E0594]: cannot assign to `z`, as it is not declared as mutable +error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:13:9 | LL | let z = (y, 10); @@ -16,7 +16,7 @@ LL | let z = (y, 10); LL | z.0.0.0 = 20; | ^^^^^^^^^^^^ cannot assign -error[E0594]: cannot assign to `bx`, as it is not declared as mutable +error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:25:9 | LL | let bx = Box::new(x); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr index e5a396c4e98..a3d1f550557 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr @@ -13,7 +13,7 @@ error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time LL | let mut c = || { | -- first mutable borrow occurs here LL | w.p.x += 20; - | - first borrow occurs due to use of `w.p.x` in closure + | ----- first borrow occurs due to use of `w.p.x` in closure ... LL | let py = &mut w.p.x; | ^^^^^^^^^^ second mutable borrow occurs here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr index 8cb2ed2235d..831e486db82 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr @@ -17,7 +17,7 @@ LL | let c = || { | ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable LL | LL | **ref_mref_x = y; - | ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure + | ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference --> $DIR/mut_ref.rs:27:13 @@ -26,7 +26,7 @@ LL | let c = || { | ^^ cannot borrow as mutable LL | LL | **mref_ref_x = y; - | ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure + | ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr index 45a61cd98b1..f1748fda151 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -13,7 +13,9 @@ error[E0502]: cannot borrow `p` as immutable because it is also borrowed as muta LL | let mut c = || { | -- mutable borrow occurs here LL | p.x += 10; - | - first borrow occurs due to use of `p` in closure + | --- capture is mutable because of use here +LL | println!("{:?}", p); + | - first borrow occurs due to use of `p` in closure ... LL | println!("{:?}", p); | ^ immutable borrow occurs here diff --git a/src/test/ui/const-generics/issues/issue-83466.rs b/src/test/ui/const-generics/issues/issue-83466.rs new file mode 100644 index 00000000000..c488a663fbb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-83466.rs @@ -0,0 +1,17 @@ +// regression test for #83466- tests that generic arg mismatch errors between +// consts and types are not supressed when there are explicit late bound lifetimes + +struct S; +impl S { + fn func<'a, U>(self) -> U { + todo!() + } +} +fn dont_crash<'a, U>() { + S.func::<'a, 10_u32>() + //~^ WARNING cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + //~^^ WARNING this was previously accepted by + //~^^^ ERROR constant provided when a type was expected [E0747] +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-83466.stderr b/src/test/ui/const-generics/issues/issue-83466.stderr new file mode 100644 index 00000000000..a60f71ea614 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-83466.stderr @@ -0,0 +1,22 @@ +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-83466.rs:11:14 + | +LL | fn func<'a, U>(self) -> U { + | -- the late bound lifetime parameter is introduced here +... +LL | S.func::<'a, 10_u32>() + | ^^ + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error[E0747]: constant provided when a type was expected + --> $DIR/issue-83466.rs:11:18 + | +LL | S.func::<'a, 10_u32>() + | ^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/consts/const-eval/auxiliary/stability.rs b/src/test/ui/consts/const-eval/auxiliary/stability.rs index 70531114f21..e6159551860 100644 --- a/src/test/ui/consts/const-eval/auxiliary/stability.rs +++ b/src/test/ui/consts/const-eval/auxiliary/stability.rs @@ -3,7 +3,6 @@ #![crate_type="rlib"] #![stable(feature = "rust1", since = "1.0.0")] -#![feature(const_fn)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.rs b/src/test/ui/consts/const-eval/const_fn_ptr.rs index 045fe9ad11a..b3c677c6984 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr.rs +++ b/src/test/ui/consts/const-eval/const_fn_ptr.rs @@ -1,6 +1,5 @@ // run-pass // compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(const_fn)] fn double(x: usize) -> usize { x * 2 } const fn double_const(x: usize) -> usize { x * 2 } diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr index ab18020056b..a16ac7b2a24 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr @@ -1,27 +1,27 @@ warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr.rs:12:5 + --> $DIR/const_fn_ptr.rs:11:5 | LL | X(x) | ^^^^ help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr.rs:16:5 + --> $DIR/const_fn_ptr.rs:15:5 | LL | X_CONST(x) | ^^^^^^^^^^ help: skipping check for `const_fn_fn_ptr_basics` feature - --> $DIR/const_fn_ptr.rs:19:14 + --> $DIR/const_fn_ptr.rs:18:14 | LL | const fn foo(x: fn(usize) -> usize, y: usize) -> usize { | ^ help: skipping check for `const_fn_fn_ptr_basics` feature - --> $DIR/const_fn_ptr.rs:20:5 + --> $DIR/const_fn_ptr.rs:19:5 | LL | x(y) | ^ help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr.rs:20:5 + --> $DIR/const_fn_ptr.rs:19:5 | LL | x(y) | ^^^^ diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs index 14bd6558e7f..1896eba82f2 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.rs @@ -1,6 +1,5 @@ // run-pass // compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(const_fn)] #![allow(unused)] fn double(x: usize) -> usize { x * 2 } diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr index 0a7182fd39c..ec5de575906 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr @@ -1,7 +1,7 @@ warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr_fail.rs:10:5 + --> $DIR/const_fn_ptr_fail.rs:9:5 | LL | X(x) // FIXME: this should error someday | ^^^^ diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs index 0a2532973f4..804ebf66008 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs @@ -1,7 +1,6 @@ // build-fail // compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(const_fn)] #![allow(const_err)] fn double(x: usize) -> usize { diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr index 2afedf30563..4f7a771f418 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_fn_ptr_fail2.rs:20:16 + --> $DIR/const_fn_ptr_fail2.rs:19:16 | LL | assert_eq!(Y, 4); | ^ referenced constant has errors error[E0080]: evaluation of constant value failed - --> $DIR/const_fn_ptr_fail2.rs:22:16 + --> $DIR/const_fn_ptr_fail2.rs:21:16 | LL | assert_eq!(Z, 4); | ^ referenced constant has errors @@ -13,17 +13,17 @@ LL | assert_eq!(Z, 4); warning: skipping const checks | help: skipping check for `const_fn_fn_ptr_basics` feature - --> $DIR/const_fn_ptr_fail2.rs:12:14 + --> $DIR/const_fn_ptr_fail2.rs:11:14 | LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize { | ^ help: skipping check for `const_fn_fn_ptr_basics` feature - --> $DIR/const_fn_ptr_fail2.rs:13:5 + --> $DIR/const_fn_ptr_fail2.rs:12:5 | LL | x(y) | ^ help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr_fail2.rs:13:5 + --> $DIR/const_fn_ptr_fail2.rs:12:5 | LL | x(y) | ^^^^ diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs index 3729285956b..4b3cf70739c 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs @@ -3,7 +3,6 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index ca80a9ab391..69e3ca716a9 100644 --- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -1,5 +1,5 @@ error: `foo` is not yet stable as a const fn - --> $DIR/dont_promote_unstable_const_fn.rs:15:25 + --> $DIR/dont_promote_unstable_const_fn.rs:14:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ @@ -7,7 +7,7 @@ LL | const fn bar() -> u32 { foo() } = help: add `#![feature(foo)]` to the crate attributes to enable error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:18:28 + --> $DIR/dont_promote_unstable_const_fn.rs:17:28 | LL | let _: &'static u32 = &foo(); | ------------ ^^^^^ creates a temporary which is freed while still in use @@ -17,7 +17,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:22:28 + --> $DIR/dont_promote_unstable_const_fn.rs:21:28 | LL | let _: &'static u32 = &meh(); | ------------ ^^^^^ creates a temporary which is freed while still in use @@ -28,7 +28,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/dont_promote_unstable_const_fn.rs:23:26 + --> $DIR/dont_promote_unstable_const_fn.rs:22:26 | LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/const-eval/double_promotion.rs b/src/test/ui/consts/const-eval/double_promotion.rs index 48f4426d9cf..9ee2777a647 100644 --- a/src/test/ui/consts/const-eval/double_promotion.rs +++ b/src/test/ui/consts/const-eval/double_promotion.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(const_fn, rustc_attrs)] +#![feature(rustc_attrs)] #[rustc_args_required_const(0)] pub const fn a(value: u8) -> u8 { diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs index 3f7bab06586..26162aa6228 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs @@ -1,5 +1,3 @@ -#![feature(const_fn)] - fn main() {} #[repr(C)] diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr index 4c8492b22f6..bc3b6aa6653 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr @@ -1,5 +1,5 @@ error[E0658]: unions in const fn are unstable - --> $DIR/feature-gate-const_fn_union.rs:12:5 + --> $DIR/feature-gate-const_fn_union.rs:10:5 | LL | Foo { u }.i | ^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 3edd4e08686..1a99c77c6dd 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -1,4 +1,4 @@ -#![feature(const_fn, const_fn_union)] +#![feature(const_fn_union)] #![allow(const_err)] diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs index 7887e426534..c9e4871bb7c 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs @@ -1,4 +1,4 @@ -#![feature(const_fn, const_fn_union)] +#![feature(const_fn_union)] #![deny(const_err)] diff --git a/src/test/ui/consts/const-eval/simd/insert_extract.rs b/src/test/ui/consts/const-eval/simd/insert_extract.rs index 9e5cb0d4eb1..cae8fcf1068 100644 --- a/src/test/ui/consts/const-eval/simd/insert_extract.rs +++ b/src/test/ui/consts/const-eval/simd/insert_extract.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(const_fn)] #![feature(repr_simd)] #![feature(platform_intrinsics)] #![feature(staged_api)] diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.rs b/src/test/ui/consts/const-eval/union-const-eval-field.rs index f8e1d6d569d..80263718330 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.rs +++ b/src/test/ui/consts/const-eval/union-const-eval-field.rs @@ -1,5 +1,4 @@ // only-x86_64 -#![feature(const_fn)] type Field1 = i32; type Field2 = f32; diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.stderr b/src/test/ui/consts/const-eval/union-const-eval-field.stderr index c1c2dcb2269..e5a107ff011 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.stderr +++ b/src/test/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-const-eval-field.rs:29:5 + --> $DIR/union-const-eval-field.rs:28:5 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes diff --git a/src/test/ui/consts/const-eval/union-ice.rs b/src/test/ui/consts/const-eval/union-ice.rs index 40e5a005ba4..4189619b2aa 100644 --- a/src/test/ui/consts/const-eval/union-ice.rs +++ b/src/test/ui/consts/const-eval/union-ice.rs @@ -1,5 +1,4 @@ // only-x86_64 -#![feature(const_fn)] type Field1 = i32; type Field3 = i64; diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index f8b9478ad1a..6d44b3c8b28 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:15:1 + --> $DIR/union-ice.rs:14:1 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes @@ -10,7 +10,7 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:17:1 + --> $DIR/union-ice.rs:16:1 | LL | / const FIELD_PATH: Struct = Struct { LL | | a: 42, @@ -24,7 +24,7 @@ LL | | }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:27:1 + --> $DIR/union-ice.rs:26:1 | LL | / const FIELD_PATH2: Struct2 = Struct2 { LL | | b: [ diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index bb91b43e20b..e25abab7e37 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -1,18 +1,18 @@ warning: any use of this value will cause an error - --> $DIR/validate_uninhabited_zsts.rs:6:14 + --> $DIR/validate_uninhabited_zsts.rs:5:14 | LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ | | | transmuting to uninhabited type - | inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14 - | inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26 + | inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14 + | inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26 ... LL | const FOO: [Empty; 3] = [foo(); 3]; | ----------------------------------- | note: the lint level is defined here - --> $DIR/validate_uninhabited_zsts.rs:15:8 + --> $DIR/validate_uninhabited_zsts.rs:14:8 | LL | #[warn(const_err)] | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #[warn(const_err)] = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:19:1 + --> $DIR/validate_uninhabited_zsts.rs:18:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] @@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; = note: the raw bytes of the constant (size: 0, align: 1) {} warning: the type `!` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:6:14 + --> $DIR/validate_uninhabited_zsts.rs:5:14 | LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | unsafe { std::mem::transmute(()) } = note: the `!` type has no valid value warning: the type `Empty` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:19:35 + --> $DIR/validate_uninhabited_zsts.rs:18:35 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index bb91b43e20b..e25abab7e37 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -1,18 +1,18 @@ warning: any use of this value will cause an error - --> $DIR/validate_uninhabited_zsts.rs:6:14 + --> $DIR/validate_uninhabited_zsts.rs:5:14 | LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ | | | transmuting to uninhabited type - | inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14 - | inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26 + | inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14 + | inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26 ... LL | const FOO: [Empty; 3] = [foo(); 3]; | ----------------------------------- | note: the lint level is defined here - --> $DIR/validate_uninhabited_zsts.rs:15:8 + --> $DIR/validate_uninhabited_zsts.rs:14:8 | LL | #[warn(const_err)] | ^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #[warn(const_err)] = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:19:1 + --> $DIR/validate_uninhabited_zsts.rs:18:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] @@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; = note: the raw bytes of the constant (size: 0, align: 1) {} warning: the type `!` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:6:14 + --> $DIR/validate_uninhabited_zsts.rs:5:14 | LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | unsafe { std::mem::transmute(()) } = note: the `!` type has no valid value warning: the type `Empty` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:19:35 + --> $DIR/validate_uninhabited_zsts.rs:18:35 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs index a32dfa2918b..112ace5e97f 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -1,5 +1,4 @@ // stderr-per-bitwidth -#![feature(const_fn)] #![feature(const_fn_transmute)] const fn foo() -> ! { diff --git a/src/test/ui/consts/const-fn-error.rs b/src/test/ui/consts/const-fn-error.rs index 68a4d414ff3..b9c5a0e040d 100644 --- a/src/test/ui/consts/const-fn-error.rs +++ b/src/test/ui/consts/const-fn-error.rs @@ -1,5 +1,3 @@ -#![feature(const_fn)] - const X : usize = 2; const fn f(x: usize) -> usize { diff --git a/src/test/ui/consts/const-fn-error.stderr b/src/test/ui/consts/const-fn-error.stderr index 86b1eebcb2c..f5e69bba4c5 100644 --- a/src/test/ui/consts/const-fn-error.stderr +++ b/src/test/ui/consts/const-fn-error.stderr @@ -1,5 +1,5 @@ error[E0744]: `for` is not allowed in a `const fn` - --> $DIR/const-fn-error.rs:7:5 + --> $DIR/const-fn-error.rs:5:5 | LL | / for i in 0..x { LL | | @@ -11,13 +11,13 @@ LL | | } | |_____^ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/const-fn-error.rs:7:14 + --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const-fn-error.rs:7:14 + --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ @@ -26,22 +26,22 @@ LL | for i in 0..x { = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/const-fn-error.rs:7:14 + --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/const-fn-error.rs:7:14 + --> $DIR/const-fn-error.rs:5:14 | LL | for i in 0..x { | ^^^^ | | | calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter` - | inside `f` at $DIR/const-fn-error.rs:7:14 + | inside `f` at $DIR/const-fn-error.rs:5:14 ... LL | let a : [i32; f(X)]; - | ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:20:19 + | ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:18:19 error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/const-fn-mismatch.rs b/src/test/ui/consts/const-fn-mismatch.rs index d4cfba6460c..3107b8128e6 100644 --- a/src/test/ui/consts/const-fn-mismatch.rs +++ b/src/test/ui/consts/const-fn-mismatch.rs @@ -3,8 +3,6 @@ // it if the trait fn is const (but right now no trait fns can be // const). -#![feature(const_fn)] - trait Foo { fn f() -> u32; } diff --git a/src/test/ui/consts/const-fn-mismatch.stderr b/src/test/ui/consts/const-fn-mismatch.stderr index 0f4ce010fee..a86a06b3ef1 100644 --- a/src/test/ui/consts/const-fn-mismatch.stderr +++ b/src/test/ui/consts/const-fn-mismatch.stderr @@ -1,5 +1,5 @@ error[E0379]: functions in traits cannot be declared const - --> $DIR/const-fn-mismatch.rs:13:5 + --> $DIR/const-fn-mismatch.rs:11:5 | LL | const fn f() -> u32 { | ^^^^^ functions in traits cannot be const diff --git a/src/test/ui/consts/const-fn-not-in-trait.rs b/src/test/ui/consts/const-fn-not-in-trait.rs index cbc220a1ba2..00bae3f3b99 100644 --- a/src/test/ui/consts/const-fn-not-in-trait.rs +++ b/src/test/ui/consts/const-fn-not-in-trait.rs @@ -1,8 +1,6 @@ // Test that const fn is illegal in a trait declaration, whether or // not a default is provided, and even with the feature gate. -#![feature(const_fn)] - trait Foo { const fn f() -> u32; //~^ ERROR functions in traits cannot be declared const diff --git a/src/test/ui/consts/const-fn-not-in-trait.stderr b/src/test/ui/consts/const-fn-not-in-trait.stderr index 12ce3066037..5d364eb882d 100644 --- a/src/test/ui/consts/const-fn-not-in-trait.stderr +++ b/src/test/ui/consts/const-fn-not-in-trait.stderr @@ -1,11 +1,11 @@ error[E0379]: functions in traits cannot be declared const - --> $DIR/const-fn-not-in-trait.rs:7:5 + --> $DIR/const-fn-not-in-trait.rs:5:5 | LL | const fn f() -> u32; | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/const-fn-not-in-trait.rs:9:5 + --> $DIR/const-fn-not-in-trait.rs:7:5 | LL | const fn g() -> u32 { | ^^^^^ functions in traits cannot be const diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 0446ece421e..726d6e9f74b 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -1,6 +1,6 @@ // Test that we can't call random fns in a const fn or do other bad things. -#![feature(const_fn, const_fn_transmute)] +#![feature(const_fn_transmute)] use std::mem::transmute; diff --git a/src/test/ui/consts/const-fn-type-name-any.rs b/src/test/ui/consts/const-fn-type-name-any.rs index 4ccfb420984..448c4fc0446 100644 --- a/src/test/ui/consts/const-fn-type-name-any.rs +++ b/src/test/ui/consts/const-fn-type-name-any.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(const_fn)] #![feature(const_type_name)] #![allow(dead_code)] diff --git a/src/test/ui/consts/const-fn-type-name.rs b/src/test/ui/consts/const-fn-type-name.rs index 72fac19c191..fd4f60cb889 100644 --- a/src/test/ui/consts/const-fn-type-name.rs +++ b/src/test/ui/consts/const-fn-type-name.rs @@ -1,7 +1,6 @@ // run-pass #![feature(core_intrinsics)] -#![feature(const_fn)] #![feature(const_type_name)] #![allow(dead_code)] diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs index 24df647f05b..03b2f9e3c74 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs @@ -1,6 +1,5 @@ // check-pass #![feature(const_mut_refs)] -#![feature(const_fn)] #![feature(raw_ref_op)] struct Foo { diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs index 166ba20f124..f35f3c5e8ef 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs @@ -1,5 +1,4 @@ #![feature(const_mut_refs)] -#![feature(const_fn)] #![feature(raw_ref_op)] #![feature(const_raw_ptr_deref)] diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr index cbae74cce6f..fb43ce21317 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr @@ -1,11 +1,11 @@ error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/mut_ref_in_final.rs:12:21 + --> $DIR/mut_ref_in_final.rs:11:21 | LL | const B: *mut i32 = &mut 4; | ^^^^^^ error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:18:40 + --> $DIR/mut_ref_in_final.rs:17:40 | LL | const B3: Option<&mut i32> = Some(&mut 42); | ----------^^- @@ -15,7 +15,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:21:42 + --> $DIR/mut_ref_in_final.rs:20:42 | LL | const B4: Option<&mut i32> = helper(&mut 42); | ------------^^- @@ -25,7 +25,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:36:65 + --> $DIR/mut_ref_in_final.rs:35:65 | LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -35,7 +35,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a constant requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:39:67 + --> $DIR/mut_ref_in_final.rs:38:67 | LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- @@ -45,7 +45,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | using this value as a static requires that borrow lasts for `'static` error[E0716]: temporary value dropped while borrowed - --> $DIR/mut_ref_in_final.rs:42:71 + --> $DIR/mut_ref_in_final.rs:41:71 | LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42)); | -------------------------------^^-- diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index 90977efd2b4..638a98130a2 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -1,5 +1,4 @@ #![feature(const_mut_refs)] -#![feature(const_fn)] #![feature(raw_ref_op)] #![feature(const_raw_ptr_deref)] diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr index 45ae055614b..6d3d18f6e68 100644 --- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error - --> $DIR/mut_ref_in_final_dynamic_check.rs:15:10 + --> $DIR/mut_ref_in_final_dynamic_check.rs:14:10 | LL | Some(&mut *(42 as *mut i32)) | ^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:15:10 - | inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:20:29 + | inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:14:10 + | inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29 ... LL | const A: Option<&mut i32> = helper(); | ------------------------------------- @@ -16,7 +16,7 @@ LL | const A: Option<&mut i32> = helper(); = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error: encountered dangling pointer in final constant - --> $DIR/mut_ref_in_final_dynamic_check.rs:27:1 + --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1 | LL | const B: Option<&mut i32> = helper2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const_constructor/const-construct-call.rs b/src/test/ui/consts/const_constructor/const-construct-call.rs index d3e6cf78bc9..cb735d7b305 100644 --- a/src/test/ui/consts/const_constructor/const-construct-call.rs +++ b/src/test/ui/consts/const_constructor/const-construct-call.rs @@ -1,11 +1,7 @@ -// Test that constructors are considered to be const fns with the required feature. +// Test that constructors are considered to be const fns // run-pass -// revisions: min_const_fn const_fn - -#![cfg_attr(const_fn, feature(const_fn))] - // Ctor(..) is transformed to Ctor { 0: ... } in THIR lowering, so directly // calling constructors doesn't require them to be const. diff --git a/src/test/ui/consts/const_constructor/const_constructor_qpath.rs b/src/test/ui/consts/const_constructor/const_constructor_qpath.rs index 18aa3d8e816..7c55f470fdf 100644 --- a/src/test/ui/consts/const_constructor/const_constructor_qpath.rs +++ b/src/test/ui/consts/const_constructor/const_constructor_qpath.rs @@ -1,8 +1,5 @@ -// revisions: min_const_fn const_fn // run-pass -#![cfg_attr(const_fn, feature(const_fn))] - trait ConstDefault { const DEFAULT: Self; } diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index 2fd6e060678..1f68de8eed0 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -1,5 +1,3 @@ -#![feature(const_fn)] - struct S { state: u32, } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 3eac61c0ce6..89073f975e8 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,5 +1,5 @@ error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const_let_assign3.rs:8:18 + --> $DIR/const_let_assign3.rs:6:18 | LL | const fn foo(&mut self, x: u32) { | ^^^^^^^^^ @@ -8,7 +8,7 @@ LL | const fn foo(&mut self, x: u32) { = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:16:5 + --> $DIR/const_let_assign3.rs:14:5 | LL | s.foo(3); | ^ @@ -17,7 +17,7 @@ LL | s.foo(3); = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:22:13 + --> $DIR/const_let_assign3.rs:20:13 | LL | let y = &mut x; | ^^^^^^ diff --git a/src/test/ui/consts/const_unsafe_unreachable.rs b/src/test/ui/consts/const_unsafe_unreachable.rs index cfed6e5deb9..1fec491ca95 100644 --- a/src/test/ui/consts/const_unsafe_unreachable.rs +++ b/src/test/ui/consts/const_unsafe_unreachable.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(const_fn)] #![feature(const_unreachable_unchecked)] const unsafe fn foo(x: bool) -> bool { diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.rs b/src/test/ui/consts/const_unsafe_unreachable_ub.rs index 0bd37876cc3..4ae3a88c451 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.rs +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.rs @@ -1,6 +1,5 @@ // build-fail -#![feature(const_fn)] #![feature(const_unreachable_unchecked)] const unsafe fn foo(x: bool) -> bool { diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr index 3f122b2a859..68d8747d287 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -6,16 +6,16 @@ LL | unsafe { intrinsics::unreachable() } | | | entering unreachable code | inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL - | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18 - | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28 + | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:8:18 + | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:13:28 | - ::: $DIR/const_unsafe_unreachable_ub.rs:14:1 + ::: $DIR/const_unsafe_unreachable_ub.rs:13:1 | LL | const BAR: bool = unsafe { foo(false) }; | ---------------------------------------- | note: the lint level is defined here - --> $DIR/const_unsafe_unreachable_ub.rs:13:8 + --> $DIR/const_unsafe_unreachable_ub.rs:12:8 | LL | #[warn(const_err)] | ^^^^^^^^^ @@ -23,13 +23,13 @@ LL | #[warn(const_err)] = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> error[E0080]: evaluation of constant value failed - --> $DIR/const_unsafe_unreachable_ub.rs:17:14 + --> $DIR/const_unsafe_unreachable_ub.rs:16:14 | LL | assert_eq!(BAR, true); | ^^^ referenced constant has errors error: erroneous constant used - --> $DIR/const_unsafe_unreachable_ub.rs:17:3 + --> $DIR/const_unsafe_unreachable_ub.rs:16:3 | LL | assert_eq!(BAR, true); | ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs index 6dd6192941d..3a4f24bbcc3 100644 --- a/src/test/ui/consts/control-flow/basics.rs +++ b/src/test/ui/consts/control-flow/basics.rs @@ -3,7 +3,6 @@ // run-pass #![feature(const_panic)] -#![feature(const_fn)] const X: u32 = 4; const Y: u32 = 5; diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index 292e2dd167c..35aa587d3d2 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 0f48341ddf3..962a57bb8e9 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -25,7 +25,7 @@ const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required, even with `const_fn` feature gate +// conformity is required const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index d17dcb28115..194f5fc1e54 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 0d0c78b0fc2..20c1169c26e 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength // Test various things that we do not want to promote. #![allow(unconditional_panic, const_err)] -#![feature(const_fn, const_fn_union)] +#![feature(const_fn_union)] use std::cell::Cell; diff --git a/src/test/ui/consts/rustc-args-required-const.rs b/src/test/ui/consts/rustc-args-required-const.rs index 87f979f1b27..0723b66879c 100644 --- a/src/test/ui/consts/rustc-args-required-const.rs +++ b/src/test/ui/consts/rustc-args-required-const.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, const_fn)] +#![feature(rustc_attrs)] #[rustc_args_required_const(0)] fn foo(_a: i32) { diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs index 651462d7ef1..2b970390f03 100644 --- a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -1,6 +1,6 @@ #![stable(feature = "core", since = "1.6.0")] #![feature(staged_api)] -#![feature(const_precise_live_drops, const_fn)] +#![feature(const_precise_live_drops)] enum Either<T, S> { Left(T), diff --git a/src/test/ui/entry-point/auxiliary/main_functions.rs b/src/test/ui/entry-point/auxiliary/main_functions.rs new file mode 100644 index 00000000000..cc7992a42c1 --- /dev/null +++ b/src/test/ui/entry-point/auxiliary/main_functions.rs @@ -0,0 +1 @@ +pub fn boilerplate() {} diff --git a/src/test/ui/entry-point/imported_main_conflict.rs b/src/test/ui/entry-point/imported_main_conflict.rs new file mode 100644 index 00000000000..2839688f342 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_conflict.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] +//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module) +mod m1 { pub(crate) fn main() {} } +mod m2 { pub(crate) fn main() {} } + +use m1::*; +use m2::*; diff --git a/src/test/ui/entry-point/imported_main_conflict.stderr b/src/test/ui/entry-point/imported_main_conflict.stderr new file mode 100644 index 00000000000..36cb98d94e6 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_conflict.stderr @@ -0,0 +1,18 @@ +error[E0659]: `main` is ambiguous (glob import vs glob import in the same module) + | +note: `main` could refer to the function imported here + --> $DIR/imported_main_conflict.rs:6:5 + | +LL | use m1::*; + | ^^^^^ + = help: consider adding an explicit import of `main` to disambiguate +note: `main` could also refer to the function imported here + --> $DIR/imported_main_conflict.rs:7:5 + | +LL | use m2::*; + | ^^^^^ + = help: consider adding an explicit import of `main` to disambiguate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs new file mode 100644 index 00000000000..559f10de109 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs @@ -0,0 +1,12 @@ +#![feature(imported_main)] +#![feature(min_type_alias_impl_trait, impl_trait_in_bindings)] +#![allow(incomplete_features)] +//~^^^ ERROR `main` function not found in crate +pub mod foo { + type MainFn = impl Fn(); + + fn bar() {} + pub const BAR: MainFn = bar; +} + +use foo::BAR as main; diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr new file mode 100644 index 00000000000..9b879fc09f7 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden` + --> $DIR/imported_main_const_fn_item_type_forbidden.rs:1:1 + | +LL | / #![feature(imported_main)] +LL | | #![feature(min_type_alias_impl_trait, impl_trait_in_bindings)] +LL | | #![allow(incomplete_features)] +LL | | +... | +LL | | +LL | | use foo::BAR as main; + | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs` + | | + | non-function item at `crate::main` is found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.rs b/src/test/ui/entry-point/imported_main_const_forbidden.rs new file mode 100644 index 00000000000..989a6c97a80 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_forbidden.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] +//~^ ERROR `main` function not found in crate +pub mod foo { + pub const BAR: usize = 42; +} + +use foo::BAR as main; diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_forbidden.stderr new file mode 100644 index 00000000000..4640513c2bb --- /dev/null +++ b/src/test/ui/entry-point/imported_main_const_forbidden.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `imported_main_const_forbidden` + --> $DIR/imported_main_const_forbidden.rs:1:1 + | +LL | / #![feature(imported_main)] +LL | | +LL | | pub mod foo { +LL | | pub const BAR: usize = 42; +LL | | } +LL | | +LL | | use foo::BAR as main; + | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs` + | | + | non-function item at `crate::main` is found + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.rs b/src/test/ui/entry-point/imported_main_from_extern_crate.rs new file mode 100644 index 00000000000..6bbf67fa540 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_extern_crate.rs @@ -0,0 +1,9 @@ +// build-fail +// aux-build:main_functions.rs + +#![feature(imported_main)] + +extern crate main_functions; +pub use main_functions::boilerplate as main; //~ ERROR entry symbol `main` from foreign crate + +// FIXME: Should be run-pass diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.stderr b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr new file mode 100644 index 00000000000..8792e1e4142 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr @@ -0,0 +1,10 @@ +error: entry symbol `main` from foreign crate is not yet supported. + --> $DIR/imported_main_from_extern_crate.rs:7:9 + | +LL | pub use main_functions::boilerplate as main; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information + +error: aborting due to previous error + diff --git a/src/test/ui/entry-point/imported_main_from_inner_mod.rs b/src/test/ui/entry-point/imported_main_from_inner_mod.rs new file mode 100644 index 00000000000..45750072a7f --- /dev/null +++ b/src/test/ui/entry-point/imported_main_from_inner_mod.rs @@ -0,0 +1,9 @@ +// run-pass +#![feature(imported_main)] + +pub mod foo { + pub fn bar() { + println!("Hello world!"); + } +} +use foo::bar as main; diff --git a/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs new file mode 100644 index 00000000000..4762fbb7c59 --- /dev/null +++ b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(rustc_attrs)] + +#[rustc_main] +fn actual_main() {} + +mod foo { + pub(crate) fn something() {} +} + +use foo::something as main; diff --git a/src/test/ui/error-codes/E0504.stderr b/src/test/ui/error-codes/E0504.stderr index 1f2a0407a39..04811721aa5 100644 --- a/src/test/ui/error-codes/E0504.stderr +++ b/src/test/ui/error-codes/E0504.stderr @@ -7,7 +7,7 @@ LL | LL | let x = move || { | ^^^^^^^ move out of `fancy_num` occurs here LL | println!("child function: {}", fancy_num.num); - | --------- move occurs due to use in closure + | ------------- move occurs due to use in closure ... LL | println!("main function: {}", fancy_ref.num); | ------------- borrow later used here diff --git a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs deleted file mode 100644 index 430a9437cee..00000000000 --- a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Feature gate test for `edition_macro_pats` feature. - -macro_rules! foo { - ($x:pat2015) => {}; //~ERROR `pat2015` and `pat2021` are unstable - ($x:pat2021) => {}; //~ERROR `pat2015` and `pat2021` are unstable -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr deleted file mode 100644 index d25bcaf929b..00000000000 --- a/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: `pat2015` and `pat2021` are unstable. - --> $DIR/feature-gate-edition_macro_pats.rs:4:9 - | -LL | ($x:pat2015) => {}; - | ^^^^^^^ - | - = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information - = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable - -error[E0658]: `pat2015` and `pat2021` are unstable. - --> $DIR/feature-gate-edition_macro_pats.rs:5:9 - | -LL | ($x:pat2021) => {}; - | ^^^^^^^ - | - = note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information - = help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.rs b/src/test/ui/feature-gates/feature-gate-imported_main.rs new file mode 100644 index 00000000000..b351d0d0e9a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-imported_main.rs @@ -0,0 +1,6 @@ +pub mod foo { + pub fn bar() { + println!("Hello world!"); + } +} +use foo::bar as main; //~ ERROR using an imported function as entry point diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.stderr b/src/test/ui/feature-gates/feature-gate-imported_main.stderr new file mode 100644 index 00000000000..3b879fdfc6b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-imported_main.stderr @@ -0,0 +1,12 @@ +error[E0658]: using an imported function as entry point `main` is experimental + --> $DIR/feature-gate-imported_main.rs:6:5 + | +LL | use foo::bar as main; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information + = help: add `#![feature(imported_main)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.rs b/src/test/ui/feature-gates/feature-gate-no_coverage.rs new file mode 100644 index 00000000000..c6b79f9a431 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-no_coverage.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] + +#[no_coverage] +#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]` +fn no_coverage_is_enabled_on_this_function() {} + +#[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature +fn requires_feature_no_coverage() {} diff --git a/src/test/ui/feature-gates/feature-gate-no_coverage.stderr b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr new file mode 100644 index 00000000000..04627be4aaf --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-no_coverage.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[no_coverage]` attribute is an experimental feature + --> $DIR/feature-gate-no_coverage.rs:7:1 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + | + = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information + = help: add `#![feature(no_coverage)]` to the crate attributes to enable + = help: or, alternatively, add `#[feature(no_coverage)]` to the function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr index fd885660d09..68d785efcfe 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr @@ -4,7 +4,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut b = || { | -- generator construction occurs here LL | let a = &mut *x; - | - first borrow occurs due to use of `x` in generator + | -- first borrow occurs due to use of `x` in generator ... LL | println!("{}", x); | ^ second borrow occurs here diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs index 2dbd1840dec..6527eb47504 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(generic_associated_types)] //~^ WARNING: the feature `generic_associated_types` is incomplete #![feature(associated_type_defaults)] @@ -22,6 +20,7 @@ impl<T> Foo for Fooer<T> { } fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} +//~^ the trait `Foo` cannot be made into an object fn main() { diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr index f3769827f04..49dfce8b4bd 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,5 +1,5 @@ warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/gat-in-trait-path.rs:3:12 + --> $DIR/gat-in-trait-path.rs:1:12 | LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information -warning: 1 warning emitted +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/gat-in-trait-path.rs:22:13 + | +LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | + = help: consider moving `A` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/gat-in-trait-path.rs:6:10 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | type A<'a> where Self: 'a; + | ^ ...because it contains the generic associated type `A` + +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs index ff38b3e93eb..6ee865072ae 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.rs +++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(generic_associated_types)] //~^ WARNING: the feature `generic_associated_types` is incomplete @@ -8,5 +6,6 @@ trait X { } fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} +//~^ ERROR the trait `X` cannot be made into an object fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr index 0fbf704df76..65998afa7f9 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,5 +1,5 @@ warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67510-pass.rs:3:12 + --> $DIR/issue-67510-pass.rs:1:12 | LL | #![feature(generic_associated_types)] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,5 +7,21 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information -warning: 1 warning emitted +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-67510-pass.rs:8:19 + | +LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | + = help: consider moving `Y` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-67510-pass.rs:5:10 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | type Y<'a>; + | ^ ...because it contains the generic associated type `Y` + +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 5e73a882986..9643c82db77 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -36,4 +36,6 @@ impl SuperTrait for SuperStruct { fn main() { let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); + //~^ ERROR the trait `SuperTrait` cannot be made into an object + //~^^ ERROR the trait `SuperTrait` cannot be made into an object } diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr index 17661e0d90a..d31560f12f0 100644 --- a/src/test/ui/generic-associated-types/issue-76535.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.stderr @@ -23,6 +23,39 @@ help: use angle brackets to add missing lifetime argument LL | type SubType<'a><'a>: SubTrait; | ^^^^ -error: aborting due to previous error; 1 warning emitted +error[E0038]: the trait `SuperTrait` cannot be made into an object + --> $DIR/issue-76535.rs:38:14 + | +LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | + = help: consider moving `SubType` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-76535.rs:7:10 + | +LL | pub trait SuperTrait { + | ---------- this trait cannot be made into an object... +LL | type SubType<'a>: SubTrait; + | ^^^^^^^ ...because it contains the generic associated type `SubType` + +error[E0038]: the trait `SuperTrait` cannot be made into an object + --> $DIR/issue-76535.rs:38:57 + | +LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | + = help: consider moving `SubType` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-76535.rs:7:10 + | +LL | pub trait SuperTrait { + | ---------- this trait cannot be made into an object... +LL | type SubType<'a>: SubTrait; + | ^^^^^^^ ...because it contains the generic associated type `SubType` + = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>` + = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>` + +error: aborting due to 3 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/issue-78671.rs b/src/test/ui/generic-associated-types/issue-78671.rs index 1b02aac8bcb..4e47d3c6655 100644 --- a/src/test/ui/generic-associated-types/issue-78671.rs +++ b/src/test/ui/generic-associated-types/issue-78671.rs @@ -7,6 +7,7 @@ trait CollectionFamily { } fn floatify() { Box::new(Family) as &dyn CollectionFamily<Member=usize> + //~^ the trait `CollectionFamily` cannot be made into an object } struct Family; diff --git a/src/test/ui/generic-associated-types/issue-78671.stderr b/src/test/ui/generic-associated-types/issue-78671.stderr index 7a9aced5bea..c9febfb59af 100644 --- a/src/test/ui/generic-associated-types/issue-78671.stderr +++ b/src/test/ui/generic-associated-types/issue-78671.stderr @@ -14,6 +14,22 @@ help: use angle brackets to add missing type argument LL | type Member<T><T>; | ^^^ -error: aborting due to previous error +error[E0038]: the trait `CollectionFamily` cannot be made into an object + --> $DIR/issue-78671.rs:9:25 + | +LL | Box::new(Family) as &dyn CollectionFamily<Member=usize> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object + | + = help: consider moving `Member` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-78671.rs:5:10 + | +LL | trait CollectionFamily { + | ---------------- this trait cannot be made into an object... +LL | type Member<T>; + | ^^^^^^ ...because it contains the generic associated type `Member` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index aeb33ca5464..b2ba3c24abb 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -42,5 +42,6 @@ impl<K, V: Default> MapLike<K, V> for Source { fn main() { let m = Box::new(std::collections::BTreeMap::<u8, u8>::new()) as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; - //~^^ ERROR type mismatch resolving + //~^^ the trait `MapLike` cannot be made into an object + //~^^ the trait `MapLike` cannot be made into an object } diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr index a119bff03e2..4973ae19729 100644 --- a/src/test/ui/generic-associated-types/issue-79422.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.stderr @@ -14,17 +14,39 @@ help: use angle brackets to add missing lifetime argument LL | type VRefCont<'a><'a>: RefCont<'a, V>; | ^^^^ -error[E0271]: type mismatch resolving `<BTreeMap<u8, u8> as MapLike<u8, u8>>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)` +error[E0038]: the trait `MapLike` cannot be made into an object + --> $DIR/issue-79422.rs:44:12 + | +LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | + = help: consider moving `VRefCont` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-79422.rs:21:10 + | +LL | trait MapLike<K, V> { + | ------- this trait cannot be made into an object... +LL | type VRefCont<'a>: RefCont<'a, V>; + | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` + +error[E0038]: the trait `MapLike` cannot be made into an object --> $DIR/issue-79422.rs:43:13 | LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | + = help: consider moving `VRefCont` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-79422.rs:21:10 | - = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` - found reference `&'static u8` - = note: required for the cast to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>` +LL | trait MapLike<K, V> { + | ------- this trait cannot be made into an object... +LL | type VRefCont<'a>: RefCont<'a, V>; + | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` + = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>` + = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0271. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/generic-associated-types/trait-objects.rs b/src/test/ui/generic-associated-types/trait-objects.rs new file mode 100644 index 00000000000..997a550b0ef --- /dev/null +++ b/src/test/ui/generic-associated-types/trait-objects.rs @@ -0,0 +1,16 @@ +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +trait StreamingIterator { + type Item<'a> where Self: 'a; + fn size_hint(&self) -> (usize, Option<usize>); + // Uncommenting makes `StreamingIterator` not object safe +// fn next(&mut self) -> Self::Item<'_>; +} + +fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize { + //~^ the trait `StreamingIterator` cannot be made into an object + x.size_hint().0 +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr new file mode 100644 index 00000000000..a8f1768ba26 --- /dev/null +++ b/src/test/ui/generic-associated-types/trait-objects.stderr @@ -0,0 +1,18 @@ +error[E0038]: the trait `StreamingIterator` cannot be made into an object + --> $DIR/trait-objects.rs:11:16 + | +LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | + = help: consider moving `Item` to another trait +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/trait-objects.rs:5:10 + | +LL | trait StreamingIterator { + | ----------------- this trait cannot be made into an object... +LL | type Item<'a> where Self: 'a; + | ^^^^ ...because it contains the generic associated type `Item` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/issues/issue-11192.stderr b/src/test/ui/issues/issue-11192.stderr index dfe7b3f6b5f..2a9d913171c 100644 --- a/src/test/ui/issues/issue-11192.stderr +++ b/src/test/ui/issues/issue-11192.stderr @@ -5,7 +5,7 @@ LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | println!("access {}", foo.x); LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure ... LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr index 188f0b25c30..a1f973e0fdf 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr @@ -5,7 +5,7 @@ LL | match x { | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr index f46a42d7508..4a4a25790b9 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr @@ -5,7 +5,7 @@ LL | match **x { | --- value is immutable in match guard ... LL | (|| { *x = &None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/issues/issue-61623.stderr b/src/test/ui/issues/issue-61623.stderr index 883a1c441d6..901c7598176 100644 --- a/src/test/ui/issues/issue-61623.stderr +++ b/src/test/ui/issues/issue-61623.stderr @@ -10,7 +10,7 @@ error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as imm --> $DIR/issue-61623.rs:6:19 | LL | f2(|| x.0, f1(x.1)) - | -- -- - ^^^ mutable borrow occurs here + | -- -- --- ^^^ mutable borrow occurs here | | | | | | | first borrow occurs due to use of `x` in closure | | immutable borrow occurs here diff --git a/src/test/ui/issues/issue-6801.stderr b/src/test/ui/issues/issue-6801.stderr index dbb8e6530c0..48c6acd1f49 100644 --- a/src/test/ui/issues/issue-6801.stderr +++ b/src/test/ui/issues/issue-6801.stderr @@ -2,7 +2,7 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/issue-6801.rs:19:13 | LL | let sq = || { *x * *x }; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `x` occurs here LL | diff --git a/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs b/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs new file mode 100644 index 00000000000..c496a3556c8 --- /dev/null +++ b/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs @@ -0,0 +1,14 @@ +// build-pass +// compile-flags: --edition 2018 +// compile-flags: --crate-type rlib + +use std::future::Future; + +async fn handle<F>(slf: &F) +where + F: Fn(&()) -> Box<dyn for<'a> Future<Output = ()> + Unpin>, +{ + (slf)(&()).await; +} + +fn main() {} diff --git a/src/test/ui/lifetimes/issue-84604.rs b/src/test/ui/lifetimes/issue-84604.rs new file mode 100644 index 00000000000..df8368da0a0 --- /dev/null +++ b/src/test/ui/lifetimes/issue-84604.rs @@ -0,0 +1,9 @@ +// run-pass +// compile-flags: -Zsymbol-mangling-version=v0 + +pub fn f<T: ?Sized>() {} +pub trait Frob<T: ?Sized> {} +fn main() { + f::<dyn Frob<str>>(); + f::<dyn for<'a> Frob<str>>(); +} diff --git a/src/test/ui/macros/edition-macro-pats.rs b/src/test/ui/macros/edition-macro-pats.rs index 58f92710305..040894712a8 100644 --- a/src/test/ui/macros/edition-macro-pats.rs +++ b/src/test/ui/macros/edition-macro-pats.rs @@ -1,10 +1,9 @@ // run-pass - -#![feature(edition_macro_pats)] +// edition:2021 macro_rules! foo { - (a $x:pat2015) => {}; - (b $x:pat2021) => {}; + (a $x:pat_param) => {}; + (b $x:pat) => {}; } fn main() { diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.fixed b/src/test/ui/macros/macro-or-patterns-back-compat.fixed index f089f0fda4e..f829129d516 100644 --- a/src/test/ui/macros/macro-or-patterns-back-compat.fixed +++ b/src/test/ui/macros/macro-or-patterns-back-compat.fixed @@ -1,15 +1,14 @@ // run-rustfix -#![feature(edition_macro_pats)] #![deny(or_patterns_back_compat)] #![allow(unused_macros)] -macro_rules! foo { ($x:pat2015 | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro -macro_rules! bar { ($($x:pat2015)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro -macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok -macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok -macro_rules! ogg { ($x:pat2015 | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! foo { ($x:pat_param | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! match_any { - ( $expr:expr , $( $( $pat:pat2015 )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + ( $expr:expr , $( $( $pat:pat_param )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro match $expr { $( $( $pat => $expr_arm, )+ diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.rs b/src/test/ui/macros/macro-or-patterns-back-compat.rs index 0252581d5f1..1cdaa1cd631 100644 --- a/src/test/ui/macros/macro-or-patterns-back-compat.rs +++ b/src/test/ui/macros/macro-or-patterns-back-compat.rs @@ -1,13 +1,12 @@ // run-rustfix -#![feature(edition_macro_pats)] #![deny(or_patterns_back_compat)] #![allow(unused_macros)] macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro -macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok -macro_rules! qux { ($x:pat2015 | $y:pat) => {} } // should be ok -macro_rules! ogg { ($x:pat | $y:pat2015) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro macro_rules! match_any { ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro match $expr { diff --git a/src/test/ui/macros/macro-or-patterns-back-compat.stderr b/src/test/ui/macros/macro-or-patterns-back-compat.stderr index d8f19fa5807..01d220dd0b1 100644 --- a/src/test/ui/macros/macro-or-patterns-back-compat.stderr +++ b/src/test/ui/macros/macro-or-patterns-back-compat.stderr @@ -1,32 +1,32 @@ error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:6:21 + --> $DIR/macro-or-patterns-back-compat.rs:5:21 | LL | macro_rules! foo { ($x:pat | $y:pat) => {} } - | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` | note: the lint level is defined here - --> $DIR/macro-or-patterns-back-compat.rs:4:9 + --> $DIR/macro-or-patterns-back-compat.rs:3:9 | LL | #![deny(or_patterns_back_compat)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:7:23 + --> $DIR/macro-or-patterns-back-compat.rs:6:23 | LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } - | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:10:21 + --> $DIR/macro-or-patterns-back-compat.rs:9:21 | -LL | macro_rules! ogg { ($x:pat | $y:pat2015) => {} } - | ^^^^^^ help: use pat2015 to preserve semantics: `$x:pat2015` +LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } + | ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param` error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - --> $DIR/macro-or-patterns-back-compat.rs:12:26 + --> $DIR/macro-or-patterns-back-compat.rs:11:26 | LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { - | ^^^^^^^^ help: use pat2015 to preserve semantics: `$pat:pat2015` + | ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param` error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs index edd3f3e7646..b4be03aaddd 100644 --- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs +++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.rs @@ -1,11 +1,12 @@ -#![feature(edition_macro_pats)] +// edition:2021 + #![allow(unused_macros)] -macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments -macro_rules! baz { ($x:pat2015 | $y:pat2015) => {} } // should be ok -macro_rules! qux { ($x:pat2015 | $y:pat2021) => {} } // should be ok -macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } //~ ERROR `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments +macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments +macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok +macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok +macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments macro_rules! match_any { - ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { //~ ERROR `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments + ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments match $expr { $( $( $pat => $expr_arm, )+ diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr index fe0b40cd86e..8aebe98515f 100644 --- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr +++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr @@ -1,24 +1,24 @@ -error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:3:32 +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28 | -LL | macro_rules! foo { ($x:pat2021 | $y:pat2021) => {} } - | ^ not allowed after `pat2021` fragments +LL | macro_rules! foo { ($x:pat | $y:pat) => {} } + | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `if` or `in` -error: `$x:pat2021` is followed by `|`, which is not allowed for `pat2021` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:6:32 +error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28 | -LL | macro_rules! ogg { ($x:pat2021 | $y:pat2015) => {} } - | ^ not allowed after `pat2021` fragments +LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} } + | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `if` or `in` -error: `$pat:pat2021` may be followed by `|`, which is not allowed for `pat2021` fragments - --> $DIR/macro-pat2021-pattern-followed-by-or.rs:8:40 +error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments + --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35 | -LL | ( $expr:expr , $( $( $pat:pat2021 )|+ => $expr_arm:pat2021 ),+ ) => { - | ^ not allowed after `pat2021` fragments +LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { + | ^ not allowed after `pat` fragments | = note: allowed there are: `=>`, `,`, `=`, `if` or `in` diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index ccc043a1890..8eded8f2857 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -28,7 +28,7 @@ error[E0500]: closure requires unique access to `x` but it is already borrowed LL | let r = &mut x; | ------ borrow occurs here LL | || *x = 2; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | r.use_mut(); @@ -88,7 +88,7 @@ LL | fn closure_unique_capture_moved(x: &mut String) { LL | let r = x; | - value moved here LL | || *x = String::new(); - | ^^ - borrow occurs due to use in closure + | ^^ -- borrow occurs due to use in closure | | | value borrowed here after move diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr index a3bcbbab3ec..fffbee4d4a8 100644 --- a/src/test/ui/nll/closure-borrow-spans.stderr +++ b/src/test/ui/nll/closure-borrow-spans.stderr @@ -110,7 +110,7 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:65:13 | LL | let f = || *x = 0; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `x` occurs here LL | let y = x; @@ -122,7 +122,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u --> $DIR/closure-borrow-spans.rs:71:13 | LL | let f = || *x = 0; - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | let y = &x; @@ -134,7 +134,7 @@ error[E0501]: cannot borrow `x` as mutable because previous closure requires uni --> $DIR/closure-borrow-spans.rs:77:13 | LL | let f = || *x = 0; - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | let y = &mut x; @@ -143,10 +143,10 @@ LL | f.use_ref(); | - first borrow later used here error[E0597]: `x` does not live long enough - --> $DIR/closure-borrow-spans.rs:86:17 + --> $DIR/closure-borrow-spans.rs:86:16 | LL | f = || *x = 0; - | -- ^ borrowed value does not live long enough + | -- ^^ borrowed value does not live long enough | | | value captured here LL | } @@ -158,7 +158,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/closure-borrow-spans.rs:93:5 | LL | let f = || *x = 0; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `*x` occurs here LL | *x = 1; diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index dd5f32ef4f5..a59e553315a 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -133,9 +133,9 @@ LL | fn_ref(|| { LL | | || | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure + | |_________--_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:51:9 @@ -150,9 +150,9 @@ LL | fn_ref(move || { LL | | || | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure + | |_________--_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error: aborting due to 12 previous errors diff --git a/src/test/ui/nll/closure-use-spans.stderr b/src/test/ui/nll/closure-use-spans.stderr index ec7e0f30855..87162904ba6 100644 --- a/src/test/ui/nll/closure-use-spans.stderr +++ b/src/test/ui/nll/closure-use-spans.stderr @@ -6,7 +6,7 @@ LL | let y = &x; LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y; - | - borrow later captured here by closure + | -- borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:11:5 @@ -16,7 +16,7 @@ LL | let y = &mut x; LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y = 1; - | - borrow later captured here by closure + | -- borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:17:5 diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 2f134f83ced..2be0460df1f 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -21,7 +21,7 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/closures-in-loops.rs:20:16 | LL | v.push(|| *x = String::new()); - | ^^ - borrows occur due to use of `x` in closure + | ^^ -- borrows occur due to use of `x` in closure | | | closures are constructed here in different iterations of loop diff --git a/src/test/ui/nll/issue-51268.stderr b/src/test/ui/nll/issue-51268.stderr index e6dadc9f6ce..0483bda6379 100644 --- a/src/test/ui/nll/issue-51268.stderr +++ b/src/test/ui/nll/issue-51268.stderr @@ -8,7 +8,7 @@ LL | self.thing.bar(|| { | | LL | | LL | | &self.number; - | | ---- first borrow occurs due to use of `self` in closure + | | ----------- first borrow occurs due to use of `self` in closure LL | | }); | |__________^ mutable borrow occurs here diff --git a/src/test/ui/or-patterns/macro-pat.rs b/src/test/ui/or-patterns/macro-pat.rs index 8c581b630de..20d8f84c247 100644 --- a/src/test/ui/or-patterns/macro-pat.rs +++ b/src/test/ui/or-patterns/macro-pat.rs @@ -1,10 +1,9 @@ // run-pass // edition:2021 -// ignore-test -// FIXME(mark-i-m): enable this test again when 2021 machinery is available use Foo::*; +#[allow(dead_code)] #[derive(Eq, PartialEq, Debug)] enum Foo { A(u64), diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs index f0ce7597aee..c0d148d9204 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs @@ -1,9 +1,7 @@ // Tests that :pat in macros in edition 2021 allows top-level or-patterns. // run-pass -// ignore-test // edition:2021 -// FIXME(mark-i-m): unignore when 2021 machinery is in place. macro_rules! accept_pat { ($p:pat) => {}; diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs index a59cacb8bde..039878af56e 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -3,6 +3,5 @@ // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. #![feature(custom_inner_attributes)] -//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601] #![issue_59191::no_main] //~^ ERROR expected crate top-level item to be a module after macro expansion, found a function diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 5995a4891f3..579041c5259 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,19 +1,10 @@ error: expected crate top-level item to be a module after macro expansion, found a function - --> $DIR/issue-59191-replace-root-with-fn.rs:7:1 + --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 | LL | #![issue_59191::no_main] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn` - --> $DIR/issue-59191-replace-root-with-fn.rs:5:1 - | -LL | / #![feature(custom_inner_attributes)] -LL | | -LL | | #![issue_59191::no_main] - | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr index 4c271a3916a..c16a6f8585b 100644 --- a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr +++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr @@ -23,7 +23,7 @@ error[E0597]: `self` does not live long enough LL | let _f = || { | -- value captured here LL | let p: &'static mut usize = &mut self.food; - | ------------------ ^^^^ borrowed value does not live long enough + | ------------------ ^^^^^^^^^ borrowed value does not live long enough | | | type annotation requires that `self` is borrowed for `'static` ... diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs index 194929fa287..5a66af1d29e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs @@ -5,7 +5,6 @@ #![allow(incomplete_features)] #![feature(const_trait_impl)] -#![feature(const_fn)] struct NonConstAdd(i32); diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs index 8e6ef12810c..fa5570d5454 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -1,6 +1,5 @@ #![allow(incomplete_features)] #![feature(const_trait_impl)] -#![feature(const_fn)] pub trait Plus { fn plus(self, rhs: Self) -> Self; diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr index 0c320d54c76..d3f350e1b61 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -1,5 +1,5 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/call-const-trait-method-fail.rs:26:5 + --> $DIR/call-const-trait-method-fail.rs:25:5 | LL | a.plus(b) | ^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs index 6a2112ea554..ec6f45f956d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs @@ -2,7 +2,6 @@ #![allow(incomplete_features)] #![feature(const_trait_impl)] -#![feature(const_fn)] struct Int(i32); diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs index 6d4bfe722de..dc4d5561d47 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs @@ -1,4 +1,4 @@ -#![feature(const_fn)] +#![feature(const_fn_trait_bound)] #![feature(const_trait_impl)] #![feature(const_trait_bound_opt_out)] #![allow(incomplete_features)] diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs index f0e32142221..1fc2c4fe445 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(const_fn)] +#![feature(const_fn_trait_bound)] #![feature(const_trait_impl)] #![feature(const_trait_bound_opt_out)] #![allow(incomplete_features)] diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index 2c8f6354dc6..9aefe6380cb 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -1,7 +1,6 @@ // FIXME(jschievink): this is not rejected correctly (only when the non-const impl is actually used) // ignore-test -#![feature(const_fn)] #![feature(const_trait_impl)] #![allow(incomplete_features)] diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index 3506237d1f1..4452ad7ea23 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -4,7 +4,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] #![feature(rustc_attrs)] -#![feature(const_fn)] +#![feature(const_fn_trait_bound)] trait T { const CONST: i32; diff --git a/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs b/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs index 655d4d7400b..ad14dd62bc7 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs @@ -1,6 +1,6 @@ // Regression test for #69615. -#![feature(const_trait_impl, const_fn)] +#![feature(const_trait_impl)] #![allow(incomplete_features)] pub trait MyTrait { diff --git a/src/test/ui/typeck/issue-75883.rs b/src/test/ui/typeck/issue-75883.rs new file mode 100644 index 00000000000..3a59ca049ba --- /dev/null +++ b/src/test/ui/typeck/issue-75883.rs @@ -0,0 +1,22 @@ +// Regression test for #75883. + +pub struct UI {} + +impl UI { + pub fn run() -> Result<_> { + //~^ ERROR: this enum takes 2 type arguments but only 1 type argument was supplied + //~| ERROR: the type placeholder `_` is not allowed within types on item signatures + let mut ui = UI {}; + ui.interact(); + + unimplemented!(); + } + + pub fn interact(&mut self) -> Result<_> { + //~^ ERROR: this enum takes 2 type arguments but only 1 type argument was supplied + //~| ERROR: the type placeholder `_` is not allowed within types on item signatures + unimplemented!(); + } +} + +fn main() {} diff --git a/src/test/ui/typeck/issue-75883.stderr b/src/test/ui/typeck/issue-75883.stderr new file mode 100644 index 00000000000..a6b2eb8f972 --- /dev/null +++ b/src/test/ui/typeck/issue-75883.stderr @@ -0,0 +1,52 @@ +error[E0107]: this enum takes 2 type arguments but only 1 type argument was supplied + --> $DIR/issue-75883.rs:6:21 + | +LL | pub fn run() -> Result<_> { + | ^^^^^^ - supplied 1 type argument + | | + | expected 2 type arguments + | +note: enum defined here, with 2 type parameters: `T`, `E` + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | pub enum Result<T, E> { + | ^^^^^^ - - +help: add missing type argument + | +LL | pub fn run() -> Result<_, E> { + | ^^^ + +error[E0107]: this enum takes 2 type arguments but only 1 type argument was supplied + --> $DIR/issue-75883.rs:15:35 + | +LL | pub fn interact(&mut self) -> Result<_> { + | ^^^^^^ - supplied 1 type argument + | | + | expected 2 type arguments + | +note: enum defined here, with 2 type parameters: `T`, `E` + --> $SRC_DIR/core/src/result.rs:LL:COL + | +LL | pub enum Result<T, E> { + | ^^^^^^ - - +help: add missing type argument + | +LL | pub fn interact(&mut self) -> Result<_, E> { + | ^^^ + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-75883.rs:15:42 + | +LL | pub fn interact(&mut self) -> Result<_> { + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-75883.rs:6:28 + | +LL | pub fn run() -> Result<_> { + | ^ not allowed in type signatures + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0121. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/typeck/issue-80779.rs b/src/test/ui/typeck/issue-80779.rs new file mode 100644 index 00000000000..6791976196f --- /dev/null +++ b/src/test/ui/typeck/issue-80779.rs @@ -0,0 +1,13 @@ +// Regression test for #80779. + +pub struct T<'a>(&'a str); + +pub fn f<'a>(val: T<'a>) -> _ { + //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures + g(val) +} + +pub fn g(_: T<'static>) -> _ {} +//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures + +fn main() {} diff --git a/src/test/ui/typeck/issue-80779.stderr b/src/test/ui/typeck/issue-80779.stderr new file mode 100644 index 00000000000..aca494520f8 --- /dev/null +++ b/src/test/ui/typeck/issue-80779.stderr @@ -0,0 +1,21 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80779.rs:10:28 + | +LL | pub fn g(_: T<'static>) -> _ {} + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `()` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-80779.rs:5:29 + | +LL | pub fn f<'a>(val: T<'a>) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with the correct return type: `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 4369396ce7d270972955d876eaa4954bea56bcd +Subproject f3e13226d6d17a2bc5f325303494b43a45f53b7 diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index d951ca0e630..4676c2affad 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -44,7 +44,7 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str create_test(&lint).context("Unable to create a test for the new lint") } -fn create_lint(lint: &LintData) -> io::Result<()> { +fn create_lint(lint: &LintData<'_>) -> io::Result<()> { let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), @@ -68,7 +68,7 @@ fn create_lint(lint: &LintData) -> io::Result<()> { write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) } -fn create_test(lint: &LintData) -> io::Result<()> { +fn create_test(lint: &LintData<'_>) -> io::Result<()> { fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { let mut path = location.into().join(case); fs::create_dir(&path)?; diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 757d7669bd8..8c74284fa46 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -17,7 +17,7 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] // warn on rustc internal lints -#![deny(rustc::internal)] +#![warn(rustc::internal)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cd85c487798..e81a92eb74c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -678,7 +678,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool { cx.tcx .entry_fn(LOCAL_CRATE) - .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id()) + .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id) } /// Returns `true` if the expression is in the program's `#[panic_handler]`. diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index fa0c5f01430..750a23e8c98 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -4,7 +4,7 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] // warn on rustc internal lints -#![deny(rustc::internal)] +#![warn(rustc::internal)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index f4d354f0bf9..e1110721f6e 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -83,14 +83,7 @@ fn default_config() -> compiletest::Config { third_party_crates(), )); - config.build_base = if cargo::is_rustc_test_suite() { - // This make the stderr files go to clippy OUT_DIR on rustc repo build dir - let mut path = PathBuf::from(env!("OUT_DIR")); - path.push("test_build_base"); - path - } else { - host_lib().join("test_build_base") - }; + config.build_base = host_lib().join("test_build_base"); config.rustc_path = clippy_driver_path(); config } diff --git a/src/tools/miri b/src/tools/miri -Subproject 5faf5a5ca059f6eb067fc86e47480f5668ac6e8 +Subproject 41f3fe64317a6ef144d2ac33e4e5870d894d603 diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject 7570212a544b8e973a7d57be3657aae6465028a +Subproject 617535393bb5ccc7adf0bac8a3b9a9c306454e7 diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index cb84fd8be6f..b14b5aeb572 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -423,6 +423,15 @@ fn map_lib_features( continue; }}; } + + lazy_static::lazy_static! { + static ref COMMENT_LINE: Regex = Regex::new(r"^\s*//").unwrap(); + } + // exclude commented out lines + if COMMENT_LINE.is_match(line) { + continue; + } + if let Some((ref name, ref mut f)) = becoming_feature { if f.tracking_issue.is_none() { f.tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none); diff --git a/src/version b/src/version index 3f4830156cb..b7921ae87bc 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.53.0 +1.54.0 |
