Auto merge of #35979 - Manishearth:rollup, r=Manishearth
Rollup of 6 pull requests - Successful merges: #35238, #35867, #35885, #35916, #35947, #35955 - Failed merges:
This commit is contained in:
commit
17a2be8c35
@ -752,25 +752,81 @@ pub struct InvalidSequence(());
|
||||
impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
|
||||
type Item = Result<char, InvalidSequence>;
|
||||
#[inline]
|
||||
|
||||
fn next(&mut self) -> Option<Result<char, InvalidSequence>> {
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -358,29 +358,50 @@ 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]),
|
||||
("<EFBFBD>", &[0xC1u8, 0x81u8] as &[u8]),
|
||||
("♥", &[0xE2u8, 0x99u8, 0xA5u8]),
|
||||
("♥A", &[0xE2u8, 0x99u8, 0xA5u8, 0x41u8] as &[u8]),
|
||||
("<EFBFBD>", &[0xE2u8, 0x99u8] as &[u8]),
|
||||
("<EFBFBD>A", &[0xE2u8, 0x99u8, 0x41u8] as &[u8]),
|
||||
("<EFBFBD>", &[0xC0u8] as &[u8]),
|
||||
("<EFBFBD>A", &[0xC0u8, 0x41u8] as &[u8]),
|
||||
("<EFBFBD>", &[0x80u8] as &[u8]),
|
||||
("<EFBFBD>A", &[0x80u8, 0x41u8] as &[u8]),
|
||||
("<EFBFBD>", &[0xFEu8] as &[u8]),
|
||||
("<EFBFBD>A", &[0xFEu8, 0x41u8] as &[u8]),
|
||||
("<EFBFBD>", &[0xFFu8] as &[u8]),
|
||||
("<EFBFBD>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::<String>();
|
||||
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], "<EFBFBD><EFBFBD>");
|
||||
assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥");
|
||||
assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A");
|
||||
assert_decode_utf8!([0xE2, 0x99], "<EFBFBD>");
|
||||
assert_decode_utf8!([0xE2, 0x99, 0x41], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0xC0], "<EFBFBD>");
|
||||
assert_decode_utf8!([0xC0, 0x41], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0x80], "<EFBFBD>");
|
||||
assert_decode_utf8!([0x80, 0x41], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0xFE], "<EFBFBD>");
|
||||
assert_decode_utf8!([0xFE, 0x41], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0xFF], "<EFBFBD>");
|
||||
assert_decode_utf8!([0xFF, 0x41], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0xC0, 0x80], "<EFBFBD><EFBFBD>");
|
||||
|
||||
// Surrogates
|
||||
assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}");
|
||||
assert_decode_utf8!([0xED, 0xA0, 0x80], "<EFBFBD><EFBFBD><EFBFBD>");
|
||||
assert_decode_utf8!([0xED, 0xBF, 0x80], "<EFBFBD><EFBFBD><EFBFBD>");
|
||||
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], "<EFBFBD>A");
|
||||
assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
|
||||
// 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], "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||||
}
|
||||
|
@ -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<String> {
|
||||
Ok(self.next_doc(EsStr)?.as_str())
|
||||
Ok(self.next_doc(EsStr)?.to_string())
|
||||
}
|
||||
|
||||
// Compound types:
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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],
|
||||
|
@ -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::<Vec<String>>()
|
||||
.join(", ");
|
||||
println!(" {} {}", padded(&name[..]), desc);
|
||||
|
@ -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,
|
||||
|
@ -86,7 +86,7 @@ pub fn load_index(data: &[u8]) -> index::Index {
|
||||
|
||||
pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
|
||||
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<char> {
|
||||
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<ast::Name> {
|
||||
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<ast::Name> {
|
||||
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<F, G>(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<ast::Name> {
|
||||
fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
|
||||
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<CrateDep> {
|
||||
|
||||
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,11 +1446,12 @@ 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();
|
||||
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" {
|
||||
@ -1476,7 +1477,7 @@ pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
|
||||
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 +1642,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)
|
||||
}
|
||||
|
@ -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<VisibilityScope, DIScope> {
|
||||
pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, MirDebugScope> {
|
||||
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<VisibilityScope, DIScope>) {
|
||||
if !scopes[scope].is_null() {
|
||||
scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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<mir::Local, LocalRef<'tcx>>,
|
||||
|
||||
/// Debug information for MIR scopes.
|
||||
scopes: IndexVec<mir::VisibilityScope, DIScope>
|
||||
scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
|
||||
}
|
||||
|
||||
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::BasicBlock, Block<'blk,'tcx>> =
|
||||
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::BasicBlock, Block<'blk,'tcx>> =
|
||||
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<mir::VisibilityScope, DIScope>,
|
||||
scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
|
||||
lvalue_locals: &BitVector)
|
||||
-> Vec<LocalRef<'tcx>> {
|
||||
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
|
||||
};
|
||||
|
@ -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::*;
|
||||
@ -287,34 +286,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 }
|
||||
@ -380,6 +379,23 @@ pub enum ItemEnum {
|
||||
StrippedItem(Box<ItemEnum>),
|
||||
}
|
||||
|
||||
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<Item>,
|
||||
@ -1469,8 +1485,8 @@ pub enum PrimitiveType {
|
||||
Str,
|
||||
Slice,
|
||||
Array,
|
||||
PrimitiveTuple,
|
||||
PrimitiveRawPointer,
|
||||
Tuple,
|
||||
RawPointer,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
|
||||
@ -1500,12 +1516,12 @@ impl Type {
|
||||
pub fn primitive_type(&self) -> Option<PrimitiveType> {
|
||||
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::Tuple),
|
||||
RawPointer(..) => Some(PrimitiveType::RawPointer),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -1530,25 +1546,25 @@ impl GetDefId for Type {
|
||||
impl PrimitiveType {
|
||||
fn from_str(s: &str) -> Option<PrimitiveType> {
|
||||
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::Tuple),
|
||||
"pointer" => Some(PrimitiveType::RawPointer),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -1568,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::Tuple => "tuple",
|
||||
PrimitiveType::RawPointer => "pointer",
|
||||
}
|
||||
}
|
||||
|
||||
@ -1603,6 +1619,38 @@ impl PrimitiveType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::IntTy> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::UintTy> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::FloatTy> 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.
|
||||
@ -1754,21 +1802,12 @@ impl<'tcx> Clean<Type> 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(int_ty) => Primitive(int_ty.into()),
|
||||
ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
|
||||
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| {
|
||||
tcx.lang_items.owned_box()
|
||||
@ -2421,25 +2460,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::Tuple => None,
|
||||
PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(),
|
||||
};
|
||||
if let Some(did) = did {
|
||||
if !did.is_local() {
|
||||
@ -2722,21 +2761,12 @@ 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(int_ty) => return Primitive(int_ty.into()),
|
||||
hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
|
||||
hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
|
||||
},
|
||||
Def::SelfTy(..) if path.segments.len() == 1 => {
|
||||
return Generic(keywords::SelfType.name().to_string());
|
||||
|
@ -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,39 +468,39 @@ impl fmt::Display for clean::Type {
|
||||
}
|
||||
clean::Tuple(ref typs) => {
|
||||
match &typs[..] {
|
||||
&[] => primitive_link(f, clean::PrimitiveTuple, "()"),
|
||||
&[] => primitive_link(f, PrimitiveType::Tuple, "()"),
|
||||
&[ref one] => {
|
||||
primitive_link(f, clean::PrimitiveTuple, "(")?;
|
||||
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
||||
write!(f, "{},", one)?;
|
||||
primitive_link(f, clean::PrimitiveTuple, ")")
|
||||
primitive_link(f, PrimitiveType::Tuple, ")")
|
||||
}
|
||||
many => {
|
||||
primitive_link(f, clean::PrimitiveTuple, "(")?;
|
||||
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
||||
write!(f, "{}", CommaSep(&many))?;
|
||||
primitive_link(f, clean::PrimitiveTuple, ")")
|
||||
primitive_link(f, PrimitiveType::Tuple, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
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("!"),
|
||||
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)
|
||||
}
|
||||
@ -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, "]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,8 +83,10 @@ impl ItemType {
|
||||
clean::StrippedItem(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_type_kind(kind: clean::TypeKind) -> ItemType {
|
||||
impl From<clean::TypeKind> for ItemType {
|
||||
fn from(kind: clean::TypeKind) -> ItemType {
|
||||
match kind {
|
||||
clean::TypeStruct => ItemType::Struct,
|
||||
clean::TypeEnum => ItemType::Enum,
|
||||
@ -97,7 +99,9 @@ impl ItemType {
|
||||
clean::TypeTypedef => ItemType::Typedef,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemType {
|
||||
pub fn css_class(&self) -> &'static str {
|
||||
match *self {
|
||||
ItemType::Module => "mod",
|
||||
|
@ -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 {
|
||||
@ -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
|
||||
@ -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 {
|
||||
@ -1362,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() {
|
||||
@ -1445,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 {
|
||||
@ -1462,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> {
|
||||
@ -1715,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::<Vec<usize>>();
|
||||
|
||||
// the order of item types in the listing
|
||||
@ -1863,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<String> {
|
||||
let mut stability = vec![];
|
||||
|
||||
|
@ -521,6 +521,15 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock(
|
||||
));
|
||||
}
|
||||
|
||||
extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
|
||||
LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustMetadataRef Scope,
|
||||
LLVMRustMetadataRef File) {
|
||||
return wrap(Builder->createLexicalBlockFile(
|
||||
unwrapDI<DIDescriptor>(Scope),
|
||||
unwrapDI<DIFile>(File)));
|
||||
}
|
||||
|
||||
extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
|
||||
LLVMRustDIBuilderRef Builder,
|
||||
LLVMRustMetadataRef Context,
|
||||
|
20
src/test/debuginfo/auxiliary/macro-stepping.rs
Normal file
20
src/test/debuginfo/auxiliary/macro-stepping.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
// min-lldb-version: 310
|
||||
|
||||
// compile-flags:-g
|
||||
// compile-flags:-g -Zdebug-macros
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
|
103
src/test/debuginfo/macro-stepping.rs
Normal file
103
src/test/debuginfo/macro-stepping.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {()}
|
18
src/test/run-pass/mir_heavy_promoted.rs
Normal file
18
src/test/run-pass/mir_heavy_promoted.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user