From 6b95606a136bad2109253e5e32cc13b7ecbbc49e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 23 Aug 2016 09:07:23 +0300 Subject: [PATCH 01/15] rustc_trans: do not generate allocas for unused locals. --- src/librustc_trans/mir/analyze.rs | 6 ++++++ src/test/run-pass/mir_heavy_promoted.rs | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/run-pass/mir_heavy_promoted.rs diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index e0d959f4774a6..66eb78aef07b4 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -48,6 +48,12 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, common::type_is_fat_ptr(bcx.tcx(), ty)); } else if common::type_is_imm_pair(bcx.ccx(), ty) { // We allow pairs and uses of any of their 2 fields. + } else if !analyzer.seen_assigned.contains(index) { + // No assignment has been seen, which means that + // either the local has been marked as lvalue + // already, or there is no possible initialization + // for the local, making any reads invalid. + // This is useful in weeding out dead temps. } else { // These sorts of types require an alloca. Note that // type_is_immediate() may *still* be true, particularly diff --git a/src/test/run-pass/mir_heavy_promoted.rs b/src/test/run-pass/mir_heavy_promoted.rs new file mode 100644 index 0000000000000..9e033421574b9 --- /dev/null +++ b/src/test/run-pass/mir_heavy_promoted.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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. + +const TEST_DATA: [u8; 32 * 1024 * 1024] = [42; 32 * 1024 * 1024]; + +// Check that the promoted copy of TEST_DATA doesn't +// leave an alloca from an unused temp behind, which, +// without optimizations, can still blow the stack. +fn main() { + println!("{}", TEST_DATA.len()); +} From 892bf3d41d8f1b5c26f19fd0f20edd1584c958a1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Aug 2016 17:26:34 +0200 Subject: [PATCH 02/15] Use a macro in test_decode_utf8 to preserve line numbers in panic messages. --- src/libcoretest/char.rs | 50 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 4632419336d7f..a4406204f1140 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -358,29 +358,31 @@ fn eu_iterator_specializations() { #[test] fn test_decode_utf8() { - use core::char::*; - use core::iter::FromIterator; - - for &(str, bs) in [("", &[] as &[u8]), - ("A", &[0x41u8] as &[u8]), - ("�", &[0xC1u8, 0x81u8] as &[u8]), - ("♥", &[0xE2u8, 0x99u8, 0xA5u8]), - ("♥A", &[0xE2u8, 0x99u8, 0xA5u8, 0x41u8] as &[u8]), - ("�", &[0xE2u8, 0x99u8] as &[u8]), - ("�A", &[0xE2u8, 0x99u8, 0x41u8] as &[u8]), - ("�", &[0xC0u8] as &[u8]), - ("�A", &[0xC0u8, 0x41u8] as &[u8]), - ("�", &[0x80u8] as &[u8]), - ("�A", &[0x80u8, 0x41u8] as &[u8]), - ("�", &[0xFEu8] as &[u8]), - ("�A", &[0xFEu8, 0x41u8] as &[u8]), - ("�", &[0xFFu8] as &[u8]), - ("�A", &[0xFFu8, 0x41u8] as &[u8])].into_iter() { - assert!(Iterator::eq(str.chars(), - decode_utf8(bs.into_iter().map(|&b|b)) - .map(|r_b| r_b.unwrap_or('\u{FFFD}'))), - "chars = {}, bytes = {:?}, decoded = {:?}", str, bs, - Vec::from_iter(decode_utf8(bs.into_iter().map(|&b|b)) - .map(|r_b| r_b.unwrap_or('\u{FFFD}')))); + macro_rules! assert_decode_utf8 { + ($input_bytes: expr, $expected_str: expr) => { + let input_bytes: &[u8] = &$input_bytes; + let s = char::decode_utf8(input_bytes.iter().cloned()) + .map(|r_b| r_b.unwrap_or('\u{FFFD}')) + .collect::(); + assert_eq!(s, $expected_str, + "input bytes: {:?}, expected str: {:?}, result: {:?}", + input_bytes, $expected_str, s); + } } + + assert_decode_utf8!([], ""); + assert_decode_utf8!([0x41], "A"); + assert_decode_utf8!([0xC1, 0x81], "�"); + assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥"); + assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A"); + assert_decode_utf8!([0xE2, 0x99], "�"); + assert_decode_utf8!([0xE2, 0x99, 0x41], "�A"); + assert_decode_utf8!([0xC0], "�"); + assert_decode_utf8!([0xC0, 0x41], "�A"); + assert_decode_utf8!([0x80], "�"); + assert_decode_utf8!([0x80, 0x41], "�A"); + assert_decode_utf8!([0xFE], "�"); + assert_decode_utf8!([0xFE, 0x41], "�A"); + assert_decode_utf8!([0xFF], "�"); + assert_decode_utf8!([0xFF, 0x41], "�A"); } From 46226a7a6e967eaae297c462457df8f2db148565 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Aug 2016 22:09:59 +0200 Subject: [PATCH 03/15] Yield Err in char::decode_utf8 per Unicode, like String::from_utf8_lossy --- src/libcore/char.rs | 82 ++++++++++++++++++++++++++++++++++------- src/libcoretest/char.rs | 21 ++++++++++- 2 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a3440fe8aa644..070ad739fd76f 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -737,25 +737,81 @@ pub struct InvalidSequence(()); impl> Iterator for DecodeUtf8 { type Item = Result; #[inline] + fn next(&mut self) -> Option> { - self.0.next().map(|b| { - if b & 0x80 == 0 { Ok(b as char) } else { - let l = (!b).leading_zeros() as usize; // number of bytes in UTF-8 representation - if l < 2 || l > 6 { return Err(InvalidSequence(())) }; - let mut x = (b as u32) & (0x7F >> l); - for _ in 0..l-1 { + self.0.next().map(|first_byte| { + // Emit InvalidSequence according to + // Unicode §5.22 Best Practice for U+FFFD Substitution + // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 + + // Roughly: consume at least one byte, + // then validate one byte at a time and stop before the first unexpected byte + // (which might be the valid start of the next byte sequence). + + let mut code_point; + macro_rules! first_byte { + ($mask: expr) => { + code_point = u32::from(first_byte & $mask) + } + } + macro_rules! continuation_byte { + () => { continuation_byte!(0x80...0xBF) }; + ($range: pat) => { match self.0.peek() { - Some(&b) if b & 0xC0 == 0x80 => { + Some(&byte @ $range) => { + code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); self.0.next(); - x = (x << 6) | (b as u32) & 0x3F; - }, - _ => return Err(InvalidSequence(())), + } + _ => return Err(InvalidSequence(())) } } - match from_u32(x) { - Some(x) if l == x.len_utf8() => Ok(x), - _ => Err(InvalidSequence(())), + } + + match first_byte { + 0x00...0x7F => { + first_byte!(0b1111_1111); + } + 0xC2...0xDF => { + first_byte!(0b0001_1111); + continuation_byte!(); + } + 0xE0 => { + first_byte!(0b0000_1111); + continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(); } + 0xE1...0xEC | 0xEE...0xEF => { + first_byte!(0b0000_1111); + continuation_byte!(); + continuation_byte!(); + } + 0xED => { + first_byte!(0b0000_1111); + continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(); + } + 0xF0 => { + first_byte!(0b0000_0111); + continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(); + continuation_byte!(); + } + 0xF1...0xF3 => { + first_byte!(0b0000_0111); + continuation_byte!(); + continuation_byte!(); + continuation_byte!(); + } + 0xF4 => { + first_byte!(0b0000_0111); + continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(); + continuation_byte!(); + } + _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX + } + unsafe { + Ok(from_u32_unchecked(code_point)) } }) } diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index a4406204f1140..333503d738943 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -367,12 +367,13 @@ fn test_decode_utf8() { assert_eq!(s, $expected_str, "input bytes: {:?}, expected str: {:?}, result: {:?}", input_bytes, $expected_str, s); + assert_eq!(String::from_utf8_lossy(&$input_bytes), $expected_str); } } assert_decode_utf8!([], ""); assert_decode_utf8!([0x41], "A"); - assert_decode_utf8!([0xC1, 0x81], "�"); + assert_decode_utf8!([0xC1, 0x81], "��"); assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥"); assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A"); assert_decode_utf8!([0xE2, 0x99], "�"); @@ -385,4 +386,22 @@ fn test_decode_utf8() { assert_decode_utf8!([0xFE, 0x41], "�A"); assert_decode_utf8!([0xFF], "�"); assert_decode_utf8!([0xFF, 0x41], "�A"); + assert_decode_utf8!([0xC0, 0x80], "��"); + + // Surrogates + assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}"); + assert_decode_utf8!([0xED, 0xA0, 0x80], "���"); + assert_decode_utf8!([0xED, 0xBF, 0x80], "���"); + assert_decode_utf8!([0xEE, 0x80, 0x80], "\u{E000}"); + + // char::MAX + assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0xBF], "\u{10FFFF}"); + assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0x41], "�A"); + assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "����"); + + // 5 and 6 bytes sequence + // Part of the original design of UTF-8, + // but invalid now that UTF-8 is artificially restricted to match the range of UTF-16. + assert_decode_utf8!([0xF8, 0x80, 0x80, 0x80, 0x80], "�����"); + assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "������"); } From 2655c89549d08a8fa8e90cc53591f7dc4794513c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 21:27:20 -0400 Subject: [PATCH 04/15] Use idiomatic names for string-related methods names. --- src/librbml/lib.rs | 8 ++++---- src/librustc/lint/context.rs | 6 +++--- src/librustc/lint/mod.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/librustc_metadata/decoder.rs | 34 ++++++++++++++++---------------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 4edbeab5dfb11..1825a892cf554 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -173,12 +173,12 @@ impl<'doc> Doc<'doc> { self.start == self.end } - pub fn as_str_slice(&self) -> &'doc str { + pub fn as_str(&self) -> &'doc str { str::from_utf8(&self.data[self.start..self.end]).unwrap() } - pub fn as_str(&self) -> String { - self.as_str_slice().to_string() + pub fn to_string(&self) -> String { + self.as_str().to_string() } } @@ -773,7 +773,7 @@ pub mod reader { Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap()) } fn read_str(&mut self) -> DecodeResult { - Ok(self.next_doc(EsStr)?.as_str()) + Ok(self.next_doc(EsStr)?.to_string()) } // Compound types: diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index daac315e14def..29bcc1257fd31 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -601,7 +601,7 @@ pub trait LintContext: Sized { for (lint_id, level, span) in v { let (now, now_source) = self.lints().get_level_source(lint_id); if now == Forbid && level != Forbid { - let lint_name = lint_id.as_str(); + let lint_name = lint_id.to_string(); let mut diag_builder = struct_span_err!(self.sess(), span, E0453, "{}({}) overruled by outer forbid({})", level.as_str(), lint_name, @@ -1216,7 +1216,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for &(lint, span, ref msg) in v { span_bug!(span, "unprocessed lint {} at {}: {}", - lint.as_str(), tcx.map.node_to_string(*id), *msg) + lint.to_string(), tcx.map.node_to_string(*id), *msg) } } @@ -1252,7 +1252,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // in the iteration code. for (_, v) in sess.lints.borrow().iter() { for &(lint, span, ref msg) in v { - span_bug!(span, "unprocessed lint {}: {}", lint.as_str(), *msg) + span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg) } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index f34b14224f779..0938086b000c0 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -263,7 +263,7 @@ impl LintId { } /// Get the name of the lint. - pub fn as_str(&self) -> String { + pub fn to_string(&self) -> String { self.lint.name_lower() } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f57ae2941838..4e87c931cc19d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -861,7 +861,7 @@ Available lint options: for (name, to) in lints { let name = name.to_lowercase().replace("_", "-"); let desc = to.into_iter() - .map(|x| x.as_str().replace("_", "-")) + .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); println!(" {} {}", padded(&name[..]), desc); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d63e0866a9d6b..ca7f81db6923e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -86,7 +86,7 @@ pub fn load_index(data: &[u8]) -> index::Index { pub fn crate_rustc_version(data: &[u8]) -> Option { let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str()) + reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string()) } pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { @@ -207,7 +207,7 @@ fn item_defaultness(item: rbml::Doc) -> hir::Defaultness { fn item_sort(item: rbml::Doc) -> Option { reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { - doc.as_str_slice().as_bytes()[0] as char + doc.as_str().as_bytes()[0] as char }) } @@ -282,7 +282,7 @@ fn item_name(item: rbml::Doc) -> ast::Name { fn maybe_item_name(item: rbml::Doc) -> Option { reader::maybe_get_doc(item, tag_paths_data_name).map(|name| { - let string = name.as_str_slice(); + let string = name.as_str(); token::intern(string) }) } @@ -368,7 +368,7 @@ fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity { fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { let names_doc = reader::get_doc(item_doc, tag_associated_type_names); reader::tagged_docs(names_doc, tag_associated_type_name) - .map(|name_doc| token::intern(name_doc.as_str_slice())) + .map(|name_doc| token::intern(name_doc.as_str())) .collect() } @@ -682,7 +682,7 @@ fn each_child_of_item_or_crate(cdata: Cmd, let name_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_name); - let name = name_doc.as_str_slice(); + let name = name_doc.as_str(); // This reexport may be in yet another crate. let crate_data = if child_def_id.krate == cdata.cnum { @@ -869,7 +869,7 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { } let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); - let string = explicit_self_doc.as_str_slice(); + let string = explicit_self_doc.as_str(); let explicit_self_kind = string.as_bytes()[0]; match explicit_self_kind as char { @@ -1124,19 +1124,19 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { fn get_meta_items(md: rbml::Doc) -> Vec> { reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); attr::mk_word_item(n) }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = token::intern_and_get_ident(nd.as_str_slice()); - let v = token::intern_and_get_ident(vd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); + let v = token::intern_and_get_ident(vd.as_str()); // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants, // but currently the encoder just drops them attr::mk_name_value_item_str(n, v) })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str_slice()); + let n = token::intern_and_get_ident(nd.as_str()); let subitems = get_meta_items(meta_item_doc); attr::mk_list_item(n, subitems) })).collect() @@ -1191,7 +1191,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { fn docstr(doc: rbml::Doc, tag_: usize) -> String { let d = reader::get_doc(doc, tag_); - d.as_str_slice().to_string() + d.as_str().to_string() } reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { @@ -1233,14 +1233,14 @@ pub fn get_crate_hash(data: &[u8]) -> Svh { pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { - doc.as_str_slice() + doc.as_str() }) } pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { let crate_doc = rbml::Doc::new(data); let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); - let slice: &'a str = disambiguator_doc.as_str_slice(); + let slice: &'a str = disambiguator_doc.as_str(); slice } @@ -1446,8 +1446,8 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) tag_dylib_dependency_formats); let mut result = Vec::new(); - debug!("found dylib deps: {}", formats.as_str_slice()); - for spec in formats.as_str_slice().split(',') { + debug!("found dylib deps: {}", formats.as_str()); + for spec in formats.as_str().split(',') { if spec.is_empty() { continue } let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); @@ -1476,7 +1476,7 @@ pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { match reader::maybe_get_doc(method_doc, tag_method_argument_names) { Some(args_doc) => { reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { - name_doc.as_str_slice().to_string() + name_doc.as_str().to_string() }).collect() }, None => vec![], @@ -1641,7 +1641,7 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { let mut decoder = reader::Decoder::new(def_key_doc); let simple_key = def_key::DefKey::decode(&mut decoder).unwrap(); let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| { - token::intern(name.as_str_slice()).as_str() + token::intern(name.as_str()).as_str() }); def_key::recover_def_key(simple_key, name) } From 19aae8e06990af5821c450594a340d90a746fa1b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 21:34:53 -0400 Subject: [PATCH 05/15] Reuse iterator to avoid unnecessary creation. --- src/librustc_metadata/decoder.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ca7f81db6923e..b0335258b4041 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1449,8 +1449,9 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) debug!("found dylib deps: {}", formats.as_str()); for spec in formats.as_str().split(',') { if spec.is_empty() { continue } - let cnum = spec.split(':').nth(0).unwrap(); - let link = spec.split(':').nth(1).unwrap(); + let mut split = spec.split(':'); + let cnum = split.next().unwrap(); + let link = split.next().unwrap(); let cnum: ast::CrateNum = cnum.parse().unwrap(); let cnum = cdata.cnum_map.borrow()[cnum]; result.push((cnum, if link == "d" { From 28ecfb691d4690ac8f3f6a2fb7d390a1f4abbbb0 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 13:36:52 -0400 Subject: [PATCH 06/15] =?UTF-8?q?Move=20ItemEnum=20=E2=86=92=20Generics=20?= =?UTF-8?q?logic=20into=20method=20on=20ItemEnum.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustdoc/clean/mod.rs | 17 +++++++++++++++++ src/librustdoc/html/render.rs | 13 ++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 39b1a04e98e69..7a4558d7b79e4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -380,6 +380,23 @@ pub enum ItemEnum { StrippedItem(Box), } +impl ItemEnum { + pub fn generics(&self) -> Option<&Generics> { + Some(match *self { + ItemEnum::StructItem(ref s) => &s.generics, + ItemEnum::EnumItem(ref e) => &e.generics, + ItemEnum::FunctionItem(ref f) => &f.generics, + ItemEnum::TypedefItem(ref t, _) => &t.generics, + ItemEnum::TraitItem(ref t) => &t.generics, + ItemEnum::ImplItem(ref i) => &i.generics, + ItemEnum::TyMethodItem(ref i) => &i.generics, + ItemEnum::MethodItem(ref i) => &i.generics, + ItemEnum::ForeignFunctionItem(ref f) => &f.generics, + _ => return None, + }) + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Module { pub items: Vec, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e02cfb96dddf1..289b967333573 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -997,17 +997,8 @@ impl DocFolder for Cache { // Register any generics to their corresponding string. This is used // when pretty-printing types - match item.inner { - clean::StructItem(ref s) => self.generics(&s.generics), - clean::EnumItem(ref e) => self.generics(&e.generics), - clean::FunctionItem(ref f) => self.generics(&f.generics), - clean::TypedefItem(ref t, _) => self.generics(&t.generics), - clean::TraitItem(ref t) => self.generics(&t.generics), - clean::ImplItem(ref i) => self.generics(&i.generics), - clean::TyMethodItem(ref i) => self.generics(&i.generics), - clean::MethodItem(ref i) => self.generics(&i.generics), - clean::ForeignFunctionItem(ref f) => self.generics(&f.generics), - _ => {} + if let Some(generics) = item.inner.generics() { + self.generics(generics); } if !self.seen_mod { From 7dc411667a313f438f9edecb0b19b58d17596915 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 14:22:08 -0400 Subject: [PATCH 07/15] Migrate Context::maybe_ignore_item method to standalone function. The method wasn't using any `self` data from Context, so it seemed miseading to implement it as a method. --- src/librustdoc/html/render.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 289b967333573..5b878c22e79b4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1353,7 +1353,7 @@ impl Context { // these modules are recursed into, but not rendered normally // (a flag on the context). if !self.render_redirect_pages { - self.render_redirect_pages = self.maybe_ignore_item(&item); + self.render_redirect_pages = maybe_ignore_item(&item); } if item.is_mod() { @@ -1436,7 +1436,7 @@ impl Context { // BTreeMap instead of HashMap to get a sorted output let mut map = BTreeMap::new(); for item in &m.items { - if self.maybe_ignore_item(item) { continue } + if maybe_ignore_item(item) { continue } let short = item_type(item).css_class(); let myname = match item.name { @@ -1453,17 +1453,6 @@ impl Context { } return map; } - - fn maybe_ignore_item(&self, it: &clean::Item) -> bool { - match it.inner { - clean::StrippedItem(..) => true, - clean::ModuleItem(ref m) => { - it.doc_value().is_none() && m.items.is_empty() - && it.visibility != Some(clean::Public) - }, - _ => false, - } - } } impl<'a> Item<'a> { @@ -1706,7 +1695,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, if let clean::DefaultImplItem(..) = items[*i].inner { return false; } - !cx.maybe_ignore_item(&items[*i]) + !maybe_ignore_item(&items[*i]) }).collect::>(); // the order of item types in the listing @@ -1854,6 +1843,17 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, Ok(()) } +fn maybe_ignore_item(it: &clean::Item) -> bool { + match it.inner { + clean::StrippedItem(..) => true, + clean::ModuleItem(ref m) => { + it.doc_value().is_none() && m.items.is_empty() + && it.visibility != Some(clean::Public) + }, + _ => false, + } +} + fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec { let mut stability = vec![]; From 30397aee0ddb1a835aefa7e786810acadde53388 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 14:22:16 -0400 Subject: [PATCH 08/15] Migrate ItemType::from_item to convert::From. --- src/librustdoc/clean/mod.rs | 20 ++++++++++---------- src/librustdoc/html/item_type.rs | 6 ++++-- src/librustdoc/html/render.rs | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7a4558d7b79e4..d5149293e099a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -287,34 +287,34 @@ impl Item { } } pub fn is_mod(&self) -> bool { - ItemType::from_item(self) == ItemType::Module + ItemType::from(self) == ItemType::Module } pub fn is_trait(&self) -> bool { - ItemType::from_item(self) == ItemType::Trait + ItemType::from(self) == ItemType::Trait } pub fn is_struct(&self) -> bool { - ItemType::from_item(self) == ItemType::Struct + ItemType::from(self) == ItemType::Struct } pub fn is_enum(&self) -> bool { - ItemType::from_item(self) == ItemType::Module + ItemType::from(self) == ItemType::Module } pub fn is_fn(&self) -> bool { - ItemType::from_item(self) == ItemType::Function + ItemType::from(self) == ItemType::Function } pub fn is_associated_type(&self) -> bool { - ItemType::from_item(self) == ItemType::AssociatedType + ItemType::from(self) == ItemType::AssociatedType } pub fn is_associated_const(&self) -> bool { - ItemType::from_item(self) == ItemType::AssociatedConst + ItemType::from(self) == ItemType::AssociatedConst } pub fn is_method(&self) -> bool { - ItemType::from_item(self) == ItemType::Method + ItemType::from(self) == ItemType::Method } pub fn is_ty_method(&self) -> bool { - ItemType::from_item(self) == ItemType::TyMethod + ItemType::from(self) == ItemType::TyMethod } pub fn is_primitive(&self) -> bool { - ItemType::from_item(self) == ItemType::Primitive + ItemType::from(self) == ItemType::Primitive } pub fn is_stripped(&self) -> bool { match self.inner { StrippedItem(..) => true, _ => false } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 6b462a76f04ed..31d965fccc2c0 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -50,8 +50,8 @@ pub enum NameSpace { Macro, } -impl ItemType { - pub fn from_item(item: &clean::Item) -> ItemType { +impl<'a> From<&'a clean::Item> for ItemType { + fn from(item: &'a clean::Item) -> ItemType { let inner = match item.inner { clean::StrippedItem(box ref item) => item, ref inner@_ => inner, @@ -83,7 +83,9 @@ impl ItemType { clean::StrippedItem(..) => unreachable!(), } } +} +impl ItemType { pub fn from_type_kind(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5b878c22e79b4..66f54587e6b32 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -833,7 +833,7 @@ fn mkdir(path: &Path) -> io::Result<()> { /// Returns a documentation-level item type from the item. fn item_type(item: &clean::Item) -> ItemType { - ItemType::from_item(item) + ItemType::from(item) } /// Takes a path to a source file and cleans the path to it. This canonicalizes From 0c9ff541396285ac441c5029ae4f0869edc97044 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 20 Aug 2016 15:55:43 -0400 Subject: [PATCH 09/15] Migrate ItemType::from_type_kind to convert::From. --- src/librustdoc/html/item_type.rs | 6 ++++-- src/librustdoc/html/render.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 31d965fccc2c0..be19217928467 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -85,8 +85,8 @@ impl<'a> From<&'a clean::Item> for ItemType { } } -impl ItemType { - pub fn from_type_kind(kind: clean::TypeKind) -> ItemType { +impl From for ItemType { + fn from(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, clean::TypeEnum => ItemType::Enum, @@ -99,7 +99,9 @@ impl ItemType { clean::TypeTypedef => ItemType::Typedef, } } +} +impl ItemType { pub fn css_class(&self) -> &'static str { match *self { ItemType::Module => "mod", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 66f54587e6b32..6993f85c3d9a4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -509,7 +509,7 @@ pub fn run(mut krate: clean::Crate, } = renderinfo; let external_paths = external_paths.into_iter() - .map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))) + .map(|(k, (v, t))| (k, (v, ItemType::from(t)))) .collect(); let mut cache = Cache { From 9dde5639908263bb3348616438c59d184fb29530 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 18:48:10 -0400 Subject: [PATCH 10/15] Stop reexporting `PrimitiveType` enum in librustdoc. --- src/librustdoc/clean/mod.rs | 183 +++++++++++++++++----------------- src/librustdoc/html/format.rs | 27 ++--- 2 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d5149293e099a..7e599569a282e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,7 +12,6 @@ //! that clean them. pub use self::Type::*; -pub use self::PrimitiveType::*; pub use self::TypeKind::*; pub use self::VariantKind::*; pub use self::Mutability::*; @@ -1517,12 +1516,12 @@ impl Type { pub fn primitive_type(&self) -> Option { match *self { Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p), - Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice), + Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(PrimitiveType::Slice), FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => { - Some(Array) + Some(PrimitiveType::Array) } - Tuple(..) => Some(PrimitiveTuple), - RawPointer(..) => Some(PrimitiveRawPointer), + Tuple(..) => Some(PrimitiveType::PrimitiveTuple), + RawPointer(..) => Some(PrimitiveType::PrimitiveRawPointer), _ => None, } } @@ -1547,25 +1546,25 @@ impl GetDefId for Type { impl PrimitiveType { fn from_str(s: &str) -> Option { match s { - "isize" => Some(Isize), - "i8" => Some(I8), - "i16" => Some(I16), - "i32" => Some(I32), - "i64" => Some(I64), - "usize" => Some(Usize), - "u8" => Some(U8), - "u16" => Some(U16), - "u32" => Some(U32), - "u64" => Some(U64), - "bool" => Some(Bool), - "char" => Some(Char), - "str" => Some(Str), - "f32" => Some(F32), - "f64" => Some(F64), - "array" => Some(Array), - "slice" => Some(Slice), - "tuple" => Some(PrimitiveTuple), - "pointer" => Some(PrimitiveRawPointer), + "isize" => Some(PrimitiveType::Isize), + "i8" => Some(PrimitiveType::I8), + "i16" => Some(PrimitiveType::I16), + "i32" => Some(PrimitiveType::I32), + "i64" => Some(PrimitiveType::I64), + "usize" => Some(PrimitiveType::Usize), + "u8" => Some(PrimitiveType::U8), + "u16" => Some(PrimitiveType::U16), + "u32" => Some(PrimitiveType::U32), + "u64" => Some(PrimitiveType::U64), + "bool" => Some(PrimitiveType::Bool), + "char" => Some(PrimitiveType::Char), + "str" => Some(PrimitiveType::Str), + "f32" => Some(PrimitiveType::F32), + "f64" => Some(PrimitiveType::F64), + "array" => Some(PrimitiveType::Array), + "slice" => Some(PrimitiveType::Slice), + "tuple" => Some(PrimitiveType::PrimitiveTuple), + "pointer" => Some(PrimitiveType::PrimitiveRawPointer), _ => None, } } @@ -1585,25 +1584,25 @@ impl PrimitiveType { pub fn to_string(&self) -> &'static str { match *self { - Isize => "isize", - I8 => "i8", - I16 => "i16", - I32 => "i32", - I64 => "i64", - Usize => "usize", - U8 => "u8", - U16 => "u16", - U32 => "u32", - U64 => "u64", - F32 => "f32", - F64 => "f64", - Str => "str", - Bool => "bool", - Char => "char", - Array => "array", - Slice => "slice", - PrimitiveTuple => "tuple", - PrimitiveRawPointer => "pointer", + PrimitiveType::Isize => "isize", + PrimitiveType::I8 => "i8", + PrimitiveType::I16 => "i16", + PrimitiveType::I32 => "i32", + PrimitiveType::I64 => "i64", + PrimitiveType::Usize => "usize", + PrimitiveType::U8 => "u8", + PrimitiveType::U16 => "u16", + PrimitiveType::U32 => "u32", + PrimitiveType::U64 => "u64", + PrimitiveType::F32 => "f32", + PrimitiveType::F64 => "f64", + PrimitiveType::Str => "str", + PrimitiveType::Bool => "bool", + PrimitiveType::Char => "char", + PrimitiveType::Array => "array", + PrimitiveType::Slice => "slice", + PrimitiveType::PrimitiveTuple => "tuple", + PrimitiveType::PrimitiveRawPointer => "pointer", } } @@ -1771,21 +1770,21 @@ impl<'tcx> Clean for ty::Ty<'tcx> { fn clean(&self, cx: &DocContext) -> Type { match self.sty { ty::TyNever => Never, - ty::TyBool => Primitive(Bool), - ty::TyChar => Primitive(Char), - ty::TyInt(ast::IntTy::Is) => Primitive(Isize), - ty::TyInt(ast::IntTy::I8) => Primitive(I8), - ty::TyInt(ast::IntTy::I16) => Primitive(I16), - ty::TyInt(ast::IntTy::I32) => Primitive(I32), - ty::TyInt(ast::IntTy::I64) => Primitive(I64), - ty::TyUint(ast::UintTy::Us) => Primitive(Usize), - ty::TyUint(ast::UintTy::U8) => Primitive(U8), - ty::TyUint(ast::UintTy::U16) => Primitive(U16), - ty::TyUint(ast::UintTy::U32) => Primitive(U32), - ty::TyUint(ast::UintTy::U64) => Primitive(U64), - ty::TyFloat(ast::FloatTy::F32) => Primitive(F32), - ty::TyFloat(ast::FloatTy::F64) => Primitive(F64), - ty::TyStr => Primitive(Str), + ty::TyBool => Primitive(PrimitiveType::Bool), + ty::TyChar => Primitive(PrimitiveType::Char), + ty::TyInt(ast::IntTy::Is) => Primitive(PrimitiveType::Isize), + ty::TyInt(ast::IntTy::I8) => Primitive(PrimitiveType::I8), + ty::TyInt(ast::IntTy::I16) => Primitive(PrimitiveType::I16), + ty::TyInt(ast::IntTy::I32) => Primitive(PrimitiveType::I32), + ty::TyInt(ast::IntTy::I64) => Primitive(PrimitiveType::I64), + ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), + ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), + ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), + ty::TyUint(ast::UintTy::U32) => Primitive(PrimitiveType::U32), + ty::TyUint(ast::UintTy::U64) => Primitive(PrimitiveType::U64), + ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), + ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), + ty::TyStr => Primitive(PrimitiveType::Str), ty::TyBox(t) => { let box_did = cx.tcx_opt().and_then(|tcx| { tcx.lang_items.owned_box() @@ -2438,25 +2437,25 @@ fn build_deref_target_impls(cx: &DocContext, } }; let did = match primitive { - Isize => tcx.lang_items.isize_impl(), - I8 => tcx.lang_items.i8_impl(), - I16 => tcx.lang_items.i16_impl(), - I32 => tcx.lang_items.i32_impl(), - I64 => tcx.lang_items.i64_impl(), - Usize => tcx.lang_items.usize_impl(), - U8 => tcx.lang_items.u8_impl(), - U16 => tcx.lang_items.u16_impl(), - U32 => tcx.lang_items.u32_impl(), - U64 => tcx.lang_items.u64_impl(), - F32 => tcx.lang_items.f32_impl(), - F64 => tcx.lang_items.f64_impl(), - Char => tcx.lang_items.char_impl(), - Bool => None, - Str => tcx.lang_items.str_impl(), - Slice => tcx.lang_items.slice_impl(), - Array => tcx.lang_items.slice_impl(), - PrimitiveTuple => None, - PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), + PrimitiveType::Isize => tcx.lang_items.isize_impl(), + PrimitiveType::I8 => tcx.lang_items.i8_impl(), + PrimitiveType::I16 => tcx.lang_items.i16_impl(), + PrimitiveType::I32 => tcx.lang_items.i32_impl(), + PrimitiveType::I64 => tcx.lang_items.i64_impl(), + PrimitiveType::Usize => tcx.lang_items.usize_impl(), + PrimitiveType::U8 => tcx.lang_items.u8_impl(), + PrimitiveType::U16 => tcx.lang_items.u16_impl(), + PrimitiveType::U32 => tcx.lang_items.u32_impl(), + PrimitiveType::U64 => tcx.lang_items.u64_impl(), + PrimitiveType::F32 => tcx.lang_items.f32_impl(), + PrimitiveType::F64 => tcx.lang_items.f64_impl(), + PrimitiveType::Char => tcx.lang_items.char_impl(), + PrimitiveType::Bool => None, + PrimitiveType::Str => tcx.lang_items.str_impl(), + PrimitiveType::Slice => tcx.lang_items.slice_impl(), + PrimitiveType::Array => tcx.lang_items.slice_impl(), + PrimitiveType::PrimitiveTuple => None, + PrimitiveType::PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { @@ -2739,21 +2738,21 @@ fn resolve_type(cx: &DocContext, let is_generic = match def { Def::PrimTy(p) => match p { - hir::TyStr => return Primitive(Str), - hir::TyBool => return Primitive(Bool), - hir::TyChar => return Primitive(Char), - hir::TyInt(ast::IntTy::Is) => return Primitive(Isize), - hir::TyInt(ast::IntTy::I8) => return Primitive(I8), - hir::TyInt(ast::IntTy::I16) => return Primitive(I16), - hir::TyInt(ast::IntTy::I32) => return Primitive(I32), - hir::TyInt(ast::IntTy::I64) => return Primitive(I64), - hir::TyUint(ast::UintTy::Us) => return Primitive(Usize), - hir::TyUint(ast::UintTy::U8) => return Primitive(U8), - hir::TyUint(ast::UintTy::U16) => return Primitive(U16), - hir::TyUint(ast::UintTy::U32) => return Primitive(U32), - hir::TyUint(ast::UintTy::U64) => return Primitive(U64), - hir::TyFloat(ast::FloatTy::F32) => return Primitive(F32), - hir::TyFloat(ast::FloatTy::F64) => return Primitive(F64), + hir::TyStr => return Primitive(PrimitiveType::Str), + hir::TyBool => return Primitive(PrimitiveType::Bool), + hir::TyChar => return Primitive(PrimitiveType::Char), + hir::TyInt(ast::IntTy::Is) => return Primitive(PrimitiveType::Isize), + hir::TyInt(ast::IntTy::I8) => return Primitive(PrimitiveType::I8), + hir::TyInt(ast::IntTy::I16) => return Primitive(PrimitiveType::I16), + hir::TyInt(ast::IntTy::I32) => return Primitive(PrimitiveType::I32), + hir::TyInt(ast::IntTy::I64) => return Primitive(PrimitiveType::I64), + hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), + hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), + hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), + hir::TyUint(ast::UintTy::U32) => return Primitive(PrimitiveType::U32), + hir::TyUint(ast::UintTy::U64) => return Primitive(PrimitiveType::U64), + hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), + hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), }, Def::SelfTy(..) if path.segments.len() == 1 => { return Generic(keywords::SelfType.name().to_string()); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f8b852074dd2b..2b8db6975f135 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -23,7 +23,7 @@ use rustc::hir::def_id::DefId; use syntax::abi::Abi; use rustc::hir; -use clean; +use clean::{self, PrimitiveType}; use core::DocAccessLevels; use html::item_type::ItemType; use html::escape::Escape; @@ -468,28 +468,28 @@ impl fmt::Display for clean::Type { } clean::Tuple(ref typs) => { match &typs[..] { - &[] => primitive_link(f, clean::PrimitiveTuple, "()"), + &[] => primitive_link(f, PrimitiveType::PrimitiveTuple, "()"), &[ref one] => { - primitive_link(f, clean::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; write!(f, "{},", one)?; - primitive_link(f, clean::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::PrimitiveTuple, ")") } many => { - primitive_link(f, clean::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; write!(f, "{}", CommaSep(&many))?; - primitive_link(f, clean::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::PrimitiveTuple, ")") } } } clean::Vector(ref t) => { - primitive_link(f, clean::Slice, &format!("["))?; + primitive_link(f, PrimitiveType::Slice, &format!("["))?; write!(f, "{}", t)?; - primitive_link(f, clean::Slice, &format!("]")) + primitive_link(f, PrimitiveType::Slice, &format!("]")) } clean::FixedVector(ref t, ref s) => { - primitive_link(f, clean::PrimitiveType::Array, "[")?; + primitive_link(f, PrimitiveType::Array, "[")?; write!(f, "{}", t)?; - primitive_link(f, clean::PrimitiveType::Array, + primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(s))) } clean::Never => f.write_str("!"), @@ -516,12 +516,13 @@ impl fmt::Display for clean::Type { clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T] match **bt { clean::Generic(_) => - primitive_link(f, clean::Slice, + primitive_link(f, PrimitiveType::Slice, &format!("&{}{}[{}]", lt, m, **bt)), _ => { - primitive_link(f, clean::Slice, &format!("&{}{}[", lt, m))?; + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; write!(f, "{}", **bt)?; - primitive_link(f, clean::Slice, "]") + primitive_link(f, PrimitiveType::Slice, "]") } } } From 5c849f4a50a6e6d42776847144e06d1405cb4189 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 18:51:56 -0400 Subject: [PATCH 11/15] Remove unnecessary 'Primitive' prefix on `PrimitiveType` enum variants. --- src/librustdoc/clean/mod.rs | 20 ++++++++++---------- src/librustdoc/html/format.rs | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7e599569a282e..093e6a2adadae 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1485,8 +1485,8 @@ pub enum PrimitiveType { Str, Slice, Array, - PrimitiveTuple, - PrimitiveRawPointer, + Tuple, + RawPointer, } #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] @@ -1520,8 +1520,8 @@ impl Type { FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => { Some(PrimitiveType::Array) } - Tuple(..) => Some(PrimitiveType::PrimitiveTuple), - RawPointer(..) => Some(PrimitiveType::PrimitiveRawPointer), + Tuple(..) => Some(PrimitiveType::Tuple), + RawPointer(..) => Some(PrimitiveType::RawPointer), _ => None, } } @@ -1563,8 +1563,8 @@ impl PrimitiveType { "f64" => Some(PrimitiveType::F64), "array" => Some(PrimitiveType::Array), "slice" => Some(PrimitiveType::Slice), - "tuple" => Some(PrimitiveType::PrimitiveTuple), - "pointer" => Some(PrimitiveType::PrimitiveRawPointer), + "tuple" => Some(PrimitiveType::Tuple), + "pointer" => Some(PrimitiveType::RawPointer), _ => None, } } @@ -1601,8 +1601,8 @@ impl PrimitiveType { PrimitiveType::Char => "char", PrimitiveType::Array => "array", PrimitiveType::Slice => "slice", - PrimitiveType::PrimitiveTuple => "tuple", - PrimitiveType::PrimitiveRawPointer => "pointer", + PrimitiveType::Tuple => "tuple", + PrimitiveType::RawPointer => "pointer", } } @@ -2454,8 +2454,8 @@ fn build_deref_target_impls(cx: &DocContext, PrimitiveType::Str => tcx.lang_items.str_impl(), PrimitiveType::Slice => tcx.lang_items.slice_impl(), PrimitiveType::Array => tcx.lang_items.slice_impl(), - PrimitiveType::PrimitiveTuple => None, - PrimitiveType::PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), + PrimitiveType::Tuple => None, + PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2b8db6975f135..65992798ab099 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -468,16 +468,16 @@ impl fmt::Display for clean::Type { } clean::Tuple(ref typs) => { match &typs[..] { - &[] => primitive_link(f, PrimitiveType::PrimitiveTuple, "()"), + &[] => primitive_link(f, PrimitiveType::Tuple, "()"), &[ref one] => { - primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::Tuple, "(")?; write!(f, "{},", one)?; - primitive_link(f, PrimitiveType::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::Tuple, ")") } many => { - primitive_link(f, PrimitiveType::PrimitiveTuple, "(")?; + primitive_link(f, PrimitiveType::Tuple, "(")?; write!(f, "{}", CommaSep(&many))?; - primitive_link(f, PrimitiveType::PrimitiveTuple, ")") + primitive_link(f, PrimitiveType::Tuple, ")") } } } @@ -496,11 +496,11 @@ impl fmt::Display for clean::Type { clean::RawPointer(m, ref t) => { match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { - primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer, + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{}{}", RawMutableSpace(m), t)) } _ => { - primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer, + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{}", RawMutableSpace(m)))?; write!(f, "{}", t) } From 8a6f7a5ced0217344f2f8a8c6a98aefb08b10fa7 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:12:24 -0400 Subject: [PATCH 12/15] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 093e6a2adadae..3abc7e985366a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1619,6 +1619,17 @@ impl PrimitiveType { } } +impl From for PrimitiveType { + fn from(int_ty: ast::IntTy) -> PrimitiveType { + match int_ty { + ast::IntTy::Is => PrimitiveType::Isize, + ast::IntTy::I8 => PrimitiveType::I8, + ast::IntTy::I16 => PrimitiveType::I16, + ast::IntTy::I32 => PrimitiveType::I32, + ast::IntTy::I64 => PrimitiveType::I64, + } + } +} // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. @@ -1772,11 +1783,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyNever => Never, ty::TyBool => Primitive(PrimitiveType::Bool), ty::TyChar => Primitive(PrimitiveType::Char), - ty::TyInt(ast::IntTy::Is) => Primitive(PrimitiveType::Isize), - ty::TyInt(ast::IntTy::I8) => Primitive(PrimitiveType::I8), - ty::TyInt(ast::IntTy::I16) => Primitive(PrimitiveType::I16), - ty::TyInt(ast::IntTy::I32) => Primitive(PrimitiveType::I32), - ty::TyInt(ast::IntTy::I64) => Primitive(PrimitiveType::I64), + ty::TyInt(int_ty) => Primitive(int_ty.into()), ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), @@ -2741,11 +2748,7 @@ fn resolve_type(cx: &DocContext, hir::TyStr => return Primitive(PrimitiveType::Str), hir::TyBool => return Primitive(PrimitiveType::Bool), hir::TyChar => return Primitive(PrimitiveType::Char), - hir::TyInt(ast::IntTy::Is) => return Primitive(PrimitiveType::Isize), - hir::TyInt(ast::IntTy::I8) => return Primitive(PrimitiveType::I8), - hir::TyInt(ast::IntTy::I16) => return Primitive(PrimitiveType::I16), - hir::TyInt(ast::IntTy::I32) => return Primitive(PrimitiveType::I32), - hir::TyInt(ast::IntTy::I64) => return Primitive(PrimitiveType::I64), + hir::TyInt(int_ty) => return Primitive(int_ty.into()), hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), From 168cfea8afaf2dddae3d848a7f49ecb63d130b47 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:22:18 -0400 Subject: [PATCH 13/15] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3abc7e985366a..4f455e7d073de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1631,6 +1631,18 @@ impl From for PrimitiveType { } } +impl From for PrimitiveType { + fn from(uint_ty: ast::UintTy) -> PrimitiveType { + match uint_ty { + ast::UintTy::Us => PrimitiveType::Usize, + ast::UintTy::U8 => PrimitiveType::U8, + ast::UintTy::U16 => PrimitiveType::U16, + ast::UintTy::U32 => PrimitiveType::U32, + ast::UintTy::U64 => PrimitiveType::U64, + } + } +} + // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. struct SubstAlias<'a, 'tcx: 'a> { @@ -1784,11 +1796,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyBool => Primitive(PrimitiveType::Bool), ty::TyChar => Primitive(PrimitiveType::Char), ty::TyInt(int_ty) => Primitive(int_ty.into()), - ty::TyUint(ast::UintTy::Us) => Primitive(PrimitiveType::Usize), - ty::TyUint(ast::UintTy::U8) => Primitive(PrimitiveType::U8), - ty::TyUint(ast::UintTy::U16) => Primitive(PrimitiveType::U16), - ty::TyUint(ast::UintTy::U32) => Primitive(PrimitiveType::U32), - ty::TyUint(ast::UintTy::U64) => Primitive(PrimitiveType::U64), + ty::TyUint(uint_ty) => Primitive(uint_ty.into()), ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), ty::TyStr => Primitive(PrimitiveType::Str), @@ -2749,11 +2757,7 @@ fn resolve_type(cx: &DocContext, hir::TyBool => return Primitive(PrimitiveType::Bool), hir::TyChar => return Primitive(PrimitiveType::Char), hir::TyInt(int_ty) => return Primitive(int_ty.into()), - hir::TyUint(ast::UintTy::Us) => return Primitive(PrimitiveType::Usize), - hir::TyUint(ast::UintTy::U8) => return Primitive(PrimitiveType::U8), - hir::TyUint(ast::UintTy::U16) => return Primitive(PrimitiveType::U16), - hir::TyUint(ast::UintTy::U32) => return Primitive(PrimitiveType::U32), - hir::TyUint(ast::UintTy::U64) => return Primitive(PrimitiveType::U64), + hir::TyUint(uint_ty) => return Primitive(uint_ty.into()), hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), }, From 42e8ac87eb013f34db5739bf154a383424595077 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 23 Aug 2016 19:41:14 -0400 Subject: [PATCH 14/15] Implement `From` for `PrimitiveType`. --- src/librustdoc/clean/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4f455e7d073de..e2e655ce38bcc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1643,6 +1643,15 @@ impl From for PrimitiveType { } } +impl From for PrimitiveType { + fn from(float_ty: ast::FloatTy) -> PrimitiveType { + match float_ty { + ast::FloatTy::F32 => PrimitiveType::F32, + ast::FloatTy::F64 => PrimitiveType::F64, + } + } +} + // Poor man's type parameter substitution at HIR level. // Used to replace private type aliases in public signatures with their aliased types. struct SubstAlias<'a, 'tcx: 'a> { @@ -1797,8 +1806,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyChar => Primitive(PrimitiveType::Char), ty::TyInt(int_ty) => Primitive(int_ty.into()), ty::TyUint(uint_ty) => Primitive(uint_ty.into()), - ty::TyFloat(ast::FloatTy::F32) => Primitive(PrimitiveType::F32), - ty::TyFloat(ast::FloatTy::F64) => Primitive(PrimitiveType::F64), + ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), ty::TyBox(t) => { let box_did = cx.tcx_opt().and_then(|tcx| { @@ -2758,8 +2766,7 @@ fn resolve_type(cx: &DocContext, hir::TyChar => return Primitive(PrimitiveType::Char), hir::TyInt(int_ty) => return Primitive(int_ty.into()), hir::TyUint(uint_ty) => return Primitive(uint_ty.into()), - hir::TyFloat(ast::FloatTy::F32) => return Primitive(PrimitiveType::F32), - hir::TyFloat(ast::FloatTy::F64) => return Primitive(PrimitiveType::F64), + hir::TyFloat(float_ty) => return Primitive(float_ty.into()), }, Def::SelfTy(..) if path.segments.len() == 1 => { return Generic(keywords::SelfType.name().to_string()); From cf6461168f5a784c996ffd6618d23f33113d2819 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Wed, 24 Aug 2016 19:34:31 -0700 Subject: [PATCH 15/15] Fix debug line info for macro expansions. Macro expansions produce code tagged with debug locations that are completely different from the surrounding expressions. This wrecks havoc on debugger's ability the step over source lines. In order to have a good line stepping behavior in debugger, we overwrite debug locations of macro expansions with that of the outermost expansion site. --- src/librustc/middle/region.rs | 2 +- src/librustc/session/config.rs | 2 + src/librustc_llvm/ffi.rs | 5 + .../debuginfo/create_scope_map.rs | 48 +++++- src/librustc_trans/debuginfo/metadata.rs | 16 +- src/librustc_trans/debuginfo/mod.rs | 3 +- src/librustc_trans/mir/mod.rs | 141 +++++++++++++----- src/rustllvm/RustWrapper.cpp | 9 ++ .../debuginfo/auxiliary/macro-stepping.rs | 20 +++ .../debuginfo/lexical-scope-with-macro.rs | 2 +- src/test/debuginfo/macro-stepping.rs | 103 +++++++++++++ 11 files changed, 298 insertions(+), 53 deletions(-) create mode 100644 src/test/debuginfo/auxiliary/macro-stepping.rs create mode 100644 src/test/debuginfo/macro-stepping.rs diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 6f0ad087dc589..faf2f7dae08c5 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -237,7 +237,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, ..blk.span }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a991a1a9ba4b5..8a32797dbd75a 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -891,6 +891,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "force overflow checks on or off"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments"), + debug_macros: bool = (false, parse_bool, [TRACKED], + "emit line numbers debug info inside macros"), enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED], "force nonzeroing move optimization on"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b2ffcac365bad..754910c246d6f 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1796,6 +1796,11 @@ extern { Col: c_uint) -> DILexicalBlock; + pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef, + Scope: DIScope, + File: DIFile) + -> DILexicalBlock; + pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, Context: DIScope, Name: *const c_char, diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 58cf85747374a..21716d55ac6fa 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -25,11 +25,33 @@ use syntax_pos::Pos; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use syntax_pos::BytePos; + +#[derive(Clone, Copy, Debug)] +pub struct MirDebugScope { + pub scope_metadata: DIScope, + // Start and end offsets of the file to which this DIScope belongs. + // These are used to quickly determine whether some span refers to the same file. + pub file_start_pos: BytePos, + pub file_end_pos: BytePos, +} + +impl MirDebugScope { + pub fn is_valid(&self) -> bool { + !self.scope_metadata.is_null() + } +} + /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. -pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { +pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn"); - let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes); + let null_scope = MirDebugScope { + scope_metadata: ptr::null_mut(), + file_start_pos: BytePos(0), + file_end_pos: BytePos(0) + }; + let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); let fn_metadata = match fcx.debug_context { FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata, @@ -59,8 +81,8 @@ fn make_mir_scope(ccx: &CrateContext, has_variables: &BitVector, fn_metadata: DISubprogram, scope: VisibilityScope, - scopes: &mut IndexVec) { - if !scopes[scope].is_null() { + scopes: &mut IndexVec) { + if scopes[scope].is_valid() { return; } @@ -70,7 +92,12 @@ fn make_mir_scope(ccx: &CrateContext, scopes[parent] } else { // The root is the function itself. - scopes[scope] = fn_metadata; + let loc = span_start(ccx, mir.span); + scopes[scope] = MirDebugScope { + scope_metadata: fn_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; return; }; @@ -81,20 +108,25 @@ fn make_mir_scope(ccx: &CrateContext, // However, we don't skip creating a nested scope if // our parent is the root, because we might want to // put arguments in the root and not have shadowing. - if parent_scope != fn_metadata { + if parent_scope.scope_metadata != fn_metadata { scopes[scope] = parent_scope; return; } } let loc = span_start(ccx, scope_data.span); - scopes[scope] = unsafe { let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path); + let scope_metadata = unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(ccx), - parent_scope, + parent_scope.scope_metadata, file_metadata, loc.line as c_uint, loc.col.to_usize() as c_uint) }; + scopes[scope] = MirDebugScope { + scope_metadata: scope_metadata, + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_pos, + }; } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index ba91b44343868..fccb326b23221 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -22,7 +22,7 @@ use context::SharedCrateContext; use session::Session; use llvm::{self, ValueRef}; -use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; +use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; @@ -1839,3 +1839,17 @@ pub fn create_global_var_metadata(cx: &CrateContext, ptr::null_mut()); } } + +// Creates an "extension" of an existing DIScope into another file. +pub fn extend_scope_to_file(ccx: &CrateContext, + scope_metadata: DIScope, + file: &syntax_pos::FileMap) + -> DILexicalBlock { + let file_metadata = file_metadata(ccx, &file.name, &file.abs_path); + unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlockFile( + DIB(ccx), + scope_metadata, + file_metadata) + } +} \ No newline at end of file diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index cbf423b0739a3..58425cf60d550 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -53,9 +53,10 @@ pub mod metadata; mod create_scope_map; mod source_loc; -pub use self::create_scope_map::create_mir_scopes; +pub use self::create_scope_map::{create_mir_scopes, MirDebugScope}; pub use self::source_loc::start_emitting_source_locations; pub use self::metadata::create_global_var_metadata; +pub use self::metadata::extend_scope_to_file; #[allow(non_upper_case_globals)] const DW_TAG_auto_variable: c_uint = 0x100; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 474b2552e7079..1934f7b870d18 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -10,18 +10,17 @@ use libc::c_uint; use llvm::{self, ValueRef}; -use llvm::debuginfo::DIScope; use rustc::ty; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use session::config::FullDebugInfo; use base; use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null}; -use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind}; +use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind, FunctionDebugContext}; use machine; use type_of; -use syntax_pos::DUMMY_SP; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use syntax::parse::token::keywords; use std::ops::Deref; @@ -103,12 +102,67 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { locals: IndexVec>, /// Debug information for MIR scopes. - scopes: IndexVec + scopes: IndexVec, } impl<'blk, 'tcx> MirContext<'blk, 'tcx> { - pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc { - DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span) + pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> DebugLoc { + // Bail out if debug info emission is not enabled. + match self.fcx.debug_context { + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + // Can't return DebugLoc::None here because intrinsic::trans_intrinsic_call() + // relies on debug location to obtain span of the call site. + return DebugLoc::ScopeAt(self.scopes[source_info.scope].scope_metadata, + source_info.span); + } + FunctionDebugContext::RegularContext(_) =>{} + } + + // In order to have a good line stepping behavior in debugger, we overwrite debug + // locations of macro expansions with that of the outermost expansion site + // (unless the crate is being compiled with `-Z debug-macros`). + if source_info.span.expn_id == NO_EXPANSION || + source_info.span.expn_id == COMMAND_LINE_EXPN || + self.fcx.ccx.sess().opts.debugging_opts.debug_macros { + + let scope_metadata = self.scope_metadata_for_loc(source_info.scope, + source_info.span.lo); + DebugLoc::ScopeAt(scope_metadata, source_info.span) + } else { + let cm = self.fcx.ccx.sess().codemap(); + // Walk up the macro expansion chain until we reach a non-expanded span. + let mut span = source_info.span; + while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { + if let Some(callsite_span) = cm.with_expn_info(span.expn_id, + |ei| ei.map(|ei| ei.call_site.clone())) { + span = callsite_span; + } else { + break; + } + } + let scope_metadata = self.scope_metadata_for_loc(source_info.scope, span.lo); + // Use span of the outermost call site, while keeping the original lexical scope + DebugLoc::ScopeAt(scope_metadata, span) + } + } + + // DILocations inherit source file name from the parent DIScope. Due to macro expansions + // it may so happen that the current span belongs to a different file than the DIScope + // corresponding to span's containing visibility scope. If so, we need to create a DIScope + // "extension" into that file. + fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos) + -> llvm::debuginfo::DIScope { + let scope_metadata = self.scopes[scope_id].scope_metadata; + if pos < self.scopes[scope_id].file_start_pos || + pos >= self.scopes[scope_id].file_end_pos { + let cm = self.fcx.ccx.sess().codemap(); + debuginfo::extend_scope_to_file(self.fcx.ccx, + scope_metadata, + &cm.lookup_char_pos(pos).file) + } else { + scope_metadata + } } } @@ -155,16 +209,38 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { analyze::cleanup_kinds(bcx, &mir)) }); + // Allocate a `Block` for every basic block + let block_bcxs: IndexVec> = + mir.basic_blocks().indices().map(|bb| { + if bb == mir::START_BLOCK { + fcx.new_block("start") + } else { + fcx.new_block(&format!("{:?}", bb)) + } + }).collect(); + // Compute debuginfo scopes from MIR scopes. let scopes = debuginfo::create_mir_scopes(fcx); + let mut mircx = MirContext { + mir: mir.clone(), + fcx: fcx, + llpersonalityslot: None, + blocks: block_bcxs, + unreachable_block: None, + cleanup_kinds: cleanup_kinds, + landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), + scopes: scopes, + locals: IndexVec::new(), + }; + // Allocate variable and temp allocas - let locals = { - let args = arg_local_refs(&bcx, &mir, &scopes, &lvalue_locals); + mircx.locals = { + let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals); let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| { let ty = bcx.monomorphize(&decl.ty); - let scope = scopes[decl.source_info.scope]; - let dbg = !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo; + let debug_scope = mircx.scopes[decl.source_info.scope]; + let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap(); if !lvalue_locals.contains(local.index()) && !dbg { @@ -173,11 +249,16 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str()); if dbg { - bcx.with_block(|bcx| { - declare_local(bcx, decl.name, ty, scope, - VariableAccess::DirectVariable { alloca: lvalue.llval }, - VariableKind::LocalVariable, decl.source_info.span); - }); + let dbg_loc = mircx.debug_loc(decl.source_info); + if let DebugLoc::ScopeAt(scope, span) = dbg_loc { + bcx.with_block(|bcx| { + declare_local(bcx, decl.name, ty, scope, + VariableAccess::DirectVariable { alloca: lvalue.llval }, + VariableKind::LocalVariable, span); + }); + } else { + panic!("Unexpected"); + } } LocalRef::Lvalue(lvalue) }); @@ -203,18 +284,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { })).collect() }; - // Allocate a `Block` for every basic block - let block_bcxs: IndexVec> = - mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - fcx.new_block("start") - } else { - fcx.new_block(&format!("{:?}", bb)) - } - }).collect(); - // Branch to the START block - let start_bcx = block_bcxs[mir::START_BLOCK]; + let start_bcx = mircx.blocks[mir::START_BLOCK]; bcx.br(start_bcx.llbb); // Up until here, IR instructions for this function have explicitly not been annotated with @@ -222,18 +293,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { // emitting should be enabled. debuginfo::start_emitting_source_locations(fcx); - let mut mircx = MirContext { - mir: mir.clone(), - fcx: fcx, - llpersonalityslot: None, - blocks: block_bcxs, - unreachable_block: None, - cleanup_kinds: cleanup_kinds, - landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), - locals: locals, - scopes: scopes - }; - let mut visited = BitVector::new(mir.basic_blocks().len()); let mut rpo = traversal::reverse_postorder(&mir); @@ -271,7 +330,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { /// indirect. fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mir: &mir::Mir<'tcx>, - scopes: &IndexVec, + scopes: &IndexVec, lvalue_locals: &BitVector) -> Vec> { let fcx = bcx.fcx(); @@ -281,8 +340,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, // Get the argument scope, if it exists and if we need it. let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE]; - let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { - Some(arg_scope) + let arg_scope = if arg_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo { + Some(arg_scope.scope_metadata) } else { None }; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 0da25e7ac57b7..82fb2b0918f79 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -521,6 +521,15 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock( )); } +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef File) { + return wrap(Builder->createLexicalBlockFile( + unwrapDI(Scope), + unwrapDI(File))); +} + extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( LLVMRustDIBuilderRef Builder, LLVMRustMetadataRef Context, diff --git a/src/test/debuginfo/auxiliary/macro-stepping.rs b/src/test/debuginfo/auxiliary/macro-stepping.rs new file mode 100644 index 0000000000000..1006b684a8c22 --- /dev/null +++ b/src/test/debuginfo/auxiliary/macro-stepping.rs @@ -0,0 +1,20 @@ +// Copyright 2013-2016 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 + +#![crate_type = "rlib"] + +#[macro_export] +macro_rules! new_scope { + () => { + let x = 1; + } +} diff --git a/src/test/debuginfo/lexical-scope-with-macro.rs b/src/test/debuginfo/lexical-scope-with-macro.rs index a00d0f74f1e4e..eb5798dc7cc48 100644 --- a/src/test/debuginfo/lexical-scope-with-macro.rs +++ b/src/test/debuginfo/lexical-scope-with-macro.rs @@ -10,7 +10,7 @@ // min-lldb-version: 310 -// compile-flags:-g +// compile-flags:-g -Zdebug-macros // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/macro-stepping.rs b/src/test/debuginfo/macro-stepping.rs new file mode 100644 index 0000000000000..52a2a58ed7d27 --- /dev/null +++ b/src/test/debuginfo/macro-stepping.rs @@ -0,0 +1,103 @@ +// Copyright 2013-2016 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. + +// ignore-windows +// ignore-android +// min-lldb-version: 310 + +// aux-build:macro-stepping.rs + +#![allow(unused)] + +#[macro_use] +extern crate macro_stepping; // exports new_scope!() + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc5[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc6[...] + +// === LLDB TESTS ================================================================================== + +// lldb-command:set set stop-line-count-before 0 +// lldb-command:set set stop-line-count-after 1 +// Can't set both to zero or lldb will stop printing source at all. So it will output the current +// line and the next. We deal with this by having at least 2 lines between the #loc's + +// lldb-command:run +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc1[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc2[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc3[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc4[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc5[...] + +macro_rules! foo { + () => { + let a = 1; + let b = 2; + let c = 3; + } +} + +macro_rules! foo2 { + () => { + foo!(); + let x = 1; + foo!(); + } +} + +fn main() { + zzz(); // #break + + foo!(); // #loc1 + + foo2!(); // #loc2 + + let x = vec![42]; // #loc3 + + new_scope!(); // #loc4 + + println!("Hello {}", // #loc5 + "world"); + + zzz(); // #loc6 +} + +fn zzz() {()}