about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-07-01 09:20:38 +0000
committerbors <bors@rust-lang.org>2021-07-01 09:20:38 +0000
commit3cb1c1134050c059a15d9ca7a00d4dd89111a373 (patch)
treed3e4dd08a2460c57d2904d3a31c9f327025f2680 /compiler
parentf8ac8fdacf66b351c6479b0c8313e3e57e571ba4 (diff)
parentd10af08f7234503d53e079d3b0a980b4d8c7b391 (diff)
downloadrust-3cb1c1134050c059a15d9ca7a00d4dd89111a373.tar.gz
rust-3cb1c1134050c059a15d9ca7a00d4dd89111a373.zip
Auto merge of #86774 - GuillaumeGomez:rollup-rkcgvph, r=GuillaumeGomez
Rollup of 6 pull requests

Successful merges:

 - #86558 (Add suggestions for "undefined reference" link errors)
 - #86616 (rustc_span: Explicitly handle crates that differ from package names)
 - #86652 (Add support for leaf function frame pointer elimination)
 - #86666 (Fix misleading "impl Trait" error)
 - #86762 (mailmap: Add my work email address)
 - #86773 (Enable the tests developed with #86594)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/misc.rs2
-rw-r--r--compiler/rustc_session/src/session.rs12
-rw-r--r--compiler/rustc_span/Cargo.toml4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs3
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs3
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs3
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_tvos.rs3
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs4
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs4
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/mod.rs55
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/thumb_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs5
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs16
27 files changed, 144 insertions, 70 deletions
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 6a032b9be72..56b93f83466 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::OptLevel;
 use rustc_session::Session;
 use rustc_target::spec::abi::Abi;
-use rustc_target::spec::{SanitizerSet, StackProbeType};
+use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
 
 use crate::attributes;
 use crate::llvm::AttributePlace::Function;
@@ -69,15 +69,25 @@ fn naked(val: &'ll Value, is_naked: bool) {
     Attribute::Naked.toggle_llfn(Function, val, is_naked);
 }
 
-pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
-    if cx.sess().must_not_eliminate_frame_pointers() {
-        llvm::AddFunctionAttrStringValue(
-            llfn,
-            llvm::AttributePlace::Function,
-            cstr!("frame-pointer"),
-            cstr!("all"),
-        );
+pub fn set_frame_pointer_type(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    let mut fp = cx.sess().target.frame_pointer;
+    // "mcount" function relies on stack pointer.
+    // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
+    if cx.sess().instrument_mcount() || matches!(cx.sess().opts.cg.force_frame_pointers, Some(true))
+    {
+        fp = FramePointer::Always;
     }
+    let attr_value = match fp {
+        FramePointer::Always => cstr!("all"),
+        FramePointer::NonLeaf => cstr!("non-leaf"),
+        FramePointer::MayOmit => return,
+    };
+    llvm::AddFunctionAttrStringValue(
+        llfn,
+        llvm::AttributePlace::Function,
+        cstr!("frame-pointer"),
+        attr_value,
+    );
 }
 
 /// Tell LLVM what instrument function to insert.
@@ -254,7 +264,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     }
 
     // FIXME: none of these three functions interact with source level attributes.
-    set_frame_pointer_elimination(cx, llfn);
+    set_frame_pointer_type(cx, llfn);
     set_instrument_function(cx, llfn);
     set_probestack(cx, llfn);
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 7415a570453..f662887abf8 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -410,8 +410,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         &self.used_statics
     }
 
-    fn set_frame_pointer_elimination(&self, llfn: &'ll Value) {
-        attributes::set_frame_pointer_elimination(self, llfn)
+    fn set_frame_pointer_type(&self, llfn: &'ll Value) {
+        attributes::set_frame_pointer_type(self, llfn)
     }
 
     fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 22d513d66d1..1fb201eda6b 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -674,7 +674,7 @@ fn gen_fn<'ll, 'tcx>(
 ) -> &'ll Value {
     let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
     let llfn = cx.declare_fn(name, &fn_abi);
-    cx.set_frame_pointer_elimination(llfn);
+    cx.set_frame_pointer_type(llfn);
     cx.apply_target_cpu_attr(llfn);
     // FIXME(eddyb) find a nicer way to do this.
     unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 6c9ec9e7b0d..d47624da79a 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -912,14 +912,23 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             if !prog.status.success() {
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
-                sess.struct_err(&format!(
+                let escaped_output = escape_stdout_stderr_string(&output);
+                let mut err = sess.struct_err(&format!(
                     "linking with `{}` failed: {}",
                     linker_path.display(),
                     prog.status
-                ))
-                .note(&format!("{:?}", &cmd))
-                .note(&escape_stdout_stderr_string(&output))
-                .emit();
+                ));
+                err.note(&format!("{:?}", &cmd)).note(&escaped_output);
+                if escaped_output.contains("undefined reference to") {
+                    err.help(
+                        "some `extern` functions couldn't be found; some native libraries may \
+                         need to be installed or have their path specified",
+                    );
+                    err.note("use the `-l` flag to specify native libraries to link");
+                    err.note("use the `cargo:rustc-link-lib` directive to specify the native \
+                              libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
+                }
+                err.emit();
 
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 31ae84f4ca1..2e9aae467f8 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -406,7 +406,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         };
 
         // `main` should respect same config for frame pointer elimination as rest of code
-        cx.set_frame_pointer_elimination(llfn);
+        cx.set_frame_pointer_type(llfn);
         cx.apply_target_cpu_attr(llfn);
 
         let llbb = Bx::append_block(&cx, llfn, "top");
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 6fff64bfcb6..46f2adbe552 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -16,7 +16,7 @@ pub trait MiscMethods<'tcx>: BackendTypes {
     fn sess(&self) -> &Session;
     fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
     fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
-    fn set_frame_pointer_elimination(&self, llfn: Self::Function);
+    fn set_frame_pointer_type(&self, llfn: Self::Function);
     fn apply_target_cpu_attr(&self, llfn: Self::Function);
     fn create_used_variable(&self);
     /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index d8a58ee18cd..f792e319867 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -792,18 +792,6 @@ impl Session {
         !self.target.is_like_windows && !self.target.is_like_osx
     }
 
-    pub fn must_not_eliminate_frame_pointers(&self) -> bool {
-        // "mcount" function relies on stack pointer.
-        // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
-        if self.instrument_mcount() {
-            true
-        } else if let Some(x) = self.opts.cg.force_frame_pointers {
-            x
-        } else {
-            !self.target.eliminate_frame_pointer
-        }
-    }
-
     pub fn must_emit_unwind_tables(&self) -> bool {
         // This is used to control the emission of the `uwtable` attribute on
         // LLVM functions.
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 08645990c48..4552f14de8b 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -17,6 +17,6 @@ scoped-tls = "1.0"
 unicode-width = "0.1.4"
 cfg-if = "0.1.2"
 tracing = "0.1"
-sha-1 = "0.9"
+sha1 = { package = "sha-1", version = "0.9" }
 sha2 = "0.9"
-md-5 = "0.9"
+md5 = { package = "md-5", version = "0.9" }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index feadd4e891c..bf3ec8f9160 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -20,6 +20,10 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: arch.to_string(),
-        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions {
+            mcount: "\u{1}mcount".to_string(),
+            frame_pointer: FramePointer::NonLeaf,
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index 5682039b865..9fa8ef69d81 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::Arm64);
@@ -13,6 +13,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 8a832546d09..a43eb99a1d7 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::Arm64_macabi);
@@ -13,6 +13,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
index 2187015b627..586e4043d79 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::Arm64_sim);
@@ -21,6 +21,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index cb6c06b3711..934f3370369 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("tvos", Arch::Arm64);
@@ -13,6 +13,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 8530db179d9..0c8a89210ff 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,6 +1,6 @@
 use std::env;
 
-use crate::spec::{SplitDebuginfo, TargetOptions};
+use crate::spec::{FramePointer, SplitDebuginfo, TargetOptions};
 
 pub fn opts(os: &str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
@@ -27,7 +27,7 @@ pub fn opts(os: &str) -> TargetOptions {
         families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         has_rpath: true,
         dll_suffix: ".dylib".to_string(),
         archive_format: "darwin".to_string(),
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index bef2fce7c83..998d6ffe0fc 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{RelroLevel, TargetOptions};
+use crate::spec::{FramePointer, RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -8,7 +8,7 @@ pub fn opts() -> TargetOptions {
         families: vec!["unix".to_string()],
         has_rpath: true,
         position_independent_executables: true,
-        eliminate_frame_pointer: false, // FIXME 43575
+        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
         dwarf_version: Some(2),
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 06d71db4af2..f2635f0656d 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -8,7 +8,7 @@ pub fn target() -> Target {
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
index 7002d88c512..92c3a1554ac 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pe".to_string()]);
     base.max_atomic_width = Some(64);
-    base.eliminate_frame_pointer = false; // Required for backtraces
+    base.frame_pointer = FramePointer::Always; // Required for backtraces
     base.linker = Some("i686-w64-mingw32-gcc".to_string());
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 228976779f0..d95cb6a82d5 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -21,7 +21,7 @@ pub fn target() -> Target {
     //
     // This may or may not be related to this bug:
     // https://llvm.org/bugs/show_bug.cgi?id=30879
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
 
     Target {
         llvm_target: "i686-unknown-linux-musl".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
index 426df59882d..27a0ac585e3 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pe".to_string()]);
     base.max_atomic_width = Some(64);
-    base.eliminate_frame_pointer = false; // Required for backtraces
+    base.frame_pointer = FramePointer::Always; // Required for backtraces
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 9d9da50be7a..f598f0f38f3 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use crate::spec::{FramePointer, LinkArgs, LinkerFlavor, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
@@ -35,7 +35,7 @@ pub fn opts() -> TargetOptions {
         is_like_solaris: true,
         linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         eh_frame_header: false,
         late_link_args,
 
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 145aa4a5894..a332e3b847a 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -1,4 +1,5 @@
-use crate::spec::{PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, PanicStrategy, RelocModel, RelroLevel, StackProbeType};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -7,7 +8,7 @@ pub fn opts() -> TargetOptions {
         panic_strategy: PanicStrategy::Abort,
         // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
         stack_probes: StackProbeType::Call,
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         position_independent_executables: true,
         needs_plt: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0bf89c3f93b..cfdae9623f3 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -671,6 +671,42 @@ impl ToJson for SanitizerSet {
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum FramePointer {
+    /// Forces the machine code generator to always preserve the frame pointers.
+    Always,
+    /// Forces the machine code generator to preserve the frame pointers except for the leaf
+    /// functions (i.e. those that don't call other functions).
+    NonLeaf,
+    /// Allows the machine code generator to omit the frame pointers.
+    ///
+    /// This option does not guarantee that the frame pointers will be omitted.
+    MayOmit,
+}
+
+impl FromStr for FramePointer {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "always" => Self::Always,
+            "non-leaf" => Self::NonLeaf,
+            "may-omit" => Self::MayOmit,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl ToJson for FramePointer {
+    fn to_json(&self) -> Json {
+        match *self {
+            Self::Always => "always",
+            Self::NonLeaf => "non-leaf",
+            Self::MayOmit => "may-omit",
+        }
+        .to_json()
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -1068,8 +1104,8 @@ pub struct TargetOptions {
     pub tls_model: TlsModel,
     /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
     pub disable_redzone: bool,
-    /// Eliminate frame pointers from stack frames if possible. Defaults to true.
-    pub eliminate_frame_pointer: bool,
+    /// Frame pointer mode for this target. Defaults to `MayOmit`.
+    pub frame_pointer: FramePointer,
     /// Emit each function in its own section. Defaults to true.
     pub function_sections: bool,
     /// String to prepend to the name of every dynamic library. Defaults to "lib".
@@ -1330,7 +1366,7 @@ impl Default for TargetOptions {
             code_model: None,
             tls_model: TlsModel::GeneralDynamic,
             disable_redzone: false,
-            eliminate_frame_pointer: true,
+            frame_pointer: FramePointer::MayOmit,
             function_sections: true,
             dll_prefix: "lib".to_string(),
             dll_suffix: ".so".to_string(),
@@ -1833,6 +1869,16 @@ impl Target {
             }
         }
 
+        if let Some(fp) = obj.remove_key("frame-pointer") {
+            if let Some(s) = Json::as_string(&fp) {
+                base.frame_pointer = s
+                    .parse()
+                    .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
+            } else {
+                incorrect_type.push("frame-pointer".to_string())
+            }
+        }
+
         key!(is_builtin, bool);
         key!(c_int_width = "target-c-int-width");
         key!(os);
@@ -1864,7 +1910,6 @@ impl Target {
         key!(code_model, CodeModel)?;
         key!(tls_model, TlsModel)?;
         key!(disable_redzone, bool);
-        key!(eliminate_frame_pointer, bool);
         key!(function_sections, bool);
         key!(dll_prefix);
         key!(dll_suffix);
@@ -2128,7 +2173,7 @@ impl ToJson for Target {
         target_option_val!(code_model);
         target_option_val!(tls_model);
         target_option_val!(disable_redzone);
-        target_option_val!(eliminate_frame_pointer);
+        target_option_val!(frame_pointer);
         target_option_val!(function_sections);
         target_option_val!(dll_prefix);
         target_option_val!(dll_suffix);
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index 29b415e7726..70e9e4aed92 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{RelroLevel, TargetOptions};
+use crate::spec::{FramePointer, RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         abi_return_struct_as_int: true,
         position_independent_executables: true,
-        eliminate_frame_pointer: false, // FIXME 43575
+        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
         dwarf_version: Some(2),
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index ec24807fec4..fbe4dd5b501 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -27,7 +27,8 @@
 // differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
 // build scripts / gcc flags.
 
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
 
 pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
@@ -52,7 +53,7 @@ pub fn opts() -> TargetOptions {
         emit_debug_gdb_scripts: false,
         // LLVM is eager to trash the link register when calling `noreturn` functions, which
         // breaks debugging. Preserve LR by default to prevent that from happening.
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index dc7597fe7b2..60fd42970c7 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
     base.pre_link_args.insert(
         LinkerFlavor::Gcc,
         vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 236fec94bdb..afa4d0f1c4d 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1481,6 +1481,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     expected,
                     found,
                     can_suggest,
+                    fcx.tcx.hir().get_parent_item(id),
                 );
             }
             if !pointing_at_return_type {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index d6b1e56316b..54aab271fdb 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -52,9 +52,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            pointing_at_return_type =
-                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
             let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
+            pointing_at_return_type = self.suggest_missing_return_type(
+                err,
+                &fn_decl,
+                expected,
+                found,
+                can_suggest,
+                fn_id,
+            );
             self.suggest_missing_break_or_return_expr(
                 err, expr, &fn_decl, expected, found, blk_id, fn_id,
             );
@@ -433,6 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         can_suggest: bool,
+        fn_id: hir::HirId,
     ) -> bool {
         // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
@@ -465,7 +472,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
                 debug!("suggest_missing_return_type: return type {:?}", ty);
                 debug!("suggest_missing_return_type: expected type {:?}", ty);
-                if ty.kind() == expected.kind() {
+                let bound_vars = self.tcx.late_bound_vars(fn_id);
+                let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
+                let ty = self.normalize_associated_types_in(sp, ty);
+                if self.can_coerce(expected, ty) {
                     err.span_label(sp, format!("expected `{}` because of return type", expected));
                     return true;
                 }