Auto merge of #54660 - kennytm:rollup, r=kennytm

Rollup of 8 pull requests

Successful merges:

 - #54564 (Add 1.29.1 release notes)
 - #54567 (Include path in stamp hash for debuginfo tests)
 - #54577 (rustdoc: give proc-macros their own pages)
 - #54590 (std: Don't let `rust_panic` get inlined)
 - #54598 (Remove useless lifetimes from `Pin` `impl`s.)
 - #54604 (Added help message for `self_in_typedefs` feature gate)
 - #54635 (Improve docs for std::io::Seek)
 - #54645 (Compute Android gdb version in compiletest)
This commit is contained in:
bors 2018-09-29 12:35:39 +00:00
commit 9653f79033
24 changed files with 685 additions and 291 deletions

View File

@ -1,3 +1,16 @@
Version 1.29.1 (2018-09-25)
===========================
Security Notes
--------------
- The standard library's `str::repeat` function contained an out of bounds write
caused by an integer overflow. This has been fixed by deterministically
panicking when an overflow happens.
Thank you to Scott McMurray for responsibily disclosing this vulnerability to
us.
Version 1.29.0 (2018-09-13)
==========================

View File

@ -293,21 +293,21 @@ where
}
#[unstable(feature = "pin", issue = "49150")]
impl<'a, P: fmt::Debug> fmt::Debug for Pin<P> {
impl<P: fmt::Debug> fmt::Debug for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.pointer, f)
}
}
#[unstable(feature = "pin", issue = "49150")]
impl<'a, P: fmt::Display> fmt::Display for Pin<P> {
impl<P: fmt::Display> fmt::Display for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.pointer, f)
}
}
#[unstable(feature = "pin", issue = "49150")]
impl<'a, P: fmt::Pointer> fmt::Pointer for Pin<P> {
impl<P: fmt::Pointer> fmt::Pointer for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.pointer, f)
}
@ -319,10 +319,10 @@ impl<'a, P: fmt::Pointer> fmt::Pointer for Pin<P> {
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[unstable(feature = "pin", issue = "49150")]
impl<'a, P, U> CoerceUnsized<Pin<U>> for Pin<P>
impl<P, U> CoerceUnsized<Pin<U>> for Pin<P>
where
P: CoerceUnsized<U>,
{}
#[unstable(feature = "pin", issue = "49150")]
impl<'a, P> Unpin for Pin<P> {}
impl<P> Unpin for Pin<P> {}

View File

@ -539,7 +539,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
.emit();
} else if has_guard && !cx.tcx.allow_bind_by_move_patterns_with_guards() {
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
"cannot bind by-move into a pattern guard");
"cannot bind by-move into a pattern guard");
err.span_label(p.span, "moves value into pattern guard");
if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() {
err.help("add #![feature(bind_by_move_pattern_guards)] to the \

View File

@ -42,8 +42,9 @@ use rustc::lint;
use rustc::hir::def::*;
use rustc::hir::def::Namespace::*;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::ty;
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::session::config::nightly_options;
use rustc::ty;
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
use rustc_metadata::creader::CrateLoader;
@ -1381,6 +1382,9 @@ pub struct Resolver<'a, 'b: 'a> {
/// The current self type if inside an impl (used for better errors).
current_self_type: Option<Ty>,
/// The current self item if inside an ADT (used for better errors).
current_self_item: Option<NodeId>,
/// The idents for the primitive types.
primitive_type_table: PrimitiveTypeTable,
@ -1710,6 +1714,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
current_trait_ref: None,
current_self_type: None,
current_self_item: None,
primitive_type_table: PrimitiveTypeTable::new(),
@ -2186,15 +2191,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
fn resolve_adt(&mut self, item: &Item, generics: &Generics) {
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
let item_def_id = this.definitions.local_def_id(item.id);
if this.session.features_untracked().self_in_typedefs {
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
self.with_current_self_item(item, |this| {
this.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
let item_def_id = this.definitions.local_def_id(item.id);
if this.session.features_untracked().self_in_typedefs {
this.with_self_rib(Def::SelfTy(None, Some(item_def_id)), |this| {
visit::walk_item(this, item);
});
} else {
visit::walk_item(this, item);
});
} else {
visit::walk_item(this, item);
}
}
});
});
}
@ -2435,6 +2442,15 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
result
}
fn with_current_self_item<T, F>(&mut self, self_item: &Item, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
{
let previous_value = replace(&mut self.current_self_item, Some(self_item.id));
let result = f(self);
self.current_self_item = previous_value;
result
}
/// This is called to resolve a trait reference from an `impl` (i.e. `impl Trait for Foo`)
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
@ -3004,6 +3020,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
"traits and impls"
};
err.span_label(span, format!("`Self` is only available in {}", available_in));
if this.current_self_item.is_some() && nightly_options::is_nightly_build() {
err.help("add #![feature(self_in_typedefs)] to the crate attributes \
to enable");
}
return (err, Vec::new());
}
if is_self_value(path, ns) {

View File

@ -17,6 +17,9 @@ use check::FnCtxt;
use hir::def_id::DefId;
use hir::def::Def;
use namespace::Namespace;
use rustc::hir;
use rustc::lint;
use rustc::session::config::nightly_options;
use rustc::ty::subst::{Subst, Substs};
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
@ -28,8 +31,6 @@ use rustc::middle::stability;
use syntax::ast;
use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
use syntax_pos::{Span, symbol::Symbol};
use rustc::hir;
use rustc::lint;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
@ -1073,9 +1074,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.tcx.item_path_str(stable_pick.item.def_id),
));
if ::rustc::session::config::nightly_options::is_nightly_build() {
if nightly_options::is_nightly_build() {
for (candidate, feature) in unstable_candidates {
diag.note(&format!(
diag.help(&format!(
"add #![feature({})] to the crate attributes to enable `{}`",
feature,
self.tcx.item_path_str(candidate.item.def_id),

View File

@ -13,7 +13,7 @@
use std::iter::once;
use syntax::ast;
use syntax::ext::base::MacroKind;
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax_pos::Span;
use rustc::hir;
@ -105,12 +105,12 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa
record_extern_fqn(cx, did, clean::TypeKind::Const);
clean::ConstantItem(build_const(cx, did))
}
// FIXME(misdreavus): if attributes/derives come down here we should probably document them
// separately
// FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty
Def::Macro(did, MacroKind::Bang) => {
record_extern_fqn(cx, did, clean::TypeKind::Macro);
if let Some(mac) = build_macro(cx, did, name) {
clean::MacroItem(mac)
let mac = build_macro(cx, did, name);
if let clean::MacroItem(..) = mac {
record_extern_fqn(cx, did, clean::TypeKind::Macro);
mac
} else {
return None;
}
@ -442,31 +442,41 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static {
}
}
fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option<clean::Macro> {
fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::ItemEnum {
let imported_from = cx.tcx.original_crate_name(did.krate);
let def = match cx.cstore.load_macro_untracked(did, cx.sess()) {
LoadedMacro::MacroDef(macro_def) => macro_def,
// FIXME(jseyfried): document proc macro re-exports
LoadedMacro::ProcMacro(..) => return None,
};
match cx.cstore.load_macro_untracked(did, cx.sess()) {
LoadedMacro::MacroDef(def) => {
let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node {
let tts: Vec<_> = def.stream().into_trees().collect();
tts.chunks(4).map(|arm| arm[0].span()).collect()
} else {
unreachable!()
};
let matchers: hir::HirVec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.node {
let tts: Vec<_> = def.stream().into_trees().collect();
tts.chunks(4).map(|arm| arm[0].span()).collect()
} else {
unreachable!()
};
let source = format!("macro_rules! {} {{\n{}}}",
name.clean(cx),
matchers.iter().map(|span| {
format!(" {} => {{ ... }};\n", span.to_src(cx))
}).collect::<String>());
let source = format!("macro_rules! {} {{\n{}}}",
name.clean(cx),
matchers.iter().map(|span| {
format!(" {} => {{ ... }};\n", span.to_src(cx))
}).collect::<String>());
clean::MacroItem(clean::Macro {
source,
imported_from: Some(imported_from).clean(cx),
})
}
LoadedMacro::ProcMacro(ext) => {
let helpers = match &*ext {
&SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) }
_ => Vec::new(),
};
clean::ProcMacroItem(clean::ProcMacro {
kind: ext.kind(),
helpers,
})
}
}
Some(clean::Macro {
source,
imported_from: Some(imported_from).clean(cx),
})
}
/// A trait's generics clause actually contains all of the predicates for all of

View File

@ -21,6 +21,7 @@ pub use self::Visibility::{Public, Inherited};
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, AttrStyle, Ident};
use syntax::attr;
use syntax::ext::base::MacroKind;
use syntax::source_map::{dummy_spanned, Spanned};
use syntax::ptr::P;
use syntax::symbol::keywords::{self, Keyword};
@ -527,6 +528,7 @@ pub enum ItemEnum {
/// `type`s from an extern block
ForeignTypeItem,
MacroItem(Macro),
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
AssociatedConstItem(Type, Option<String>),
AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
@ -588,6 +590,7 @@ impl Clean<Item> for doctree::Module {
items.extend(self.traits.iter().map(|x| x.clean(cx)));
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
@ -2191,6 +2194,8 @@ pub enum TypeKind {
Typedef,
Foreign,
Macro,
Attr,
Derive,
}
pub trait GetDefId {
@ -3727,7 +3732,12 @@ pub fn register_def(cx: &DocContext, def: Def) -> DefId {
Def::Static(i, _) => (i, TypeKind::Static),
Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"),
TypeKind::Enum),
Def::Macro(i, _) => (i, TypeKind::Macro),
Def::Macro(i, mac_kind) => match mac_kind {
MacroKind::Bang => (i, TypeKind::Macro),
MacroKind::Attr => (i, TypeKind::Attr),
MacroKind::Derive => (i, TypeKind::Derive),
MacroKind::ProcMacroStub => unreachable!(),
},
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
Def::SelfTy(_, Some(impl_def_id)) => {
return impl_def_id
@ -3782,6 +3792,30 @@ impl Clean<Item> for doctree::Macro {
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ProcMacro {
pub kind: MacroKind,
pub helpers: Vec<String>,
}
impl Clean<Item> for doctree::ProcMacro {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: Some(Public),
stability: self.stab.clean(cx),
deprecation: self.depr.clean(cx),
def_id: cx.tcx.hir.local_def_id(self.id),
inner: ProcMacroItem(ProcMacro {
kind: self.kind,
helpers: self.helpers.clean(cx),
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Stability {
pub level: stability::StabilityLevel,

View File

@ -15,6 +15,7 @@ pub use self::StructType::*;
use syntax::ast;
use syntax::ast::{Name, NodeId};
use syntax::attr;
use syntax::ext::base::MacroKind;
use syntax::ptr::P;
use syntax::source_map::Spanned;
use syntax_pos::{self, Span};
@ -46,6 +47,7 @@ pub struct Module {
pub impls: Vec<Impl>,
pub foreigns: Vec<hir::ForeignMod>,
pub macros: Vec<Macro>,
pub proc_macros: Vec<ProcMacro>,
pub is_crate: bool,
}
@ -75,6 +77,7 @@ impl Module {
impls : Vec::new(),
foreigns : Vec::new(),
macros : Vec::new(),
proc_macros: Vec::new(),
is_crate : false,
}
}
@ -264,6 +267,17 @@ pub struct Import {
pub whence: Span,
}
pub struct ProcMacro {
pub name: Name,
pub id: NodeId,
pub kind: MacroKind,
pub helpers: Vec<Name>,
pub attrs: hir::HirVec<ast::Attribute>,
pub whence: Span,
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
}
pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
match *vdata {
hir::VariantData::Struct(..) => Plain,

View File

@ -11,6 +11,7 @@
//! Item types.
use std::fmt;
use syntax::ext::base::MacroKind;
use clean;
/// Item type. Corresponds to `clean::ItemEnum` variants.
@ -19,6 +20,11 @@ use clean;
/// discriminants. JavaScript then is used to decode them into the original value.
/// Consequently, every change to this type should be synchronized to
/// the `itemTypes` mapping table in `static/main.js`.
///
/// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and
/// module headings. If you are adding to this enum and want to ensure that the sidebar also prints
/// a heading, edit the listing in `html/render.rs`, function `sidebar_module`. This uses an
/// ordering based on a helper function inside `item_module`, in the same file.
#[derive(Copy, PartialEq, Clone, Debug)]
pub enum ItemType {
Module = 0,
@ -44,6 +50,8 @@ pub enum ItemType {
ForeignType = 20,
Keyword = 21,
Existential = 22,
ProcAttribute = 23,
ProcDerive = 24,
}
@ -88,6 +96,12 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem(..) => ItemType::Keyword,
clean::ProcMacroItem(ref mac) => match mac.kind {
MacroKind::Bang => ItemType::Macro,
MacroKind::Attr => ItemType::ProcAttribute,
MacroKind::Derive => ItemType::ProcDerive,
MacroKind::ProcMacroStub => unreachable!(),
}
clean::StrippedItem(..) => unreachable!(),
}
}
@ -107,7 +121,9 @@ impl From<clean::TypeKind> for ItemType {
clean::TypeKind::Variant => ItemType::Variant,
clean::TypeKind::Typedef => ItemType::Typedef,
clean::TypeKind::Foreign => ItemType::ForeignType,
clean::TypeKind::Macro => ItemType::Macro,
clean::TypeKind::Macro => ItemType::Macro,
clean::TypeKind::Attr => ItemType::ProcAttribute,
clean::TypeKind::Derive => ItemType::ProcDerive,
}
}
}
@ -138,6 +154,8 @@ impl ItemType {
ItemType::ForeignType => "foreigntype",
ItemType::Keyword => "keyword",
ItemType::Existential => "existential",
ItemType::ProcAttribute => "attr",
ItemType::ProcDerive => "derive",
}
}
@ -166,7 +184,9 @@ impl ItemType {
ItemType::Constant |
ItemType::AssociatedConst => NameSpace::Value,
ItemType::Macro => NameSpace::Macro,
ItemType::Macro |
ItemType::ProcAttribute |
ItemType::ProcDerive => NameSpace::Macro,
ItemType::Keyword => NameSpace::Keyword,
}

View File

@ -56,6 +56,7 @@ use externalfiles::ExternalHtml;
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
use syntax::ext::base::MacroKind;
use syntax::source_map::FileName;
use syntax::feature_gate::UnstableFeatures;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
@ -1595,6 +1596,8 @@ struct AllTypes {
statics: FxHashSet<ItemEntry>,
constants: FxHashSet<ItemEntry>,
keywords: FxHashSet<ItemEntry>,
attributes: FxHashSet<ItemEntry>,
derives: FxHashSet<ItemEntry>,
}
impl AllTypes {
@ -1613,6 +1616,8 @@ impl AllTypes {
statics: new_set(100),
constants: new_set(100),
keywords: new_set(100),
attributes: new_set(100),
derives: new_set(100),
}
}
@ -1634,6 +1639,8 @@ impl AllTypes {
ItemType::Existential => self.existentials.insert(ItemEntry::new(new_url, name)),
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
_ => true,
};
}
@ -1673,6 +1680,8 @@ impl fmt::Display for AllTypes {
print_entries(f, &self.primitives, "Primitives", "primitives")?;
print_entries(f, &self.traits, "Traits", "traits")?;
print_entries(f, &self.macros, "Macros", "macros")?;
print_entries(f, &self.attributes, "Attribute Macros", "attributes")?;
print_entries(f, &self.derives, "Derive Macros", "derives")?;
print_entries(f, &self.functions, "Functions", "functions")?;
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
print_entries(f, &self.existentials, "Existentials", "existentials")?;
@ -2155,6 +2164,12 @@ impl<'a> fmt::Display for Item<'a> {
clean::EnumItem(..) => write!(fmt, "Enum ")?,
clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
clean::MacroItem(..) => write!(fmt, "Macro ")?,
clean::ProcMacroItem(ref mac) => match mac.kind {
MacroKind::Bang => write!(fmt, "Macro ")?,
MacroKind::Attr => write!(fmt, "Attribute Macro ")?,
MacroKind::Derive => write!(fmt, "Derive Macro ")?,
MacroKind::ProcMacroStub => unreachable!(),
}
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
clean::ConstantItem(..) => write!(fmt, "Constant ")?,
@ -2191,6 +2206,7 @@ impl<'a> fmt::Display for Item<'a> {
clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m),
clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p),
clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
item_static(fmt, self.cx, self.item, i),
@ -4079,11 +4095,12 @@ impl<'a> fmt::Display for Sidebar<'a> {
write!(fmt,
"<div class='block version'>\
<p>Version {}</p>\
</div>
<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
version,
it.name.as_ref().unwrap())?;
</div>",
version)?;
}
write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
it.name.as_ref().expect("crates always have a name"))?;
}
write!(fmt, "<div class=\"sidebar-elems\">")?;
@ -4523,6 +4540,8 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
ItemType::Keyword => ("keywords", "Keywords"),
ItemType::Existential => ("existentials", "Existentials"),
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
ItemType::ProcDerive => ("derives", "Derive Macros"),
}
}
@ -4598,6 +4617,39 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
document(w, cx, it)
}
fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &clean::ProcMacro)
-> fmt::Result
{
let name = it.name.as_ref().expect("proc-macros always have names");
match m.kind {
MacroKind::Bang => {
write!(w, "<pre class='rust macro'>")?;
write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
write!(w, "</pre>")?;
}
MacroKind::Attr => {
write!(w, "<pre class='rust attr'>")?;
write!(w, "#[{}]", name)?;
write!(w, "</pre>")?;
}
MacroKind::Derive => {
write!(w, "<pre class='rust derive'>")?;
write!(w, "#[derive({})]", name)?;
if !m.helpers.is_empty() {
writeln!(w, "\n{{")?;
writeln!(w, " // Attributes available to this derive:")?;
for attr in &m.helpers {
writeln!(w, " #[{}]", attr)?;
}
write!(w, "}}")?;
}
write!(w, "</pre>")?;
}
_ => {}
}
document(w, cx, it)
}
fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
it: &clean::Item,
_p: &clean::PrimitiveType) -> fmt::Result {

View File

@ -39,7 +39,10 @@
"associatedconstant",
"union",
"foreigntype",
"keyword"];
"keyword",
"existential",
"attr",
"derive"];
var search_input = document.getElementsByClassName('search-input')[0];

View File

@ -124,6 +124,8 @@ pre {
.content .highlighted.tymethod { background-color: #4950ed; }
.content .highlighted.type { background-color: #38902c; }
.content .highlighted.foreigntype { background-color: #b200d6; }
.content .highlighted.attr,
.content .highlighted.derive,
.content .highlighted.macro { background-color: #217d1c; }
.content .highlighted.constant,
.content .highlighted.static { background-color: #0063cc; }
@ -134,6 +136,8 @@ pre {
.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
.content span.type, .content a.type, .block a.current.type { color: #ff7f00; }
.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #dd7de8; }
.content span.attr, .content a.attr, .block a.current.attr,
.content span.derive, .content a.derive, .block a.current.derive,
.content span.macro, .content a.macro, .block a.current.macro { color: #09bd00; }
.content span.union, .content a.union, .block a.current.union { color: #a6ae37; }
.content span.constant, .content a.constant, .block a.current.constant,

View File

@ -124,6 +124,8 @@ pre {
.content .highlighted.tymethod { background-color: #c6afb3; }
.content .highlighted.type { background-color: #ffc891; }
.content .highlighted.foreigntype { background-color: #f5c4ff; }
.content .highlighted.attr,
.content .highlighted.derive,
.content .highlighted.macro { background-color: #8ce488; }
.content .highlighted.constant,
.content .highlighted.static { background-color: #c3e0ff; }
@ -134,6 +136,8 @@ pre {
.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; }
.content span.type, .content a.type, .block a.current.type { color: #ba5d00; }
.content span.foreigntype, .content a.foreigntype, .block a.current.foreigntype { color: #cd00e2; }
.content span.attr, .content a.attr, .block a.current.attr,
.content span.derive, .content a.derive, .block a.current.derive,
.content span.macro, .content a.macro, .block a.current.macro { color: #068000; }
.content span.union, .content a.union, .block a.current.union { color: #767b27; }
.content span.constant, .content a.constant, .block a.current.constant,

View File

@ -249,6 +249,9 @@ impl<'a> fold::DocFolder for Stripper<'a> {
// tymethods/macros have no control over privacy
clean::MacroItem(..) | clean::TyMethodItem(..) => {}
// Proc-macros are always public
clean::ProcMacroItem(..) => {}
// Primitives are never stripped
clean::PrimitiveItem(..) => {}

View File

@ -15,6 +15,7 @@ use std::mem;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::MacroKind;
use syntax::source_map::Spanned;
use syntax_pos::{self, Span};
@ -168,24 +169,75 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
}
}
pub fn visit_fn(&mut self, item: &hir::Item,
pub fn visit_fn(&mut self, om: &mut Module, item: &hir::Item,
name: ast::Name, fd: &hir::FnDecl,
header: hir::FnHeader,
gen: &hir::Generics,
body: hir::BodyId) -> Function {
body: hir::BodyId) {
debug!("Visiting fn");
Function {
id: item.id,
vis: item.vis.clone(),
stab: self.stability(item.id),
depr: self.deprecation(item.id),
attrs: item.attrs.clone(),
decl: fd.clone(),
name,
whence: item.span,
generics: gen.clone(),
header,
body,
let macro_kind = item.attrs.iter().filter_map(|a| {
if a.check_name("proc_macro") {
Some(MacroKind::Bang)
} else if a.check_name("proc_macro_derive") {
Some(MacroKind::Derive)
} else if a.check_name("proc_macro_attribute") {
Some(MacroKind::Attr)
} else {
None
}
}).next();
match macro_kind {
Some(kind) => {
let name = if kind == MacroKind::Derive {
item.attrs.lists("proc_macro_derive")
.filter_map(|mi| mi.name())
.next()
.expect("proc-macro derives require a name")
} else {
name
};
let mut helpers = Vec::new();
for mi in item.attrs.lists("proc_macro_derive") {
if !mi.check_name("attributes") {
continue;
}
if let Some(list) = mi.meta_item_list() {
for inner_mi in list {
if let Some(name) = inner_mi.name() {
helpers.push(name);
}
}
}
}
om.proc_macros.push(ProcMacro {
name,
id: item.id,
kind,
helpers,
attrs: item.attrs.clone(),
whence: item.span,
stab: self.stability(item.id),
depr: self.deprecation(item.id),
});
}
None => {
om.fns.push(Function {
id: item.id,
vis: item.vis.clone(),
stab: self.stability(item.id),
depr: self.deprecation(item.id),
attrs: item.attrs.clone(),
decl: fd.clone(),
name,
whence: item.span,
generics: gen.clone(),
header,
body,
});
}
}
}
@ -425,7 +477,7 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
hir::ItemKind::Union(ref sd, ref gen) =>
om.unions.push(self.visit_union_data(item, name, sd, gen)),
hir::ItemKind::Fn(ref fd, header, ref gen, body) =>
om.fns.push(self.visit_fn(item, name, &**fd, header, gen, body)),
self.visit_fn(om, item, name, &**fd, header, gen, body),
hir::ItemKind::Ty(ref ty, ref gen) => {
let t = Typedef {
ty: ty.clone(),

View File

@ -1204,8 +1204,8 @@ pub trait Write {
pub trait Seek {
/// Seek to an offset, in bytes, in a stream.
///
/// A seek beyond the end of a stream is allowed, but implementation
/// defined.
/// A seek beyond the end of a stream is allowed, but behavior is defined
/// by the implementation.
///
/// If the seek operation completed successfully,
/// this method returns the new position from the start of the stream.

View File

@ -517,6 +517,7 @@ pub fn update_count_then_panic(msg: Box<dyn Any + Send>) -> ! {
}
/// A private no-mangle function on which to slap yer breakpoints.
#[inline(never)]
#[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {

View File

@ -0,0 +1,37 @@
// Copyright 2018 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.
// no-prefer-dynamic
#![crate_type="proc-macro"]
#![crate_name="some_macros"]
extern crate proc_macro;
use proc_macro::TokenStream;
/// a proc-macro that swallows its input and does nothing.
#[proc_macro]
pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
TokenStream::new()
}
/// a proc-macro attribute that passes its item through verbatim.
#[proc_macro_attribute]
pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
/// a derive attribute that adds nothing to its input.
#[proc_macro_derive(SomeDerive)]
pub fn some_derive(_item: TokenStream) -> TokenStream {
TokenStream::new()
}

View File

@ -0,0 +1,27 @@
// Copyright 2018 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-stage1
// aux-build:proc_macro.rs
// build-aux-docs
// FIXME: if/when proc-macros start exporting their doc attributes across crates, we can turn on
// cross-crate inlining for them
extern crate some_macros;
// @has proc_macro/index.html
// @has - '//a/@href' '../some_macros/macro.some_proc_macro.html'
// @has - '//a/@href' '../some_macros/attr.some_proc_attr.html'
// @has - '//a/@href' '../some_macros/derive.SomeDerive.html'
// @!has proc_macro/macro.some_proc_macro.html
// @!has proc_macro/attr.some_proc_attr.html
// @!has proc_macro/derive.SomeDerive.html
pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive};

View File

@ -0,0 +1,62 @@
// Copyright 2018 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-stage1
#![crate_type="proc-macro"]
#![crate_name="some_macros"]
extern crate proc_macro;
use proc_macro::TokenStream;
// @has some_macros/index.html
// @has - '//h2' 'Macros'
// @has - '//h2' 'Attribute Macros'
// @has - '//h2' 'Derive Macros'
// @!has - '//h2' 'Functions'
// @has some_macros/all.html
// @has - '//a[@href="macro.some_proc_macro.html"]' 'some_proc_macro'
// @has - '//a[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
// @has - '//a[@href="derive.SomeDerive.html"]' 'SomeDerive'
// @!has - '//a/@href' 'fn.some_proc_macro.html'
// @!has - '//a/@href' 'fn.some_proc_attr.html'
// @!has - '//a/@href' 'fn.some_derive.html'
// @has some_macros/index.html '//a/@href' 'macro.some_proc_macro.html'
// @!has - '//a/@href' 'fn.some_proc_macro.html'
// @has some_macros/macro.some_proc_macro.html
// @!has some_macros/fn.some_proc_macro.html
/// a proc-macro that swallows its input and does nothing.
#[proc_macro]
pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
TokenStream::new()
}
// @has some_macros/index.html '//a/@href' 'attr.some_proc_attr.html'
// @!has - '//a/@href' 'fn.some_proc_attr.html'
// @has some_macros/attr.some_proc_attr.html
// @!has some_macros/fn.some_proc_attr.html
/// a proc-macro attribute that passes its item through verbatim.
#[proc_macro_attribute]
pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
// @has some_macros/index.html '//a/@href' 'derive.SomeDerive.html'
// @!has - '//a/@href' 'fn.some_derive.html'
// @has some_macros/derive.SomeDerive.html
// @!has some_macros/fn.some_derive.html
/// a derive attribute that adds nothing to its input.
#[proc_macro_derive(SomeDerive)]
pub fn some_derive(_item: TokenStream) -> TokenStream {
TokenStream::new()
}

View File

@ -3,6 +3,8 @@ error[E0411]: cannot find type `Self` in this scope
|
LL | Cons(T, &'a Self)
| ^^^^ `Self` is only available in traits and impls
|
= help: add #![feature(self_in_typedefs)] to the crate attributes to enable
error: aborting due to previous error

View File

@ -8,5 +8,5 @@ LL | assert_eq!('x'.ipu_flatten(), 1);
= warning: once this method is added to the standard library, the ambiguity may cause an error or change in behavior!
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
= help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method
= note: add #![feature(ipu_flatten)] to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten`
= help: add #![feature(ipu_flatten)] to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten`

View File

@ -278,7 +278,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
}
}
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"));
let target = opt_str2(matches.opt_str("target"));
let android_cross_path = opt_path(matches, "android-cross-path");
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target,
&android_cross_path);
let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
Some("auto") | None => ColorConfig::AutoColor,
@ -318,7 +321,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
runtool: matches.opt_str("runtool"),
host_rustcflags: matches.opt_str("host-rustcflags"),
target_rustcflags: matches.opt_str("target-rustcflags"),
target: opt_str2(matches.opt_str("target")),
target: target,
host: opt_str2(matches.opt_str("host")),
gdb,
gdb_version,
@ -326,7 +329,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
llvm_version: matches.opt_str("llvm-version"),
system_llvm: matches.opt_present("system-llvm"),
android_cross_path: opt_path(matches, "android-cross-path"),
android_cross_path: android_cross_path,
adb_path: opt_str2(matches.opt_str("adb-path")),
adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")),
adb_device_status: opt_str2(matches.opt_str("target")).contains("android")
@ -780,8 +783,18 @@ fn make_test_closure(
}))
}
/// Returns true if the given target is an Android target for the
/// purposes of GDB testing.
fn is_android_gdb_target(target: &String) -> bool {
match &target[..] {
"arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => true,
_ => false,
}
}
/// Returns (Path to GDB, GDB Version, GDB has Rust Support)
fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
fn analyze_gdb(gdb: Option<String>, target: &String, android_cross_path: &PathBuf)
-> (Option<String>, Option<u32>, bool) {
#[cfg(not(windows))]
const GDB_FALLBACK: &str = "gdb";
#[cfg(windows)]
@ -789,14 +802,27 @@ fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
const MIN_GDB_WITH_RUST: u32 = 7011010;
let fallback_gdb = || {
if is_android_gdb_target(target) {
let mut gdb_path = match android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => panic!("cannot find android cross path"),
};
gdb_path.push_str("/bin/gdb");
gdb_path
} else {
GDB_FALLBACK.to_owned()
}
};
let gdb = match gdb {
None => GDB_FALLBACK,
Some(ref s) if s.is_empty() => GDB_FALLBACK, // may be empty if configure found no gdb
Some(ref s) => s,
None => fallback_gdb(),
Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb
Some(ref s) => s.to_owned(),
};
let mut version_line = None;
if let Ok(output) = Command::new(gdb).arg("--version").output() {
if let Ok(output) = Command::new(&gdb).arg("--version").output() {
if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
version_line = Some(first_line.to_string());
}
@ -809,7 +835,7 @@ fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST);
(Some(gdb.to_owned()), version, gdb_native_rust)
(Some(gdb), version, gdb_native_rust)
}
fn extract_gdb_version(full_version_line: &str) -> Option<u32> {

View File

@ -38,6 +38,7 @@ use std::process::{Child, Command, ExitStatus, Output, Stdio};
use std::str;
use extract_gdb_version;
use is_android_gdb_target;
#[cfg(windows)]
fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R {
@ -224,6 +225,19 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
pub fn compute_stamp_hash(config: &Config) -> String {
let mut hash = DefaultHasher::new();
config.stage_id.hash(&mut hash);
match config.mode {
DebugInfoGdb => match config.gdb {
None => env::var_os("PATH").hash(&mut hash),
Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash),
Some(ref s) => s.hash(&mut hash),
},
DebugInfoLldb => {
env::var_os("PATH").hash(&mut hash);
env::var_os("PYTHONPATH").hash(&mut hash);
},
_ => {},
};
format!("{:x}", hash.finish())
}
@ -666,222 +680,217 @@ impl<'test> TestCx<'test> {
let exe_file = self.make_exe_name();
let debugger_run_result;
match &*self.config.target {
"arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => {
cmds = cmds.replace("run", "continue");
if is_android_gdb_target(&self.config.target) {
cmds = cmds.replace("run", "continue");
let tool_path = match self.config.android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => self.fatal("cannot find android cross path"),
};
let tool_path = match self.config.android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => self.fatal("cannot find android cross path"),
};
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str(&format!("set sysroot {}\n", tool_path));
script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
script_str.push_str("target remote :5039\n");
script_str.push_str(&format!(
"set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
self.config.host, self.config.target
));
for line in &breakpoint_lines {
script_str.push_str(
&format!(
"break {:?}:{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
)[..],
);
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let adb_path = &self.config.adb_path;
Command::new(adb_path)
.arg("push")
.arg(&exe_file)
.arg(&self.config.adb_test_dir)
.status()
.expect(&format!("failed to exec `{:?}`", adb_path));
Command::new(adb_path)
.args(&["forward", "tcp:5039", "tcp:5039"])
.status()
.expect(&format!("failed to exec `{:?}`", adb_path));
let adb_arg = format!(
"export LD_LIBRARY_PATH={}; \
gdbserver{} :5039 {}/{}",
self.config.adb_test_dir.clone(),
if self.config.target.contains("aarch64") {
"64"
} else {
""
},
self.config.adb_test_dir.clone(),
exe_file.file_name().unwrap().to_str().unwrap()
);
debug!("adb arg: {}", adb_arg);
let mut adb = Command::new(adb_path)
.args(&["shell", &adb_arg])
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.expect(&format!("failed to exec `{:?}`", adb_path));
// Wait for the gdbserver to print out "Listening on port ..."
// at which point we know that it's started and then we can
// execute the debugger below.
let mut stdout = BufReader::new(adb.stdout.take().unwrap());
let mut line = String::new();
loop {
line.truncate(0);
stdout.read_line(&mut line).unwrap();
if line.starts_with("Listening on port 5039") {
break;
}
}
drop(stdout);
let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts = vec![
"-quiet".to_owned(),
"-batch".to_owned(),
"-nx".to_owned(),
format!("-command={}", debugger_script.to_str().unwrap()),
];
let mut gdb_path = tool_path;
gdb_path.push_str("/bin/gdb");
let Output {
status,
stdout,
stderr,
} = Command::new(&gdb_path)
.args(&debugger_opts)
.output()
.expect(&format!("failed to exec `{:?}`", gdb_path));
let cmdline = {
let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
gdb.args(&debugger_opts);
let cmdline = self.make_cmdline(&gdb, "");
logv(self.config, format!("executing {}", cmdline));
cmdline
};
debugger_run_result = ProcRes {
status,
stdout: String::from_utf8(stdout).unwrap(),
stderr: String::from_utf8(stderr).unwrap(),
cmdline,
};
if adb.kill().is_err() {
println!("Adb process is already finished.");
}
}
_ => {
let rust_src_root = self
.config
.find_rust_src_root()
.expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root
.join(rust_pp_module_rel_path)
.to_str()
.unwrap()
.to_owned();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str("show version\n");
match self.config.gdb_version {
Some(version) => {
println!(
"NOTE: compiletest thinks it is using GDB version {}",
version
);
if version > extract_gdb_version("7.4").unwrap() {
// Add the directory containing the pretty printers to
// GDB's script auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
rust_pp_module_abs_path.replace(r"\", r"\\")
));
}
}
_ => {
println!(
"NOTE: compiletest does not know which version of \
GDB it is using"
);
}
}
// The following line actually doesn't have to do anything with
// pretty printing, it just tells GDB to print values on one line:
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path));
// Load the target executable
script_str.push_str(&format!(
"file {}\n",
exe_file.to_str().unwrap().replace(r"\", r"\\")
));
// Force GDB to print values in the Rust format.
if self.config.gdb_native_rust {
script_str.push_str("set language rust\n");
}
// Add line breakpoints
for line in &breakpoint_lines {
script_str.push_str(&format!(
"break '{}':{}\n",
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str(&format!("set sysroot {}\n", tool_path));
script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
script_str.push_str("target remote :5039\n");
script_str.push_str(&format!(
"set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
self.config.host, self.config.target
));
for line in &breakpoint_lines {
script_str.push_str(
&format!(
"break {:?}:{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
));
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts = vec![
"-quiet".to_owned(),
"-batch".to_owned(),
"-nx".to_owned(),
format!("-command={}", debugger_script.to_str().unwrap()),
];
let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
gdb.args(&debugger_opts)
.env("PYTHONPATH", rust_pp_module_abs_path);
debugger_run_result = self.compose_and_run(
gdb,
self.config.run_lib_path.to_str().unwrap(),
None,
None,
)[..],
);
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let adb_path = &self.config.adb_path;
Command::new(adb_path)
.arg("push")
.arg(&exe_file)
.arg(&self.config.adb_test_dir)
.status()
.expect(&format!("failed to exec `{:?}`", adb_path));
Command::new(adb_path)
.args(&["forward", "tcp:5039", "tcp:5039"])
.status()
.expect(&format!("failed to exec `{:?}`", adb_path));
let adb_arg = format!(
"export LD_LIBRARY_PATH={}; \
gdbserver{} :5039 {}/{}",
self.config.adb_test_dir.clone(),
if self.config.target.contains("aarch64") {
"64"
} else {
""
},
self.config.adb_test_dir.clone(),
exe_file.file_name().unwrap().to_str().unwrap()
);
debug!("adb arg: {}", adb_arg);
let mut adb = Command::new(adb_path)
.args(&["shell", &adb_arg])
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.expect(&format!("failed to exec `{:?}`", adb_path));
// Wait for the gdbserver to print out "Listening on port ..."
// at which point we know that it's started and then we can
// execute the debugger below.
let mut stdout = BufReader::new(adb.stdout.take().unwrap());
let mut line = String::new();
loop {
line.truncate(0);
stdout.read_line(&mut line).unwrap();
if line.starts_with("Listening on port 5039") {
break;
}
}
drop(stdout);
let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts = vec![
"-quiet".to_owned(),
"-batch".to_owned(),
"-nx".to_owned(),
format!("-command={}", debugger_script.to_str().unwrap()),
];
let gdb_path = self.config.gdb.as_ref().unwrap();
let Output {
status,
stdout,
stderr,
} = Command::new(&gdb_path)
.args(&debugger_opts)
.output()
.expect(&format!("failed to exec `{:?}`", gdb_path));
let cmdline = {
let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
gdb.args(&debugger_opts);
let cmdline = self.make_cmdline(&gdb, "");
logv(self.config, format!("executing {}", cmdline));
cmdline
};
debugger_run_result = ProcRes {
status,
stdout: String::from_utf8(stdout).unwrap(),
stderr: String::from_utf8(stderr).unwrap(),
cmdline,
};
if adb.kill().is_err() {
println!("Adb process is already finished.");
}
} else {
let rust_src_root = self
.config
.find_rust_src_root()
.expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root
.join(rust_pp_module_rel_path)
.to_str()
.unwrap()
.to_owned();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str("show version\n");
match self.config.gdb_version {
Some(version) => {
println!(
"NOTE: compiletest thinks it is using GDB version {}",
version
);
if version > extract_gdb_version("7.4").unwrap() {
// Add the directory containing the pretty printers to
// GDB's script auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
rust_pp_module_abs_path.replace(r"\", r"\\")
));
}
}
_ => {
println!(
"NOTE: compiletest does not know which version of \
GDB it is using"
);
}
}
// The following line actually doesn't have to do anything with
// pretty printing, it just tells GDB to print values on one line:
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path));
// Load the target executable
script_str.push_str(&format!(
"file {}\n",
exe_file.to_str().unwrap().replace(r"\", r"\\")
));
// Force GDB to print values in the Rust format.
if self.config.gdb_native_rust {
script_str.push_str("set language rust\n");
}
// Add line breakpoints
for line in &breakpoint_lines {
script_str.push_str(&format!(
"break '{}':{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
));
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
let debugger_opts = vec![
"-quiet".to_owned(),
"-batch".to_owned(),
"-nx".to_owned(),
format!("-command={}", debugger_script.to_str().unwrap()),
];
let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
gdb.args(&debugger_opts)
.env("PYTHONPATH", rust_pp_module_abs_path);
debugger_run_result = self.compose_and_run(
gdb,
self.config.run_lib_path.to_str().unwrap(),
None,
None,
);
}
if !debugger_run_result.status.success() {