From 1373c4fcf21930a22150210200bdc14f5f935b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 13 Jul 2015 21:48:07 +0200 Subject: [PATCH 1/4] Properly create debug info for functions We're currently using the actual function type as the return type when creating the debug info for a function, so we're actually creating debug info for a function that takes the same parameters, and returns the actual function type, which is completely wrong. --- .../trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans/debuginfo/mod.rs | 51 +++++++++++-------- src/test/debuginfo/basic-types-metadata.rs | 2 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 599a255ef8b..d1f52403896 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -920,7 +920,7 @@ pub fn scope_metadata(fcx: &FunctionContext, } } -fn diverging_type_metadata(cx: &CrateContext) -> DIType { +pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index a8735298917..39def5ed48a 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -18,7 +18,8 @@ use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_att create_DIArray, is_node_local_to_unit}; use self::namespace::{namespace_for_item, NamespaceTreeNode}; use self::type_names::compute_debuginfo_type_name; -use self::metadata::{type_metadata, file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; +use self::metadata::{type_metadata, diverging_type_metadata}; +use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; use self::source_loc::InternalDebugLocation; use llvm; @@ -30,7 +31,7 @@ use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; use trans::monomorphize; -use middle::ty::Ty; +use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -325,7 +326,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, fn_ast_id, - &*fn_decl, param_substs, span); llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) @@ -402,35 +402,42 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn_ast_id: ast::NodeId, - fn_decl: &ast::FnDecl, param_substs: &Substs<'tcx>, error_reporting_span: Span) -> DIArray { if cx.sess().opts.debuginfo == LimitedDebugInfo { return create_DIArray(DIB(cx), &[]); } - let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1); - // Return type -- llvm::DIBuilder wants this at index 0 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); - let return_type = cx.tcx().node_id_to_type(fn_ast_id); - let return_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &return_type); - if return_type.is_nil() { - signature.push(ptr::null_mut()) - } else { - signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); - } + let fn_type = cx.tcx().node_id_to_type(fn_ast_id); + + let sig = match fn_type.sty { + ty::TyBareFn(_, ref barefnty) => { + cx.tcx().erase_late_bound_regions(&barefnty.sig) + } + ty::TyClosure(def_id, substs) => { + cx.tcx().erase_late_bound_regions(&cx.tcx().closure_type(def_id, substs).sig) + } + + _ => cx.sess().bug("get_function_metdata: Expected a function type!") + }; + let sig = monomorphize::apply_param_substs(cx.tcx(), param_substs, &sig); + + let mut signature = Vec::with_capacity(sig.inputs.len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output { + ty::FnConverging(ret_ty) => match ret_ty.sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, ret_ty, codemap::DUMMY_SP) + }, + ty::FnDiverging => diverging_type_metadata(cx) + }); // Arguments types - for arg in &fn_decl.inputs { - assert_type_for_node_id(cx, arg.pat.id, arg.pat.span); - let arg_type = cx.tcx().node_id_to_type(arg.pat.id); - let arg_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &arg_type); - signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP)); + for &argument_type in &sig.inputs { + signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP)); } return create_DIArray(DIB(cx), &signature[..]); diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 0134a058c99..57dabadfbd5 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -43,7 +43,7 @@ // gdb-command:whatis f64 // gdb-check:type = f64 // gdb-command:info functions _yyy -// gdb-check:[...]![...]_yyy([...])([...]); +// gdb-check:[...]![...]_yyy([...]); // gdb-command:continue #![allow(unused_variables)] From 47128b8c7ed38b28e1e7788bc9d5197959d450e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 14 Jul 2015 19:03:13 +0200 Subject: [PATCH 2/4] Create correct debuginfo for closure function signatures Internally, the arguments passed to the closure are represented by a tuple, but the actual function takes them as individual arguments, so we have to untuple the arguments before creating the debuginfo. --- src/librustc_trans/trans/debuginfo/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 39def5ed48a..9ce5c457bff 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -30,7 +30,7 @@ use middle::subst::{self, Substs}; use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; -use trans::monomorphize; +use trans::{monomorphize, type_of}; use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -41,7 +41,7 @@ use std::ffi::CString; use std::ptr; use std::rc::Rc; use syntax::codemap::{Span, Pos}; -use syntax::{ast, codemap, ast_util}; +use syntax::{abi, ast, codemap, ast_util}; use syntax::attr::IntType; use syntax::parse::token::{self, special_idents}; @@ -412,12 +412,13 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); let fn_type = cx.tcx().node_id_to_type(fn_ast_id); - let sig = match fn_type.sty { + let (sig, abi) = match fn_type.sty { ty::TyBareFn(_, ref barefnty) => { - cx.tcx().erase_late_bound_regions(&barefnty.sig) + (cx.tcx().erase_late_bound_regions(&barefnty.sig), barefnty.abi) } ty::TyClosure(def_id, substs) => { - cx.tcx().erase_late_bound_regions(&cx.tcx().closure_type(def_id, substs).sig) + let closure_type = cx.tcx().closure_type(def_id, substs); + (cx.tcx().erase_late_bound_regions(&closure_type.sig), closure_type.abi) } _ => cx.sess().bug("get_function_metdata: Expected a function type!") @@ -435,8 +436,14 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::FnDiverging => diverging_type_metadata(cx) }); + let inputs = &if abi == abi::RustCall { + type_of::untuple_arguments(cx, &sig.inputs) + } else { + sig.inputs + }; + // Arguments types - for &argument_type in &sig.inputs { + for &argument_type in inputs { signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP)); } From 9175a16bd8c5b37c485dfe36fea8f9df96e02bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 13 Jul 2015 21:50:21 +0200 Subject: [PATCH 3/4] Generate proper debug info for function pointers Instead of generating pointer debug info, we're currently generating subroutine debug info. --- src/librustc_trans/trans/debuginfo/metadata.rs | 15 ++++++++++++++- src/test/debuginfo/basic-types-metadata.rs | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index d1f52403896..33f60d7e78d 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -796,7 +796,20 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ty::TyBareFn(_, ref barefnty) => { - subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + &barefnty.sig, + usage_site_span).metadata; + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return metadata, + None => { /* proceed normally */ } + }; + + // This is actually a function pointer, so wrap it in pointer DI + MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + } ty::TyClosure(def_id, substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 57dabadfbd5..1bc2ddef51e 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -42,6 +42,8 @@ // gdb-check:type = f32 // gdb-command:whatis f64 // gdb-check:type = f64 +// gdb-command:whatis fnptr +// gdb-check:type = void (*)(void) // gdb-command:info functions _yyy // gdb-check:[...]![...]_yyy([...]); // gdb-command:continue @@ -65,6 +67,7 @@ fn main() { let u64: u64 = 64; let f32: f32 = 2.5; let f64: f64 = 3.5; + let fnptr : fn() = _zzz; _zzz(); // #break if 1 == 1 { _yyy(); } } From 3d65c7ff849bea9cd44fc652396d50486396f867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 14 Jul 2015 19:08:08 +0200 Subject: [PATCH 4/4] Create proper debuginfo for closure variables Variables for closures hold a tuple of captured variables, and not the function itself. Fixes #26484 --- .../trans/debuginfo/metadata.rs | 10 ++++++++-- src/test/debuginfo/basic-types-metadata.rs | 2 +- src/test/run-pass/issue-26484.rs | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-26484.rs diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 33f60d7e78d..5f17197a4b9 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -813,8 +813,14 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } ty::TyClosure(def_id, substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let sig = infcx.closure_type(def_id, substs).sig; - subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); + let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); + + prepare_tuple_metadata(cx, + t, + &upvar_types[..], + unique_type_id, + usage_site_span).finalize(cx) } ty::TyStruct(def_id, substs) => { prepare_struct_metadata(cx, diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 1bc2ddef51e..2468150a6a5 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -43,7 +43,7 @@ // gdb-command:whatis f64 // gdb-check:type = f64 // gdb-command:whatis fnptr -// gdb-check:type = void (*)(void) +// gdb-check:type = [...] (*)([...]) // gdb-command:info functions _yyy // gdb-check:[...]![...]_yyy([...]); // gdb-command:continue diff --git a/src/test/run-pass/issue-26484.rs b/src/test/run-pass/issue-26484.rs new file mode 100644 index 00000000000..d3e6fc85f13 --- /dev/null +++ b/src/test/run-pass/issue-26484.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-g + +fn helper bool>(_f: F) { + print!(""); +} + +fn main() { + let cond = 0; + helper(|v| v == cond) +}