From 77503578e1e727228ce47dd7847302936cf80a23 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 30 May 2020 18:48:54 +0900 Subject: [PATCH 01/19] Return early to avoid ICE --- .../traits/error_reporting/suggestions.rs | 6 ++++++ src/librustc_trait_selection/traits/mod.rs | 7 ------- src/test/ui/suggestions/issue-72766.rs | 20 +++++++++++++++++++ src/test/ui/suggestions/issue-72766.stderr | 15 ++++++++++++++ .../clippy/clippy_lints/src/utils/mod.rs | 5 +++++ 5 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/suggestions/issue-72766.rs create mode 100644 src/test/ui/suggestions/issue-72766.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 31992f298080e..3174f43c65792 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1909,6 +1909,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + // Do not check on infer_types to avoid panic in evaluate_obligation. + if self_ty.has_infer_types() { + return; + } + let self_ty = self.tcx.erase_regions(&self_ty); + let impls_future = self.tcx.type_implements_trait(( future_trait, self_ty, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index b45de72ab0262..958ba69a8262c 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -540,13 +540,6 @@ fn type_implements_trait<'tcx>( trait_def_id, ty, params, param_env ); - // Do not check on infer_types to avoid panic in evaluate_obligation. - if ty.has_infer_types() { - return false; - } - - let ty = tcx.erase_regions(&ty); - let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; let obligation = Obligation { diff --git a/src/test/ui/suggestions/issue-72766.rs b/src/test/ui/suggestions/issue-72766.rs new file mode 100644 index 0000000000000..0448f0719589d --- /dev/null +++ b/src/test/ui/suggestions/issue-72766.rs @@ -0,0 +1,20 @@ +// edition:2018 +// compile-flags: -Cincremental=tmp/issue-72766 + +pub struct SadGirl; + +impl SadGirl { + pub async fn call(&self) -> Result<(), ()> { + Ok(()) + } +} + +async fn async_main() -> Result<(), ()> { + // should be `.call().await?` + SadGirl {}.call()?; //~ ERROR: the `?` operator can only be applied to values + Ok(()) +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr new file mode 100644 index 0000000000000..4290f3b4bf1aa --- /dev/null +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -0,0 +1,15 @@ +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-72766.rs:14:5 + | +LL | SadGirl {}.call()?; + | ^^^^^^^^^^^^^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `SadGirl {}.call().await?` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 6c1488664bf00..6dd8fef7e82da 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -323,6 +323,11 @@ pub fn implements_trait<'a, 'tcx>( trait_id: DefId, ty_params: &[GenericArg<'tcx>], ) -> bool { + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + let ty = cx.tcx.erase_regions(&ty); let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } From 2d4b09aa1961e3ce494cfc3ad84f7a366db0db1f Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 6 May 2016 09:32:10 -0400 Subject: [PATCH 02/19] [AVR] Add AVR platform support --- config.toml.example | 2 +- src/bootstrap/native.rs | 2 +- src/librustc_ast_passes/feature_gate.rs | 8 +++++ src/librustc_codegen_llvm/abi.rs | 2 ++ src/librustc_codegen_llvm/llvm/ffi.rs | 2 ++ src/librustc_feature/active.rs | 3 ++ src/librustc_llvm/build.rs | 1 + src/librustc_llvm/lib.rs | 8 +++++ src/librustc_middle/ty/layout.rs | 2 ++ src/librustc_span/symbol.rs | 1 + src/librustc_target/abi/call/avr.rs | 33 +++++++++++++++++++ src/librustc_target/abi/call/mod.rs | 4 +++ src/librustc_target/spec/abi.rs | 8 +++++ .../spec/avr_unknown_unknown.rs | 17 ++++++++++ src/librustc_target/spec/mod.rs | 3 ++ src/librustc_target/spec/none_base.rs | 30 +++++++++++++++++ src/libstd/env.rs | 6 ++++ src/rustllvm/PassWrapper.cpp | 7 ++++ .../feature-gate-abi-avr-interrupt.rs | 9 +++++ .../feature-gate-abi-avr-interrupt.stderr | 11 +++++++ src/tools/compiletest/src/util.rs | 1 + 21 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 src/librustc_target/abi/call/avr.rs create mode 100644 src/librustc_target/spec/avr_unknown_unknown.rs create mode 100644 src/librustc_target/spec/none_base.rs create mode 100644 src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs create mode 100644 src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr diff --git a/config.toml.example b/config.toml.example index cf8fe4e082ac3..d995554913f84 100644 --- a/config.toml.example +++ b/config.toml.example @@ -69,7 +69,7 @@ # the same format as above, but since these targets are experimental, they are # not built by default and the experimental Rust compilation targets that depend # on them will not work unless the user opts in to building them. -#experimental-targets = "" +#experimental-targets = "AVR" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5b6e953484369..252a6316e574b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -144,7 +144,7 @@ impl Step for Llvm { let llvm_exp_targets = match builder.config.llvm_experimental_targets { Some(ref s) => s, - None => "", + None => "AVR", }; let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index ffd741a7b37b0..a7b0c9cf81be6 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -121,6 +121,14 @@ impl<'a> PostExpansionVisitor<'a> { "amdgpu-kernel ABI is experimental and subject to change" ); } + "avr-interrupt" | "avr-non-blocking-interrupt" => { + gate_feature_post!( + &self, + abi_avr_interrupt, + span, + "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change" + ); + } "efiapi" => { gate_feature_post!( &self, diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 8e9c5f25ccb71..099c402703d09 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -375,6 +375,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { match self.conv { Conv::C | Conv::Rust => llvm::CCallConv, Conv::AmdGpuKernel => llvm::AmdGpuKernel, + Conv::AvrInterrupt => llvm::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::ArmAapcs => llvm::ArmAapcsCallConv, Conv::Msp430Intr => llvm::Msp430Intr, Conv::PtxKernel => llvm::PtxKernel, diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 3fb7ff3cb8dfd..597261f61a497 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -45,6 +45,8 @@ pub enum CallConv { X86_64_Win64 = 79, X86_VectorCall = 80, X86_Intr = 83, + AvrNonBlockingInterrupt = 84, + AvrInterrupt = 85, AmdGpuKernel = 91, } diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index fd35cb6c3f785..fc64727ad6272 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -347,6 +347,9 @@ declare_features! ( /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), + /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. + (active, abi_avr_interrupt, "1.41.0", None, None), + /// Allows declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index e97fa4345fe7c..ada48bc147e47 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -78,6 +78,7 @@ fn main() { "arm", "aarch64", "amdgpu", + "avr", "mips", "powerpc", "systemz", diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index eca1808de3f90..79e1a6cc5dcdb 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -76,6 +76,14 @@ pub fn initialize_available_targets() { LLVMInitializeAMDGPUAsmPrinter, LLVMInitializeAMDGPUAsmParser ); + init_target!( + llvm_component = "avr", + LLVMInitializeAVRTargetInfo, + LLVMInitializeAVRTarget, + LLVMInitializeAVRTargetMC, + LLVMInitializeAVRAsmPrinter, + LLVMInitializeAVRAsmParser + ); init_target!( llvm_component = "mips", LLVMInitializeMipsTargetInfo, diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 5566e187c0c5c..7edc11833e293 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -2530,6 +2530,8 @@ where Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, AmdGpuKernel => Conv::AmdGpuKernel, + AvrInterrupt => Conv::AvrInterrupt, + AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, // These API constants ought to be more specific... Cdecl => Conv::C, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 0f2d52c2264fd..7a936eb432f31 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -120,6 +120,7 @@ symbols! { abi_unadjusted, abi_vectorcall, abi_x86_interrupt, + abi_avr_interrupt, abort, aborts, address, diff --git a/src/librustc_target/abi/call/avr.rs b/src/librustc_target/abi/call/avr.rs new file mode 100644 index 0000000000000..f681302bc0319 --- /dev/null +++ b/src/librustc_target/abi/call/avr.rs @@ -0,0 +1,33 @@ +#![allow(non_upper_case_globals)] + +use crate::abi::call::{ArgAbi, FnAbi}; + +fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { + if ret.layout.is_aggregate() { + ret.make_indirect(); + } else { + ret.extend_integer_width_to(8); // Is 8 correct? + } +} + +fn classify_arg_ty(arg: &mut ArgAbi<'_, Ty>) { + if arg.layout.is_aggregate() { + arg.make_indirect(); + } else { + arg.extend_integer_width_to(8); + } +} + +pub fn compute_abi_info(fty: &mut FnAbi<'_, Ty>) { + if !fty.ret.is_ignore() { + classify_ret_ty(&mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + + classify_arg_ty(arg); + } +} diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 0303312d057fe..8f7e2bba5aa6d 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -5,6 +5,7 @@ use crate::spec::{self, HasTargetSpec}; mod aarch64; mod amdgpu; mod arm; +mod avr; mod hexagon; mod mips; mod mips64; @@ -525,6 +526,8 @@ pub enum Conv { X86_64Win64, AmdGpuKernel, + AvrInterrupt, + AvrNonBlockingInterrupt, } /// Metadata describing how the arguments to a native function @@ -580,6 +583,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "aarch64" => aarch64::compute_abi_info(cx, self), "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), + "avr" => avr::compute_abi_info(self), "mips" => mips::compute_abi_info(cx, self), "mips64" => mips64::compute_abi_info(cx, self), "powerpc" => powerpc::compute_abi_info(self), diff --git a/src/librustc_target/spec/abi.rs b/src/librustc_target/spec/abi.rs index 1736063cc5f7c..b7b544cea0c3c 100644 --- a/src/librustc_target/spec/abi.rs +++ b/src/librustc_target/spec/abi.rs @@ -25,6 +25,8 @@ pub enum Abi { X86Interrupt, AmdGpuKernel, EfiApi, + AvrInterrupt, + AvrNonBlockingInterrupt, // Multiplatform / generic ABIs Rust, @@ -63,6 +65,12 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false }, AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false }, AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false }, + AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false }, + AbiData { + abi: Abi::AvrNonBlockingInterrupt, + name: "avr-non-blocking-interrupt", + generic: false, + }, // Cross-platform ABIs AbiData { abi: Abi::Rust, name: "Rust", generic: true }, AbiData { abi: Abi::C, name: "C", generic: true }, diff --git a/src/librustc_target/spec/avr_unknown_unknown.rs b/src/librustc_target/spec/avr_unknown_unknown.rs new file mode 100644 index 0000000000000..c951c980e2a02 --- /dev/null +++ b/src/librustc_target/spec/avr_unknown_unknown.rs @@ -0,0 +1,17 @@ +use crate::spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "avr-unknown-unknown".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "16".to_string(), + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), + arch: "avr".to_string(), + linker_flavor: LinkerFlavor::Gcc, + target_os: "unknown".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + target_c_int_width: 16.to_string(), + options: super::none_base::opts(), + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index c9558879a1c6e..b6ada8e7aaf9a 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -65,6 +65,7 @@ mod linux_kernel_base; mod linux_musl_base; mod msvc_base; mod netbsd_base; +mod none_base; mod openbsd_base; mod redox_base; mod riscv_base; @@ -579,6 +580,8 @@ supported_targets! { ("aarch64-fuchsia", aarch64_fuchsia), ("x86_64-fuchsia", x86_64_fuchsia), + ("avr-unknown-unknown", avr_unknown_unknown), + ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), ("aarch64-unknown-redox", aarch64_unknown_redox), diff --git a/src/librustc_target/spec/none_base.rs b/src/librustc_target/spec/none_base.rs new file mode 100644 index 0000000000000..5402ea074fae1 --- /dev/null +++ b/src/librustc_target/spec/none_base.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; +use std::default::Default; + +pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + + args.insert( + LinkerFlavor::Gcc, + vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + ], + ); + + TargetOptions { + dynamic_linking: false, + executables: true, + linker_is_gnu: true, + has_rpath: false, + pre_link_args: args, + position_independent_executables: false, + ..Default::default() + } +} diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 97c20ca9459ef..0354f7850f5bf 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -874,6 +874,7 @@ pub mod consts { /// - x86_64 /// - arm /// - aarch64 + /// - avr /// - mips /// - mips64 /// - powerpc @@ -986,6 +987,11 @@ mod arch { pub const ARCH: &str = "aarch64"; } +#[cfg(target_arch = "avr")] +mod arch { + pub const ARCH: &'static str = "avr"; +} + #[cfg(target_arch = "mips")] mod arch { pub const ARCH: &str = "mips"; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 02dcfb8e82952..3d252fe70afeb 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -203,6 +203,12 @@ void LLVMRustAddLastExtensionPasses( #define SUBTARGET_AARCH64 #endif +#ifdef LLVM_COMPONENT_AVR +#define SUBTARGET_AVR SUBTARGET(AVR) +#else +#define SUBTARGET_AVR +#endif + #ifdef LLVM_COMPONENT_MIPS #define SUBTARGET_MIPS SUBTARGET(Mips) #else @@ -249,6 +255,7 @@ void LLVMRustAddLastExtensionPasses( SUBTARGET_X86 \ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ + SUBTARGET_AVR \ SUBTARGET_MIPS \ SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ diff --git a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs new file mode 100644 index 0000000000000..0d7df8182c458 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs @@ -0,0 +1,9 @@ +// Test that the AVR interrupt ABI cannot be used when avr_interrupt +// feature gate is not used. + +extern "avr-interrupt" fn foo() {} +//~^ ERROR avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr new file mode 100644 index 0000000000000..023b6121784f7 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr @@ -0,0 +1,11 @@ +error[E0658]: avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change + --> $DIR/feature-gate-abi-avr-interrupt.rs:14:1 + | +LL | extern "avr-interrupt" fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(abi_avr_interrupt)] 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/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index c61bee0f8d9ea..e1c3042edb80f 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -47,6 +47,7 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("armv7", "arm"), ("armv7s", "arm"), ("asmjs", "asmjs"), + ("avr", "avr"), ("hexagon", "hexagon"), ("i386", "x86"), ("i586", "x86"), From a42bf5a551c095ee16ddc9a5cf56937b47881a8e Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 9 Jun 2019 01:57:40 +1200 Subject: [PATCH 03/19] [AVR] Fix debug printing of function pointers This commit fixes debug printing of function pointers on AVR. AVR does not support `addrspacecast` instructions, and so this patch modifies libcore so that a `ptrtoint` IR instruction is used and the address space cast is avoided. --- src/libcore/ptr/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index ecc70adda4111..777284ca5c096 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1345,14 +1345,24 @@ macro_rules! fnptr_impls_safety_abi { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Pointer for $FnTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) + // HACK: The intermediate cast as usize is required for AVR + // so that the address space of the source function pointer + // is preserved in the final function pointer. + // + // https://github.com/avr-rust/rust/issues/143 + fmt::Pointer::fmt(&(*self as usize as *const ()), f) } } #[stable(feature = "fnptr_impls", since = "1.4.0")] impl fmt::Debug for $FnTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) + // HACK: The intermediate cast as usize is required for AVR + // so that the address space of the source function pointer + // is preserved in the final function pointer. + // + // https://github.com/avr-rust/rust/issues/143 + fmt::Pointer::fmt(&(*self as usize as *const ()), f) } } } From 208adf9f805bafb3aaa62b1588c998448a171b48 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Tue, 3 Mar 2020 19:36:26 +1300 Subject: [PATCH 04/19] [AVR] Add required references for AVR to the parser test suites --- src/test/ui/codemap_tests/unicode.stderr | 2 +- src/test/ui/parser/issue-8537.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 01d54ac8cc8a2..82968da7e8755 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/parser/issue-8537.stderr b/src/test/ui/parser/issue-8537.stderr index a0793d94653da..0213b368769f1 100644 --- a/src/test/ui/parser/issue-8537.stderr +++ b/src/test/ui/parser/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error From 94a94d7db02b5c2e99b4b7c9c2caea756d191de4 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Tue, 3 Mar 2020 21:05:17 +1300 Subject: [PATCH 05/19] [AVR] Raise and link to a tracking issue for the `avr-interrupt` calling convention Also fix the order of the feature gate to fix the tidy errors. --- src/librustc_feature/active.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index fc64727ad6272..b4935236b6a97 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -347,9 +347,6 @@ declare_features! ( /// Allows `extern "msp430-interrupt" fn()`. (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. - (active, abi_avr_interrupt, "1.41.0", None, None), - /// Allows declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), @@ -577,6 +574,9 @@ declare_features! ( /// No longer treat an unsafe function as an unsafe block. (active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None), + /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. + (active, abi_avr_interrupt, "1.45.0", Some(69664), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- From 717268c5e4ee9df6b04ea486c7d3788a4aec6a67 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 4 Mar 2020 17:07:45 +1300 Subject: [PATCH 06/19] [AVR] Re-bless the UI tests Patch generated with `./x.py test --stage 1 src/test/ui/feature-gates --bless`. --- .../ui/feature-gates/feature-gate-abi-avr-interrupt.stderr | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr index 023b6121784f7..be7040e1491fe 100644 --- a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr @@ -1,10 +1,11 @@ error[E0658]: avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change - --> $DIR/feature-gate-abi-avr-interrupt.rs:14:1 + --> $DIR/feature-gate-abi-avr-interrupt.rs:4:8 | LL | extern "avr-interrupt" fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | - = help: add #![feature(abi_avr_interrupt)] to the crate attributes to enable + = note: see issue #69664 for more information + = help: add `#![feature(abi_avr_interrupt)]` to the crate attributes to enable error: aborting due to previous error From 737c342c06520e7ebd133f64fe3a0b71892ef68c Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 5 Mar 2020 13:18:51 +1300 Subject: [PATCH 07/19] [AVR] Update the compiletest library to recognize AVR as a 16-bit target --- src/tools/compiletest/src/util.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index e1c3042edb80f..ca36a15ffc7de 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -115,6 +115,8 @@ pub fn matches_env(triple: &str, name: &str) -> bool { pub fn get_pointer_width(triple: &str) -> &'static str { if (triple.contains("64") && !triple.ends_with("gnux32")) || triple.starts_with("s390x") { "64bit" + } else if triple.starts_with("avr") { + "16bit" } else { "32bit" } From 94ece5e80c345588243fac0b175ddabf5590d28a Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 5 Mar 2020 13:22:13 +1300 Subject: [PATCH 08/19] [AVR] Re-bless the 'test/ui/symbol-names' tests Adding a new ABI changes the hashes of all previous ABIs. Fix suggested by @shepmaster in https://github.com/rust-lang/rust/pull/69478#issuecomment-594568660. --- src/test/ui/symbol-names/basic.legacy.stderr | 4 ++-- src/test/ui/symbol-names/impl1.legacy.stderr | 8 ++++---- src/test/ui/symbol-names/impl1.rs | 2 +- src/test/ui/symbol-names/issue-60925.legacy.stderr | 4 ++-- src/tools/compiletest/src/header/tests.rs | 6 ++++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index 895ff5ae54fde..45c051e91afbc 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h81759b0695851718E) +error: symbol-name(_ZN5basic4main17h7bbff4a01206d8c2E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h81759b0695851718) +error: demangling(basic::main::h7bbff4a01206d8c2) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 33cacaf212855..42995da3e3e31 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5impl13foo3Foo3bar17h92cf46db76791039E) +error: symbol-name(_ZN5impl13foo3Foo3bar17hf9d7d0e61617a4b8E) --> $DIR/impl1.rs:16:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::foo::Foo::bar::h92cf46db76791039) +error: demangling(impl1::foo::Foo::bar::hf9d7d0e61617a4b8) --> $DIR/impl1.rs:16:9 | LL | #[rustc_symbol_name] @@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h90c4a800b1aa0df0E) +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h6435cd4293f0ad82E) --> $DIR/impl1.rs:34:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::bar::::baz::h90c4a800b1aa0df0) +error: demangling(impl1::bar::::baz::h6435cd4293f0ad82) --> $DIR/impl1.rs:34:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index cdcf89e4e614e..5bb0d9ee3c454 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -4,7 +4,7 @@ //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 //[legacy]normalize-stderr-32bit: "h5ef5dfc14aeecbfc" -> "SYMBOL_HASH" -//[legacy]normalize-stderr-64bit: "h9e54d216f70fcbc5" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "hd9e82dc29c74d643" -> "SYMBOL_HASH" #![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 0e3a34adbc7cf..0855422e6af02 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hc86312d25b60f6eeE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h91943b9c102410e4E) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::hc86312d25b60f6ee) +error: demangling(issue_60925::foo::Foo::foo::h91943b9c102410e4) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 31d991e0c2f87..f7355433463d6 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -27,6 +27,12 @@ fn test_parse_normalization_string() { let first = parse_normalization_string(&mut s); assert_eq!(first, Some("something (32 bits)".to_owned())); assert_eq!(s, " -> \"something ($WORD bits)."); + + // Nothing to normalize (No quotes, 16-bit) + let mut s = "normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, None); + assert_eq!(s, r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."#); } fn config() -> Config { From cd890ff451da461adb0173b17224c3ba5fd4ce51 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 1 Apr 2020 20:39:09 +1300 Subject: [PATCH 09/19] [AVR] Remove AVR-specific logic from libstd It is not possible to compile libstd for AVR anyway. --- src/libstd/env.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 0354f7850f5bf..97c20ca9459ef 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -874,7 +874,6 @@ pub mod consts { /// - x86_64 /// - arm /// - aarch64 - /// - avr /// - mips /// - mips64 /// - powerpc @@ -987,11 +986,6 @@ mod arch { pub const ARCH: &str = "aarch64"; } -#[cfg(target_arch = "avr")] -mod arch { - pub const ARCH: &'static str = "avr"; -} - #[cfg(target_arch = "mips")] mod arch { pub const ARCH: &str = "mips"; From 6260bc4edba5bad589eb88c6521ad6f5514b0d94 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 1 Apr 2020 20:51:05 +1300 Subject: [PATCH 10/19] [AVR] Rename the 'none_base' target spec module to 'freestanding_base' --- src/librustc_target/spec/avr_unknown_unknown.rs | 2 +- src/librustc_target/spec/{none_base.rs => freestanding_base.rs} | 0 src/librustc_target/spec/mod.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/librustc_target/spec/{none_base.rs => freestanding_base.rs} (100%) diff --git a/src/librustc_target/spec/avr_unknown_unknown.rs b/src/librustc_target/spec/avr_unknown_unknown.rs index c951c980e2a02..f90a8def0aa2f 100644 --- a/src/librustc_target/spec/avr_unknown_unknown.rs +++ b/src/librustc_target/spec/avr_unknown_unknown.rs @@ -12,6 +12,6 @@ pub fn target() -> TargetResult { target_env: "".to_string(), target_vendor: "unknown".to_string(), target_c_int_width: 16.to_string(), - options: super::none_base::opts(), + options: super::freestanding_base::opts(), }) } diff --git a/src/librustc_target/spec/none_base.rs b/src/librustc_target/spec/freestanding_base.rs similarity index 100% rename from src/librustc_target/spec/none_base.rs rename to src/librustc_target/spec/freestanding_base.rs diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index b6ada8e7aaf9a..636e7f2d26bc5 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -54,6 +54,7 @@ mod arm_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; +mod freestanding_base; mod fuchsia_base; mod haiku_base; mod hermit_base; @@ -65,7 +66,6 @@ mod linux_kernel_base; mod linux_musl_base; mod msvc_base; mod netbsd_base; -mod none_base; mod openbsd_base; mod redox_base; mod riscv_base; From 491bf8c22c03cc1a4c1274b84fc7337200f595fe Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 May 2020 16:36:23 +1200 Subject: [PATCH 11/19] [AVR] Update ABI type classification logic to match the the AVR-Clang ABI This patch brings the AVR calling convention argument classification logic in line with AVR Clang's behaviour. AVR-Clang currently uses the `clang::DefaultABIInfo` ABI implementation. This calling convention promotes all aggregates to indirect, no matter their size. It is also unnecessary to perform any integer width extension for AVR as the minimum argument size matches the minimum describable size of abi::Primitive::Int - 8 bits. At some point in the future, an AVR-GCC compatible argument classification implementation should be adopted in both Clang and Rust. --- src/librustc_target/abi/call/avr.rs | 36 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/librustc_target/abi/call/avr.rs b/src/librustc_target/abi/call/avr.rs index f681302bc0319..c1f7a1e3af586 100644 --- a/src/librustc_target/abi/call/avr.rs +++ b/src/librustc_target/abi/call/avr.rs @@ -1,20 +1,46 @@ -#![allow(non_upper_case_globals)] +//! LLVM-frontend specific AVR calling convention implementation. +//! +//! # Current calling convention ABI +//! +//! Inherited from Clang's `clang::DefaultABIInfo` implementation - self described +//! as +//! +//! > the default implementation for ABI specific details. This implementation +//! > provides information which results in +//! > self-consistent and sensible LLVM IR generation, but does not +//! > conform to any particular ABI. +//! > +//! > - Doxygen Doxumentation of `clang::DefaultABIInfo` +//! +//! This calling convention may not match AVR-GCC in all cases. +//! +//! In the future, an AVR-GCC compatible argument classification ABI should be +//! adopted in both Rust and Clang. +//! +//! *NOTE*: Currently, this module implements the same calling convention +//! that clang with AVR currently does - the default, simple, unspecialized +//! ABI implementation available to all targets. This ABI is not +//! binary-compatible with AVR-GCC. Once LLVM [PR46140](https://bugs.llvm.org/show_bug.cgi?id=46140) +//! is completed, this module should be updated to match so that both Clang +//! and Rust emit code to the same AVR-GCC compatible ABI. +//! +//! In particular, both Clang and Rust may not have the same semantics +//! when promoting arguments to indirect references as AVR-GCC. It is important +//! to note that the core AVR ABI implementation within LLVM itself is ABI +//! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount +//! of compiler frontend specific calling convention logic implemented here. use crate::abi::call::{ArgAbi, FnAbi}; fn classify_ret_ty(ret: &mut ArgAbi<'_, Ty>) { if ret.layout.is_aggregate() { ret.make_indirect(); - } else { - ret.extend_integer_width_to(8); // Is 8 correct? } } fn classify_arg_ty(arg: &mut ArgAbi<'_, Ty>) { if arg.layout.is_aggregate() { arg.make_indirect(); - } else { - arg.extend_integer_width_to(8); } } From f6dfbbb90af21fcea91ab85e98dbd478f37d5592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 09:24:59 -0700 Subject: [PATCH 12/19] On recursive ADT, provide indirection structured suggestion --- src/librustc_errors/diagnostic.rs | 23 +++++++ src/librustc_errors/diagnostic_builder.rs | 13 ++++ src/librustc_middle/ty/util.rs | 10 ++- .../traits/error_reporting/mod.rs | 66 +++++++++++++++---- src/librustc_typeck/check/mod.rs | 6 +- .../infinite-tag-type-recursion.stderr | 9 ++- src/test/ui/issues/issue-17431-1.stderr | 11 +++- src/test/ui/issues/issue-17431-2.stderr | 22 +++++-- src/test/ui/issues/issue-17431-3.stderr | 11 +++- src/test/ui/issues/issue-17431-4.stderr | 11 +++- src/test/ui/issues/issue-17431-5.stderr | 11 +++- src/test/ui/issues/issue-17431-6.stderr | 9 ++- src/test/ui/issues/issue-17431-7.stderr | 9 ++- src/test/ui/issues/issue-2718-a.stderr | 9 ++- src/test/ui/issues/issue-3008-1.stderr | 9 ++- src/test/ui/issues/issue-3008-2.stderr | 11 +++- src/test/ui/issues/issue-3008-3.stderr | 9 ++- src/test/ui/issues/issue-32326.stderr | 5 +- src/test/ui/issues/issue-3779.stderr | 11 +++- src/test/ui/issues/issue-57271.stderr | 18 ++++- src/test/ui/recursion/recursive-enum.stderr | 9 ++- src/test/ui/sized-cycle-note.stderr | 22 +++++-- src/test/ui/span/E0072.stderr | 11 +++- src/test/ui/span/multiline-span-E0072.stderr | 11 +++- src/test/ui/span/recursive-type-field.stderr | 23 ++++--- src/test/ui/type/type-recursive.stderr | 11 +++- .../ui/union/union-nonrepresentable.stderr | 11 +++- 27 files changed, 315 insertions(+), 66 deletions(-) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index cff83c3d5cda2..acaa26c6ad2fc 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -296,6 +296,29 @@ impl Diagnostic { self } + pub fn multipart_suggestions( + &mut self, + msg: &str, + suggestions: Vec>, + applicability: Applicability, + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: suggestions + .into_iter() + .map(|suggestion| Substitution { + parts: suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), + }) + .collect(), + msg: msg.to_owned(), + style: SuggestionStyle::ShowCode, + applicability, + }); + self + } + /// Prints out a message with for a multipart suggestion without showing the suggested code. /// /// This is intended to be used for suggestions that are obvious in what the changes need to diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 2dbd9f4e52fad..22bf8fe34aa15 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -260,6 +260,19 @@ impl<'a> DiagnosticBuilder<'a> { self } + pub fn multipart_suggestions( + &mut self, + msg: &str, + suggestions: Vec>, + applicability: Applicability, + ) -> &mut Self { + if !self.0.allow_suggestions { + return self; + } + self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability); + self + } + pub fn tool_only_multipart_suggestion( &mut self, msg: &str, diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs index c2b794ca4bdd9..5cdfa6f90128d 100644 --- a/src/librustc_middle/ty/util.rs +++ b/src/librustc_middle/ty/util.rs @@ -827,7 +827,15 @@ impl<'tcx> ty::TyS<'tcx> { // Find non representable fields with their spans fold_repr(def.all_fields().map(|field| { let ty = field.ty(tcx, substs); - let span = tcx.hir().span_if_local(field.did).unwrap_or(sp); + let span = match field + .did + .as_local() + .map(|id| tcx.hir().as_local_hir_id(id)) + .and_then(|id| tcx.hir().find(id)) + { + Some(hir::Node::Field(field)) => field.ty.span, + _ => sp, + }; match is_type_structurally_recursive( tcx, span, diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f8b33b782c017..f14e2a9a06720 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1725,24 +1725,62 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { pub fn recursive_type_with_infinite_size_error( tcx: TyCtxt<'tcx>, type_def_id: DefId, -) -> DiagnosticBuilder<'tcx> { + spans: Vec, +) { assert!(type_def_id.is_local()); let span = tcx.hir().span_if_local(type_def_id).unwrap(); let span = tcx.sess.source_map().guess_head_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0072, - "recursive type `{}` has infinite size", - tcx.def_path_str(type_def_id) - ); + let path = tcx.def_path_str(type_def_id); + let mut err = + struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path); err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.def_path_str(type_def_id) - )); - err + for &span in &spans { + err.span_label(span, "recursive without indirection"); + } + let short_msg = format!("insert some indirection to make `{}` representable", path); + let msg = format!( + "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable", + path, + ); + match &spans[..] { + [span] => { + err.multipart_suggestions( + &short_msg, + vec![ + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + vec![ + (span.shrink_to_lo(), "Rc<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + vec![(span.shrink_to_lo(), "&".to_string())], + ], + Applicability::HasPlaceholders, + ); + } + _ if spans.len() <= 4 => { + err.multipart_suggestion( + &msg, + spans + .iter() + .flat_map(|&span| { + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ] + .into_iter() + }) + .collect(), + Applicability::HasPlaceholders, + ); + } + _ => { + err.help(&msg); + } + } + err.emit(); } /// Summarizes information diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8fa65a135ac2..284b7aa42c2ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2374,11 +2374,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bo // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive(spans) => { - let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id()); - for span in spans { - err.span_label(span, "recursive without indirection"); - } - err.emit(); + recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); return false; } Representability::Representable | Representability::ContainsRecursive => (), diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 8f6529db0bec5..868d57fec4cd2 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -6,7 +6,14 @@ LL | enum MList { Cons(isize, MList), Nil } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable +help: insert some indirection to make `MList` representable + | +LL | enum MList { Cons(isize, Box), Nil } + | ^^^^ ^ +LL | enum MList { Cons(isize, Rc), Nil } + | ^^^ ^ +LL | enum MList { Cons(isize, &MList), Nil } + | ^ error[E0391]: cycle detected when processing `MList` --> $DIR/infinite-tag-type-recursion.rs:1:1 diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr index eb5a1366e8953..8d44154650e04 100644 --- a/src/test/ui/issues/issue-17431-1.stderr +++ b/src/test/ui/issues/issue-17431-1.stderr @@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-1.rs:1:1 | LL | struct Foo { foo: Option> } - | ^^^^^^^^^^ ------------------------ recursive without indirection + | ^^^^^^^^^^ ------------------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | struct Foo { foo: Box>> } + | ^^^^ ^ +LL | struct Foo { foo: Rc>> } + | ^^^ ^ +LL | struct Foo { foo: &Option> } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr index 3a7b0e9ce7997..b06184e84da28 100644 --- a/src/test/ui/issues/issue-17431-2.stderr +++ b/src/test/ui/issues/issue-17431-2.stderr @@ -2,21 +2,35 @@ error[E0072]: recursive type `Baz` has infinite size --> $DIR/issue-17431-2.rs:1:1 | LL | struct Baz { q: Option } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable +help: insert some indirection to make `Baz` representable + | +LL | struct Baz { q: Box> } + | ^^^^ ^ +LL | struct Baz { q: Rc> } + | ^^^ ^ +LL | struct Baz { q: &Option } + | ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-2.rs:4:1 | LL | struct Foo { q: Option } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | struct Foo { q: Box> } + | ^^^^ ^ +LL | struct Foo { q: Rc> } + | ^^^ ^ +LL | struct Foo { q: &Option } + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17431-3.stderr b/src/test/ui/issues/issue-17431-3.stderr index 675a2e2714209..f32bd70fd6d94 100644 --- a/src/test/ui/issues/issue-17431-3.stderr +++ b/src/test/ui/issues/issue-17431-3.stderr @@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-3.rs:3:1 | LL | struct Foo { foo: Mutex> } - | ^^^^^^^^^^ ----------------------- recursive without indirection + | ^^^^^^^^^^ ------------------ recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | struct Foo { foo: Box>> } + | ^^^^ ^ +LL | struct Foo { foo: Rc>> } + | ^^^ ^ +LL | struct Foo { foo: &Mutex> } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr index aff9071095ca0..372c5e975c844 100644 --- a/src/test/ui/issues/issue-17431-4.stderr +++ b/src/test/ui/issues/issue-17431-4.stderr @@ -2,11 +2,18 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-4.rs:3:1 | LL | struct Foo { foo: Option>>, marker: marker::PhantomData } - | ^^^^^^^^^^^^^ --------------------------- recursive without indirection + | ^^^^^^^^^^^^^ ---------------------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | struct Foo { foo: Box>>>, marker: marker::PhantomData } + | ^^^^ ^ +LL | struct Foo { foo: Rc>>>, marker: marker::PhantomData } + | ^^^ ^ +LL | struct Foo { foo: &Option>>, marker: marker::PhantomData } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-5.stderr b/src/test/ui/issues/issue-17431-5.stderr index 537f9f34f55ca..01b850ac33694 100644 --- a/src/test/ui/issues/issue-17431-5.stderr +++ b/src/test/ui/issues/issue-17431-5.stderr @@ -2,11 +2,18 @@ error[E0072]: recursive type `Bar` has infinite size --> $DIR/issue-17431-5.rs:5:1 | LL | struct Bar { x: Bar , marker: marker::PhantomData } - | ^^^^^^^^^^^^^ ----------- recursive without indirection + | ^^^^^^^^^^^^^ -------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection to make `Bar` representable + | +LL | struct Bar { x: Box> , marker: marker::PhantomData } + | ^^^^ ^ +LL | struct Bar { x: Rc> , marker: marker::PhantomData } + | ^^^ ^ +LL | struct Bar { x: &Bar , marker: marker::PhantomData } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-6.stderr b/src/test/ui/issues/issue-17431-6.stderr index cb2dab9501488..ce6c2db07fb6d 100644 --- a/src/test/ui/issues/issue-17431-6.stderr +++ b/src/test/ui/issues/issue-17431-6.stderr @@ -6,7 +6,14 @@ LL | enum Foo { X(Mutex>) } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | enum Foo { X(Box>>) } + | ^^^^ ^ +LL | enum Foo { X(Rc>>) } + | ^^^ ^ +LL | enum Foo { X(&Mutex>) } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr index de70851da4b5f..4fb563ba502f2 100644 --- a/src/test/ui/issues/issue-17431-7.stderr +++ b/src/test/ui/issues/issue-17431-7.stderr @@ -6,7 +6,14 @@ LL | enum Foo { Voo(Option>) } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | enum Foo { Voo(Box>>) } + | ^^^^ ^ +LL | enum Foo { Voo(Rc>>) } + | ^^^ ^ +LL | enum Foo { Voo(&Option>) } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index 0f52c79192843..48b7a61e059ea 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -7,7 +7,14 @@ LL | pub struct Pong(SendPacket); | | recursive without indirection | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `pingpong::Pong` representable +help: insert some indirection to make `pingpong::Pong` representable + | +LL | pub struct Pong(Box>); + | ^^^^ ^ +LL | pub struct Pong(Rc>); + | ^^^ ^ +LL | pub struct Pong(&SendPacket); + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-1.stderr b/src/test/ui/issues/issue-3008-1.stderr index f12274134ee05..d1173a4b3334c 100644 --- a/src/test/ui/issues/issue-3008-1.stderr +++ b/src/test/ui/issues/issue-3008-1.stderr @@ -7,7 +7,14 @@ LL | enum Bar { LL | BarSome(Bar) | --- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection to make `Bar` representable + | +LL | BarSome(Box) + | ^^^^ ^ +LL | BarSome(Rc) + | ^^^ ^ +LL | BarSome(&Bar) + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-2.stderr b/src/test/ui/issues/issue-3008-2.stderr index acc15f4b57c73..4fd60639b21a8 100644 --- a/src/test/ui/issues/issue-3008-2.stderr +++ b/src/test/ui/issues/issue-3008-2.stderr @@ -2,11 +2,18 @@ error[E0072]: recursive type `Bar` has infinite size --> $DIR/issue-3008-2.rs:2:1 | LL | struct Bar { x: Bar } - | ^^^^^^^^^^ ------ recursive without indirection + | ^^^^^^^^^^ --- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection to make `Bar` representable + | +LL | struct Bar { x: Box } + | ^^^^ ^ +LL | struct Bar { x: Rc } + | ^^^ ^ +LL | struct Bar { x: &Bar } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-3.stderr b/src/test/ui/issues/issue-3008-3.stderr index d08a3d9708db3..e6efad9188300 100644 --- a/src/test/ui/issues/issue-3008-3.stderr +++ b/src/test/ui/issues/issue-3008-3.stderr @@ -6,7 +6,14 @@ LL | enum E2 { V2(E2, marker::PhantomData), } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `E2` representable +help: insert some indirection to make `E2` representable + | +LL | enum E2 { V2(Box>, marker::PhantomData), } + | ^^^^ ^ +LL | enum E2 { V2(Rc>, marker::PhantomData), } + | ^^^ ^ +LL | enum E2 { V2(&E2, marker::PhantomData), } + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32326.stderr b/src/test/ui/issues/issue-32326.stderr index 5967627e51a4b..0f3d3690b732e 100644 --- a/src/test/ui/issues/issue-32326.stderr +++ b/src/test/ui/issues/issue-32326.stderr @@ -8,7 +8,10 @@ LL | Plus(Expr, Expr), | | | recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Expr` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Expr` representable + | +LL | Plus(Box, Box), + | ^^^^ ^ ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr index ba1e842c610ba..9b50ddec12a44 100644 --- a/src/test/ui/issues/issue-3779.stderr +++ b/src/test/ui/issues/issue-3779.stderr @@ -5,9 +5,16 @@ LL | struct S { | ^^^^^^^^ recursive type has infinite size LL | LL | element: Option - | ------------------ recursive without indirection + | --------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable +help: insert some indirection to make `S` representable + | +LL | element: Box> + | ^^^^ ^ +LL | element: Rc> + | ^^^ ^ +LL | element: &Option + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr index 4f164624f7a53..a6fe83a9b5636 100644 --- a/src/test/ui/issues/issue-57271.stderr +++ b/src/test/ui/issues/issue-57271.stderr @@ -7,7 +7,14 @@ LL | Class(ClassTypeSignature), LL | Array(TypeSignature), | ------------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ObjectType` representable +help: insert some indirection to make `ObjectType` representable + | +LL | Array(Box), + | ^^^^ ^ +LL | Array(Rc), + | ^^^ ^ +LL | Array(&TypeSignature), + | ^ error[E0072]: recursive type `TypeSignature` has infinite size --> $DIR/issue-57271.rs:19:1 @@ -18,7 +25,14 @@ LL | Base(BaseType), LL | Object(ObjectType), | ---------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `TypeSignature` representable +help: insert some indirection to make `TypeSignature` representable + | +LL | Object(Box), + | ^^^^ ^ +LL | Object(Rc), + | ^^^ ^ +LL | Object(&ObjectType), + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/recursion/recursive-enum.stderr b/src/test/ui/recursion/recursive-enum.stderr index e4674b57a6d21..c68badd458bce 100644 --- a/src/test/ui/recursion/recursive-enum.stderr +++ b/src/test/ui/recursion/recursive-enum.stderr @@ -6,7 +6,14 @@ LL | enum List { Cons(T, List), Nil } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable +help: insert some indirection to make `List` representable + | +LL | enum List { Cons(T, Box>), Nil } + | ^^^^ ^ +LL | enum List { Cons(T, Rc>), Nil } + | ^^^ ^ +LL | enum List { Cons(T, &List), Nil } + | ^ error: aborting due to previous error diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr index 95bdc34942645..99d8cfd0a05c9 100644 --- a/src/test/ui/sized-cycle-note.stderr +++ b/src/test/ui/sized-cycle-note.stderr @@ -2,21 +2,35 @@ error[E0072]: recursive type `Baz` has infinite size --> $DIR/sized-cycle-note.rs:9:1 | LL | struct Baz { q: Option } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable +help: insert some indirection to make `Baz` representable + | +LL | struct Baz { q: Box> } + | ^^^^ ^ +LL | struct Baz { q: Rc> } + | ^^^ ^ +LL | struct Baz { q: &Option } + | ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/sized-cycle-note.rs:11:1 | LL | struct Foo { q: Option } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | struct Foo { q: Box> } + | ^^^^ ^ +LL | struct Foo { q: Rc> } + | ^^^ ^ +LL | struct Foo { q: &Option } + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index d4a5e7400d2a4..855e4facb7b8c 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -5,9 +5,16 @@ LL | struct ListNode { | ^^^^^^^^^^^^^^^ recursive type has infinite size LL | head: u8, LL | tail: Option, - | ---------------------- recursive without indirection + | ---------------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable +help: insert some indirection to make `ListNode` representable + | +LL | tail: Box>, + | ^^^^ ^ +LL | tail: Rc>, + | ^^^ ^ +LL | tail: &Option, + | ^ error: aborting due to previous error diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index dd322fe833b49..260c2157e96b7 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -6,11 +6,18 @@ LL | | ListNode LL | | { LL | | head: u8, LL | | tail: Option, - | | ---------------------- recursive without indirection + | | ---------------- recursive without indirection LL | | } | |_^ recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable +help: insert some indirection to make `ListNode` representable + | +LL | tail: Box>, + | ^^^^ ^ +LL | tail: Rc>, + | ^^^ ^ +LL | tail: &Option, + | ^ error: aborting due to previous error diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index d240872647e50..c1a3270d0a567 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -4,9 +4,16 @@ error[E0072]: recursive type `Foo` has infinite size LL | struct Foo<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | bar: Bar<'a>, - | ------------ recursive without indirection + | ------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection to make `Foo` representable + | +LL | bar: Box>, + | ^^^^ ^ +LL | bar: Rc>, + | ^^^ ^ +LL | bar: &Bar<'a>, + | ^ error[E0072]: recursive type `Bar` has infinite size --> $DIR/recursive-type-field.rs:8:1 @@ -14,18 +21,18 @@ error[E0072]: recursive type `Bar` has infinite size LL | struct Bar<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | y: (Foo<'a>, Foo<'a>), - | --------------------- recursive without indirection + | ------------------ recursive without indirection LL | z: Option>, - | ------------------ recursive without indirection + | --------------- recursive without indirection ... LL | d: [Bar<'a>; 1], - | --------------- recursive without indirection + | ------------ recursive without indirection LL | e: Foo<'a>, - | ---------- recursive without indirection + | ------- recursive without indirection LL | x: Bar<'a>, - | ---------- recursive without indirection + | ------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable + = help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index 72bf372e561d6..b98a6eac49e04 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -5,9 +5,16 @@ LL | struct T1 { | ^^^^^^^^^ recursive type has infinite size LL | foo: isize, LL | foolish: T1 - | ----------- recursive without indirection + | -- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `T1` representable +help: insert some indirection to make `T1` representable + | +LL | foolish: Box + | ^^^^ ^ +LL | foolish: Rc + | ^^^ ^ +LL | foolish: &T1 + | ^ error: aborting due to previous error diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 746c1033ea348..70863a549ad25 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -5,9 +5,16 @@ LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, LL | b: U, - | ---- recursive without indirection + | - recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `U` representable +help: insert some indirection to make `U` representable + | +LL | b: Box, + | ^^^^ ^ +LL | b: Rc, + | ^^^ ^ +LL | b: &U, + | ^ error: aborting due to previous error From c209040b54f22f8aed75433212431e99e6f8cd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 30 May 2020 19:58:49 -0700 Subject: [PATCH 13/19] review comments: only suggest one substitution --- .../traits/error_reporting/mod.rs | 49 ++++++------------- .../infinite-tag-type-recursion.stderr | 6 +-- src/test/ui/issues/issue-17431-1.stderr | 6 +-- src/test/ui/issues/issue-17431-2.stderr | 12 +---- src/test/ui/issues/issue-17431-3.stderr | 6 +-- src/test/ui/issues/issue-17431-4.stderr | 6 +-- src/test/ui/issues/issue-17431-5.stderr | 6 +-- src/test/ui/issues/issue-17431-6.stderr | 6 +-- src/test/ui/issues/issue-17431-7.stderr | 6 +-- src/test/ui/issues/issue-2718-a.stderr | 6 +-- src/test/ui/issues/issue-3008-1.stderr | 6 +-- src/test/ui/issues/issue-3008-2.stderr | 6 +-- src/test/ui/issues/issue-3008-3.stderr | 6 +-- src/test/ui/issues/issue-3779.stderr | 6 +-- src/test/ui/issues/issue-57271.stderr | 12 +---- src/test/ui/recursion/recursive-enum.stderr | 6 +-- src/test/ui/sized-cycle-note.stderr | 12 +---- src/test/ui/span/E0072.stderr | 6 +-- src/test/ui/span/multiline-span-E0072.stderr | 6 +-- src/test/ui/span/recursive-type-field.stderr | 6 +-- src/test/ui/type/type-recursive.stderr | 6 +-- .../ui/union/union-nonrepresentable.stderr | 6 +-- 22 files changed, 38 insertions(+), 155 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f14e2a9a06720..2ce2059d68019 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1737,48 +1737,27 @@ pub fn recursive_type_with_infinite_size_error( for &span in &spans { err.span_label(span, "recursive without indirection"); } - let short_msg = format!("insert some indirection to make `{}` representable", path); let msg = format!( "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable", path, ); - match &spans[..] { - [span] => { - err.multipart_suggestions( - &short_msg, - vec![ + if spans.len() <= 4 { + err.multipart_suggestion( + &msg, + spans + .iter() + .flat_map(|&span| { vec![ (span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string()), - ], - vec![ - (span.shrink_to_lo(), "Rc<".to_string()), - (span.shrink_to_hi(), ">".to_string()), - ], - vec![(span.shrink_to_lo(), "&".to_string())], - ], - Applicability::HasPlaceholders, - ); - } - _ if spans.len() <= 4 => { - err.multipart_suggestion( - &msg, - spans - .iter() - .flat_map(|&span| { - vec![ - (span.shrink_to_lo(), "Box<".to_string()), - (span.shrink_to_hi(), ">".to_string()), - ] - .into_iter() - }) - .collect(), - Applicability::HasPlaceholders, - ); - } - _ => { - err.help(&msg); - } + ] + .into_iter() + }) + .collect(), + Applicability::HasPlaceholders, + ); + } else { + err.help(&msg); } err.emit(); } diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 868d57fec4cd2..97d0588c18d17 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -6,14 +6,10 @@ LL | enum MList { Cons(isize, MList), Nil } | | | recursive type has infinite size | -help: insert some indirection to make `MList` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` representable | LL | enum MList { Cons(isize, Box), Nil } | ^^^^ ^ -LL | enum MList { Cons(isize, Rc), Nil } - | ^^^ ^ -LL | enum MList { Cons(isize, &MList), Nil } - | ^ error[E0391]: cycle detected when processing `MList` --> $DIR/infinite-tag-type-recursion.rs:1:1 diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr index 8d44154650e04..58d087ca1998b 100644 --- a/src/test/ui/issues/issue-17431-1.stderr +++ b/src/test/ui/issues/issue-17431-1.stderr @@ -6,14 +6,10 @@ LL | struct Foo { foo: Option> } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | struct Foo { foo: Box>> } | ^^^^ ^ -LL | struct Foo { foo: Rc>> } - | ^^^ ^ -LL | struct Foo { foo: &Option> } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr index b06184e84da28..eba4bf6d1d5ea 100644 --- a/src/test/ui/issues/issue-17431-2.stderr +++ b/src/test/ui/issues/issue-17431-2.stderr @@ -6,14 +6,10 @@ LL | struct Baz { q: Option } | | | recursive type has infinite size | -help: insert some indirection to make `Baz` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable | LL | struct Baz { q: Box> } | ^^^^ ^ -LL | struct Baz { q: Rc> } - | ^^^ ^ -LL | struct Baz { q: &Option } - | ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-2.rs:4:1 @@ -23,14 +19,10 @@ LL | struct Foo { q: Option } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | struct Foo { q: Box> } | ^^^^ ^ -LL | struct Foo { q: Rc> } - | ^^^ ^ -LL | struct Foo { q: &Option } - | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17431-3.stderr b/src/test/ui/issues/issue-17431-3.stderr index f32bd70fd6d94..f6b15d0528ae8 100644 --- a/src/test/ui/issues/issue-17431-3.stderr +++ b/src/test/ui/issues/issue-17431-3.stderr @@ -6,14 +6,10 @@ LL | struct Foo { foo: Mutex> } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | struct Foo { foo: Box>> } | ^^^^ ^ -LL | struct Foo { foo: Rc>> } - | ^^^ ^ -LL | struct Foo { foo: &Mutex> } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr index 372c5e975c844..aa709e1ad5183 100644 --- a/src/test/ui/issues/issue-17431-4.stderr +++ b/src/test/ui/issues/issue-17431-4.stderr @@ -6,14 +6,10 @@ LL | struct Foo { foo: Option>>, marker: marker::PhantomData | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | struct Foo { foo: Box>>>, marker: marker::PhantomData } | ^^^^ ^ -LL | struct Foo { foo: Rc>>>, marker: marker::PhantomData } - | ^^^ ^ -LL | struct Foo { foo: &Option>>, marker: marker::PhantomData } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-5.stderr b/src/test/ui/issues/issue-17431-5.stderr index 01b850ac33694..1558cffb036b3 100644 --- a/src/test/ui/issues/issue-17431-5.stderr +++ b/src/test/ui/issues/issue-17431-5.stderr @@ -6,14 +6,10 @@ LL | struct Bar { x: Bar , marker: marker::PhantomData } | | | recursive type has infinite size | -help: insert some indirection to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable | LL | struct Bar { x: Box> , marker: marker::PhantomData } | ^^^^ ^ -LL | struct Bar { x: Rc> , marker: marker::PhantomData } - | ^^^ ^ -LL | struct Bar { x: &Bar , marker: marker::PhantomData } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-6.stderr b/src/test/ui/issues/issue-17431-6.stderr index ce6c2db07fb6d..f2aa2a79c8200 100644 --- a/src/test/ui/issues/issue-17431-6.stderr +++ b/src/test/ui/issues/issue-17431-6.stderr @@ -6,14 +6,10 @@ LL | enum Foo { X(Mutex>) } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | enum Foo { X(Box>>) } | ^^^^ ^ -LL | enum Foo { X(Rc>>) } - | ^^^ ^ -LL | enum Foo { X(&Mutex>) } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr index 4fb563ba502f2..684c3089e85ec 100644 --- a/src/test/ui/issues/issue-17431-7.stderr +++ b/src/test/ui/issues/issue-17431-7.stderr @@ -6,14 +6,10 @@ LL | enum Foo { Voo(Option>) } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | enum Foo { Voo(Box>>) } | ^^^^ ^ -LL | enum Foo { Voo(Rc>>) } - | ^^^ ^ -LL | enum Foo { Voo(&Option>) } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index 48b7a61e059ea..d152ffde4e57d 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -7,14 +7,10 @@ LL | pub struct Pong(SendPacket); | | recursive without indirection | recursive type has infinite size | -help: insert some indirection to make `pingpong::Pong` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `pingpong::Pong` representable | LL | pub struct Pong(Box>); | ^^^^ ^ -LL | pub struct Pong(Rc>); - | ^^^ ^ -LL | pub struct Pong(&SendPacket); - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-1.stderr b/src/test/ui/issues/issue-3008-1.stderr index d1173a4b3334c..87ee36df21696 100644 --- a/src/test/ui/issues/issue-3008-1.stderr +++ b/src/test/ui/issues/issue-3008-1.stderr @@ -7,14 +7,10 @@ LL | enum Bar { LL | BarSome(Bar) | --- recursive without indirection | -help: insert some indirection to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable | LL | BarSome(Box) | ^^^^ ^ -LL | BarSome(Rc) - | ^^^ ^ -LL | BarSome(&Bar) - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-2.stderr b/src/test/ui/issues/issue-3008-2.stderr index 4fd60639b21a8..369a19d37e6f6 100644 --- a/src/test/ui/issues/issue-3008-2.stderr +++ b/src/test/ui/issues/issue-3008-2.stderr @@ -6,14 +6,10 @@ LL | struct Bar { x: Bar } | | | recursive type has infinite size | -help: insert some indirection to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable | LL | struct Bar { x: Box } | ^^^^ ^ -LL | struct Bar { x: Rc } - | ^^^ ^ -LL | struct Bar { x: &Bar } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-3.stderr b/src/test/ui/issues/issue-3008-3.stderr index e6efad9188300..0b162eff94a7c 100644 --- a/src/test/ui/issues/issue-3008-3.stderr +++ b/src/test/ui/issues/issue-3008-3.stderr @@ -6,14 +6,10 @@ LL | enum E2 { V2(E2, marker::PhantomData), } | | | recursive type has infinite size | -help: insert some indirection to make `E2` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E2` representable | LL | enum E2 { V2(Box>, marker::PhantomData), } | ^^^^ ^ -LL | enum E2 { V2(Rc>, marker::PhantomData), } - | ^^^ ^ -LL | enum E2 { V2(&E2, marker::PhantomData), } - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr index 9b50ddec12a44..7b17e91421660 100644 --- a/src/test/ui/issues/issue-3779.stderr +++ b/src/test/ui/issues/issue-3779.stderr @@ -7,14 +7,10 @@ LL | LL | element: Option | --------- recursive without indirection | -help: insert some indirection to make `S` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable | LL | element: Box> | ^^^^ ^ -LL | element: Rc> - | ^^^ ^ -LL | element: &Option - | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr index a6fe83a9b5636..b7c799e163cee 100644 --- a/src/test/ui/issues/issue-57271.stderr +++ b/src/test/ui/issues/issue-57271.stderr @@ -7,14 +7,10 @@ LL | Class(ClassTypeSignature), LL | Array(TypeSignature), | ------------- recursive without indirection | -help: insert some indirection to make `ObjectType` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ObjectType` representable | LL | Array(Box), | ^^^^ ^ -LL | Array(Rc), - | ^^^ ^ -LL | Array(&TypeSignature), - | ^ error[E0072]: recursive type `TypeSignature` has infinite size --> $DIR/issue-57271.rs:19:1 @@ -25,14 +21,10 @@ LL | Base(BaseType), LL | Object(ObjectType), | ---------- recursive without indirection | -help: insert some indirection to make `TypeSignature` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `TypeSignature` representable | LL | Object(Box), | ^^^^ ^ -LL | Object(Rc), - | ^^^ ^ -LL | Object(&ObjectType), - | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/recursion/recursive-enum.stderr b/src/test/ui/recursion/recursive-enum.stderr index c68badd458bce..ab4709d8e709e 100644 --- a/src/test/ui/recursion/recursive-enum.stderr +++ b/src/test/ui/recursion/recursive-enum.stderr @@ -6,14 +6,10 @@ LL | enum List { Cons(T, List), Nil } | | | recursive type has infinite size | -help: insert some indirection to make `List` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `List` representable | LL | enum List { Cons(T, Box>), Nil } | ^^^^ ^ -LL | enum List { Cons(T, Rc>), Nil } - | ^^^ ^ -LL | enum List { Cons(T, &List), Nil } - | ^ error: aborting due to previous error diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr index 99d8cfd0a05c9..45062c2ea6c72 100644 --- a/src/test/ui/sized-cycle-note.stderr +++ b/src/test/ui/sized-cycle-note.stderr @@ -6,14 +6,10 @@ LL | struct Baz { q: Option } | | | recursive type has infinite size | -help: insert some indirection to make `Baz` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable | LL | struct Baz { q: Box> } | ^^^^ ^ -LL | struct Baz { q: Rc> } - | ^^^ ^ -LL | struct Baz { q: &Option } - | ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/sized-cycle-note.rs:11:1 @@ -23,14 +19,10 @@ LL | struct Foo { q: Option } | | | recursive type has infinite size | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | struct Foo { q: Box> } | ^^^^ ^ -LL | struct Foo { q: Rc> } - | ^^^ ^ -LL | struct Foo { q: &Option } - | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index 855e4facb7b8c..06493f05142e6 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -7,14 +7,10 @@ LL | head: u8, LL | tail: Option, | ---------------- recursive without indirection | -help: insert some indirection to make `ListNode` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable | LL | tail: Box>, | ^^^^ ^ -LL | tail: Rc>, - | ^^^ ^ -LL | tail: &Option, - | ^ error: aborting due to previous error diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index 260c2157e96b7..55128347f7404 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -10,14 +10,10 @@ LL | | tail: Option, LL | | } | |_^ recursive type has infinite size | -help: insert some indirection to make `ListNode` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable | LL | tail: Box>, | ^^^^ ^ -LL | tail: Rc>, - | ^^^ ^ -LL | tail: &Option, - | ^ error: aborting due to previous error diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index c1a3270d0a567..fb1d98b58dfbe 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -6,14 +6,10 @@ LL | struct Foo<'a> { LL | bar: Bar<'a>, | ------- recursive without indirection | -help: insert some indirection to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable | LL | bar: Box>, | ^^^^ ^ -LL | bar: Rc>, - | ^^^ ^ -LL | bar: &Bar<'a>, - | ^ error[E0072]: recursive type `Bar` has infinite size --> $DIR/recursive-type-field.rs:8:1 diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index b98a6eac49e04..d6d32cc5d6f39 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -7,14 +7,10 @@ LL | foo: isize, LL | foolish: T1 | -- recursive without indirection | -help: insert some indirection to make `T1` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable | LL | foolish: Box | ^^^^ ^ -LL | foolish: Rc - | ^^^ ^ -LL | foolish: &T1 - | ^ error: aborting due to previous error diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 70863a549ad25..c54d04de12c50 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -7,14 +7,10 @@ LL | a: u8, LL | b: U, | - recursive without indirection | -help: insert some indirection to make `U` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable | LL | b: Box, | ^^^^ ^ -LL | b: Rc, - | ^^^ ^ -LL | b: &U, - | ^ error: aborting due to previous error From 57078384809fffafac4e90e18cc37a91a1dd5200 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 09:52:51 +0200 Subject: [PATCH 14/19] validate basic sanity for TerminatorKind --- src/librustc_mir/interpret/terminator.rs | 8 +- src/librustc_mir/transform/validate.rs | 103 ++++++++++++++++++++++- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index b048240ca8dc1..3db16a71bab15 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -50,7 +50,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.go_to_block(target_block); } - Call { ref func, ref args, destination, ref cleanup, .. } => { + Call { + ref func, + ref args, + destination, + ref cleanup, + from_hir_call: _from_hir_call, + } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index a25edd131baa1..046889193dac3 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -3,8 +3,11 @@ use super::{MirPass, MirSource}; use rustc_middle::mir::visit::Visitor; use rustc_middle::{ - mir::{Body, Location, Operand, Rvalue, Statement, StatementKind}, - ty::{ParamEnv, TyCtxt}, + mir::{ + BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, + }, + ty::{self, ParamEnv, TyCtxt}, }; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; @@ -38,6 +41,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()), ); } + + fn check_bb(&self, span: Span, bb: BasicBlock) { + if self.body.basic_blocks().get(bb).is_none() { + self.fail(span, format!("encountered jump to invalid basic block {:?}", bb)) + } + } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -77,4 +86,94 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) { + match &terminator.kind { + TerminatorKind::Goto { target } => { + self.check_bb(terminator.source_info.span, *target); + } + TerminatorKind::SwitchInt { targets, .. } => { + if targets.is_empty() { + self.fail( + terminator.source_info.span, + "encountered `SwitchInt` terminator with no target to jump to", + ); + } + for target in targets { + self.check_bb(terminator.source_info.span, *target); + } + } + TerminatorKind::Drop { target, unwind, .. } => { + self.check_bb(terminator.source_info.span, *target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::DropAndReplace { target, unwind, .. } => { + self.check_bb(terminator.source_info.span, *target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::Call { func, destination, cleanup, .. } => { + let func_ty = func.ty(&self.body.local_decls, self.tcx); + match func_ty.kind { + ty::FnPtr(..) | ty::FnDef(..) => {} + _ => self.fail( + terminator.source_info.span, + format!("encountered non-callable type {} in `Call` terminator", func_ty), + ), + } + if let Some((_, target)) = destination { + self.check_bb(terminator.source_info.span, *target); + } + if let Some(cleanup) = cleanup { + self.check_bb(terminator.source_info.span, *cleanup); + } + } + TerminatorKind::Assert { cond, target, cleanup, .. } => { + let cond_ty = cond.ty(&self.body.local_decls, self.tcx); + if cond_ty != self.tcx.types.bool { + self.fail( + terminator.source_info.span, + format!( + "encountered non-boolean condition of type {} in `Assert` terminator", + cond_ty + ), + ); + } + self.check_bb(terminator.source_info.span, *target); + if let Some(cleanup) = cleanup { + self.check_bb(terminator.source_info.span, *cleanup); + } + } + TerminatorKind::Yield { resume, drop, .. } => { + self.check_bb(terminator.source_info.span, *resume); + if let Some(drop) = drop { + self.check_bb(terminator.source_info.span, *drop); + } + } + TerminatorKind::FalseEdges { real_target, imaginary_target } => { + self.check_bb(terminator.source_info.span, *real_target); + self.check_bb(terminator.source_info.span, *imaginary_target); + } + TerminatorKind::FalseUnwind { real_target, unwind } => { + self.check_bb(terminator.source_info.span, *real_target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::InlineAsm { destination, .. } => { + if let Some(destination) = destination { + self.check_bb(terminator.source_info.span, *destination); + } + } + // Nothing to validate for these. + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop => {} + } + } } From e07e42433f9f8e2845d4941c59dc64918d467228 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 14:26:41 +0200 Subject: [PATCH 15/19] replace DUMMY_SP by proper span --- src/librustc_mir/transform/validate.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 046889193dac3..7a1393468cec6 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -54,12 +54,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { let ty = place.ty(&self.body.local_decls, self.tcx).ty; + let span = self.body.source_info(location).span; - if !ty.is_copy_modulo_regions(self.tcx, self.param_env, DUMMY_SP) { - self.fail( - DUMMY_SP, - format!("`Operand::Copy` with non-`Copy` type {} at {:?}", ty, location), - ); + if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) { + self.fail(span, format!("`Operand::Copy` with non-`Copy` type {}", ty)); } } From 9a4bdbff9e52fe2bb2977ea6edddb13064726a25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 15:07:16 +0200 Subject: [PATCH 16/19] more checks for SwitchInt --- src/librustc_mir/transform/validate.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 7a1393468cec6..4039d1b50e8f5 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -90,11 +90,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { TerminatorKind::Goto { target } => { self.check_bb(terminator.source_info.span, *target); } - TerminatorKind::SwitchInt { targets, .. } => { - if targets.is_empty() { + TerminatorKind::SwitchInt { targets, values, .. } => { + if targets.len() != values.len() + 1 { self.fail( terminator.source_info.span, - "encountered `SwitchInt` terminator with no target to jump to", + format!( + "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", + values.len(), + targets.len(), + ), ); } for target in targets { From f793c0b1bf3392c19eb11331fddc8c9f561361ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 15:21:09 +0200 Subject: [PATCH 17/19] always print MIR Location when validator finds a problem --- src/librustc_mir/transform/validate.rs | 68 ++++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 4039d1b50e8f5..7d301b2f49648 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -9,7 +9,7 @@ use rustc_middle::{ }, ty::{self, ParamEnv, TyCtxt}, }; -use rustc_span::{def_id::DefId, Span, DUMMY_SP}; +use rustc_span::def_id::DefId; pub struct Validator { /// Describes at which point in the pipeline this validation is happening. @@ -33,18 +33,25 @@ struct TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn fail(&self, span: Span, msg: impl AsRef) { + fn fail(&self, location: Location, msg: impl AsRef) { + let span = self.body.source_info(location).span; // We use `delay_span_bug` as we might see broken MIR when other errors have already // occurred. self.tcx.sess.diagnostic().delay_span_bug( span, - &format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()), + &format!( + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.def_id, + self.when, + location, + msg.as_ref() + ), ); } - fn check_bb(&self, span: Span, bb: BasicBlock) { + fn check_bb(&self, location: Location, bb: BasicBlock) { if self.body.basic_blocks().get(bb).is_none() { - self.fail(span, format!("encountered jump to invalid basic block {:?}", bb)) + self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) } } } @@ -57,7 +64,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let span = self.body.source_info(location).span; if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) { - self.fail(span, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); } } @@ -72,11 +79,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { if dest == src { self.fail( - DUMMY_SP, - format!( - "encountered `Assign` statement with overlapping memory at {:?}", - location - ), + location, + "encountered `Assign` statement with overlapping memory", ); } } @@ -85,15 +89,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match &terminator.kind { TerminatorKind::Goto { target } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } TerminatorKind::SwitchInt { targets, values, .. } => { if targets.len() != values.len() + 1 { self.fail( - terminator.source_info.span, + location, format!( "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", values.len(), @@ -102,19 +106,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } for target in targets { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } } TerminatorKind::Drop { target, unwind, .. } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::DropAndReplace { target, unwind, .. } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::Call { func, destination, cleanup, .. } => { @@ -122,52 +126,52 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { match func_ty.kind { ty::FnPtr(..) | ty::FnDef(..) => {} _ => self.fail( - terminator.source_info.span, + location, format!("encountered non-callable type {} in `Call` terminator", func_ty), ), } if let Some((_, target)) = destination { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } if let Some(cleanup) = cleanup { - self.check_bb(terminator.source_info.span, *cleanup); + self.check_bb(location, *cleanup); } } TerminatorKind::Assert { cond, target, cleanup, .. } => { let cond_ty = cond.ty(&self.body.local_decls, self.tcx); if cond_ty != self.tcx.types.bool { self.fail( - terminator.source_info.span, + location, format!( "encountered non-boolean condition of type {} in `Assert` terminator", cond_ty ), ); } - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(cleanup) = cleanup { - self.check_bb(terminator.source_info.span, *cleanup); + self.check_bb(location, *cleanup); } } TerminatorKind::Yield { resume, drop, .. } => { - self.check_bb(terminator.source_info.span, *resume); + self.check_bb(location, *resume); if let Some(drop) = drop { - self.check_bb(terminator.source_info.span, *drop); + self.check_bb(location, *drop); } } TerminatorKind::FalseEdges { real_target, imaginary_target } => { - self.check_bb(terminator.source_info.span, *real_target); - self.check_bb(terminator.source_info.span, *imaginary_target); + self.check_bb(location, *real_target); + self.check_bb(location, *imaginary_target); } TerminatorKind::FalseUnwind { real_target, unwind } => { - self.check_bb(terminator.source_info.span, *real_target); + self.check_bb(location, *real_target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::InlineAsm { destination, .. } => { if let Some(destination) = destination { - self.check_bb(terminator.source_info.span, *destination); + self.check_bb(location, *destination); } } // Nothing to validate for these. From 717fd665ad1095b12907ed0f2426d8eb06c2bddc Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 26 May 2020 13:21:58 -0400 Subject: [PATCH 18/19] Make `SourceMap` available for early debug-printing of `Span`s Normally, we debug-print `Spans` using the `SourceMap` retrieved from the global `TyCtxt`. However, we fall back to printing out the `Span`'s raw fields (instead of a file and line number) when we try to print a `Span` before a `TyCtxt` is available. This makes debugging early phases of the compile, such as parsing, much more difficult. This commit stores a `SourceMap` in `rustc_span::GlOBALS` as a fallback. When a `TyCtxt` is not available, we try to retrieve one from `GLOBALS` - only if this is not available do we fall back to the raw field output. I'm not sure how to write a test for this - however, this can be verified locally by setting `RUSTC_LOG="rustc_parse=debug"`, and verifying that the output contains filenames and line numbers. --- src/librustc_interface/interface.rs | 24 ++++++++------- src/librustc_span/lib.rs | 45 +++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index f127a239eea2c..5aad64f84cee3 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -186,17 +186,19 @@ pub fn run_compiler_in_existing_thread_pool( override_queries: config.override_queries, }; - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) } pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 616876d4b02a8..0f2eec48b4809 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -25,6 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; mod caching_source_map_view; pub mod source_map; pub use self::caching_source_map_view::CachingSourceMapView; +use source_map::SourceMap; pub mod edition; use edition::Edition; @@ -67,6 +68,7 @@ pub struct Globals { symbol_interner: Lock, span_interner: Lock, hygiene_data: Lock, + source_map: Lock>>, } impl Globals { @@ -75,6 +77,7 @@ impl Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), + source_map: Lock::new(None), } } } @@ -641,12 +644,44 @@ impl rustc_serialize::UseSpecializedDecodable for Span { } } +/// Calls the provided closure, using the provided `SourceMap` to format +/// any spans that are debug-printed during the closure'e exectuino. +/// +/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap` +/// (see `rustc_interface::callbacks::span_debug1). However, some parts +/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before +/// a `TyCtxt` is available. In this case, we fall back to +/// the `SourceMap` provided to this function. If that is not available, +/// we fall back to printing the raw `Span` field values +pub fn with_source_map T>(source_map: Lrc, f: F) -> T { + GLOBALS.with(|globals| { + *globals.source_map.borrow_mut() = Some(source_map); + }); + struct ClearSourceMap; + impl Drop for ClearSourceMap { + fn drop(&mut self) { + GLOBALS.with(|globals| { + globals.source_map.borrow_mut().take(); + }); + } + } + + let _guard = ClearSourceMap; + f() +} + pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Span") - .field("lo", &span.lo()) - .field("hi", &span.hi()) - .field("ctxt", &span.ctxt()) - .finish() + GLOBALS.with(|globals| { + if let Some(source_map) = &*globals.source_map.borrow() { + write!(f, "{}", source_map.span_to_string(span)) + } else { + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() + } + }) } impl fmt::Debug for Span { From aa5d29fcb1fac6f8db692341f069c9531c802607 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 12:11:31 +0200 Subject: [PATCH 19/19] bump Miri, update for cargo-miri being a separate project --- Cargo.lock | 25 ++++++++++++++++--------- Cargo.toml | 1 + src/bootstrap/builder.rs | 2 ++ src/bootstrap/test.rs | 15 +++++++++++---- src/bootstrap/tool.rs | 4 +++- src/tools/miri | 2 +- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2f5d058f5cf1..2b174c62891b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,6 +345,19 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata 0.9.1", + "directories", + "rustc-workspace-hack", + "rustc_version", + "serde", + "serde_json", + "vergen", +] + [[package]] name = "cargo-platform" version = "0.1.1" @@ -2220,22 +2233,17 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder", - "cargo_metadata 0.9.1", "colored", "compiletest_rs", - "directories", "env_logger 0.7.1", "getrandom", "hex 0.4.0", + "libc", "log", - "num-traits", "rand 0.7.3", "rustc-workspace-hack", "rustc_version", - "serde", - "serde_json", "shell-escape", - "vergen", ] [[package]] @@ -5555,13 +5563,12 @@ checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" [[package]] name = "vergen" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" dependencies = [ "bitflags", "chrono", - "failure", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7b5e0fa1c2817..f2177a99a9b88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "src/tools/rls", "src/tools/rustfmt", "src/tools/miri", + "src/tools/miri/cargo-miri", "src/tools/rustdoc-themes", "src/tools/unicode-table-generator", "src/tools/expand-yaml-anchors", diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c8a85eae252ff..ffdd8485181f4 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -344,10 +344,12 @@ impl<'a> Builder<'a> { tool::Rls, tool::Rustdoc, tool::Clippy, + tool::CargoClippy, native::Llvm, native::Sanitizers, tool::Rustfmt, tool::Miri, + tool::CargoMiri, native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f1305e2540b4c..9f305ea4729c5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -360,7 +360,12 @@ impl Step for Miri { let miri = builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }); - if let Some(miri) = miri { + let cargo_miri = builder.ensure(tool::CargoMiri { + compiler, + target: self.host, + extra_features: Vec::new(), + }); + if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) { let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "install"); cargo.arg("xargo"); // Configure `cargo install` path. cargo adds a `bin/`. @@ -378,14 +383,16 @@ impl Step for Miri { Mode::ToolRustc, host, "run", - "src/tools/miri", + "src/tools/miri/cargo-miri", SourceType::Submodule, &[], ); - cargo.arg("--bin").arg("cargo-miri").arg("--").arg("miri").arg("setup"); + cargo.arg("--").arg("miri").arg("setup"); // Tell `cargo miri setup` where to find the sources. cargo.env("XARGO_RUST_SRC", builder.src.join("src")); + // Tell it where to find Miri. + cargo.env("MIRI", &miri); // Debug things. cargo.env("RUST_BACKTRACE", "1"); // Overwrite bootstrap's `rustc` wrapper overwriting our flags. @@ -437,7 +444,7 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", miri_sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - cargo.env("MIRI_PATH", miri); + cargo.env("MIRI", miri); cargo.arg("--").args(builder.config.cmd.test_args()); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 5f58f00a2a24d..6cd9f9029c948 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -649,12 +649,14 @@ macro_rules! tool_extended { } } +// Note: tools need to be also added to `Builder::get_step_descriptions` in `build.rs` +// to make `./x.py build ` work. tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {}; Clippy, clippy, "src/tools/clippy", "clippy-driver", {}; Miri, miri, "src/tools/miri", "miri", {}; - CargoMiri, miri, "src/tools/miri", "cargo-miri", {}; + CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", {}; Rls, rls, "src/tools/rls", "rls", { builder.ensure(Clippy { compiler: self.compiler, diff --git a/src/tools/miri b/src/tools/miri index a6c28f08458e1..a8df047f5c71c 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit a6c28f08458e15cead0e80f3b5b7009786bce4a4 +Subproject commit a8df047f5c71c872b72bf6868938f2595cfc2f4b