From 6b59cac1197fafda31951aa05a55b0dd7871400f Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 6 Jul 2020 14:32:30 -0400 Subject: [PATCH] Suppress debuginfo on naked function arguments A function that has no prologue cannot be reasonably expected to support debuginfo. In fact, the existing code (before this patch) would generate invalid instructions that caused crashes. We can solve this easily by just not emitting the debuginfo in this case. Fixes https://github.com/rust-lang/rust/issues/42779 cc https://github.com/rust-lang/rust/issues/32408 --- src/librustc_mir_build/build/mod.rs | 12 +++++++++++- src/test/codegen/naked-functions.rs | 4 ++-- src/test/debuginfo/function-arguments.rs | 17 +++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index e69f6b30abd5c..d6dd3711dba19 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; @@ -790,12 +791,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { argument_scope: region::Scope, ast_body: &'tcx hir::Expr<'tcx>, ) -> BlockAnd<()> { + let tcx = self.hir.tcx(); + let attrs = tcx.codegen_fn_attrs(fn_def_id); + let naked = attrs.flags.contains(CodegenFnAttrFlags::NAKED); + // Allocate locals for the function arguments for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { let source_info = SourceInfo::outermost(arg_opt.map_or(self.fn_span, |arg| arg.pat.span)); let arg_local = self.local_decls.push(LocalDecl::with_source_info(ty, source_info)); + // Emit function argument debuginfo only for non-naked functions. + // See: https://github.com/rust-lang/rust/issues/42779 + if naked { + continue; + } + // If this is a simple binding pattern, give debuginfo a nice name. if let Some(arg) = arg_opt { if let Some(ident) = arg.pat.simple_ident() { @@ -808,7 +819,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let tcx = self.hir.tcx(); let tcx_hir = tcx.hir(); let hir_tables = self.hir.tables(); diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 493c1b9f0ba6b..758c6c4da9293 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -18,7 +18,7 @@ pub fn naked_empty() { // CHECK-NEXT: define void @naked_with_args(i{{[0-9]+( %0)?}}) pub fn naked_with_args(a: isize) { // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: %a = alloca i{{[0-9]+}} + // CHECK-NEXT: %_1 = alloca i{{[0-9]+}} &a; // keep variable in an alloca // CHECK: ret void } @@ -39,7 +39,7 @@ pub fn naked_with_return() -> isize { #[naked] pub fn naked_with_args_and_return(a: isize) -> isize { // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: %a = alloca i{{[0-9]+}} + // CHECK-NEXT: %_1 = alloca i{{[0-9]+}} &a; // keep variable in an alloca // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a diff --git a/src/test/debuginfo/function-arguments.rs b/src/test/debuginfo/function-arguments.rs index 5cfd7d1f8f198..fb0bbbf371d8e 100644 --- a/src/test/debuginfo/function-arguments.rs +++ b/src/test/debuginfo/function-arguments.rs @@ -18,6 +18,10 @@ // gdb-check:$4 = 3000 // gdb-command:continue +// gdb-command:info args +// gdb-check:No arguments. +// gdb-command:continue + // === LLDB TESTS ================================================================================== // lldb-command:run @@ -38,7 +42,12 @@ // lldbr-check:(i64) b = 3000 // lldb-command:continue +// lldb-command:frame variable +// lldbg-check:(unsigned long) = 111 (unsigned long) = 222 +// lldbr-check:(unsigned long) = 111 (unsigned long) = 222 +// lldb-command:continue +#![feature(naked_functions)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -46,6 +55,7 @@ fn main() { fun(111102, true); nested(2000, 3000); + naked(111, 222); fn nested(a: i32, b: i64) -> (i32, i64) { zzz(); // #break @@ -59,4 +69,11 @@ fn fun(x: isize, y: bool) -> (isize, bool) { (x, y) } +#[naked] +fn naked(x: usize, y: usize) -> usize { + zzz(); // #break + + x + y +} + fn zzz() { () }