From 24472943ce34e6ed0ac072191f8747de5acb000e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 25 Sep 2018 10:48:07 -0700 Subject: [PATCH 01/16] Add 1.29.1 release nodes Forward-port of #54397, should have included it earlier! --- RELEASES.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 819c9184364..08470e731d8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -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) ========================== From e6ea19d7bd17cf7252d6af90781665d5e87ea156 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 25 Sep 2018 12:27:09 -0600 Subject: [PATCH 02/16] Include path in stamp hash for debuginfo tests The debuginfo tests are exposed to the environment in a couple of ways: the path to the gdb executable matters, as does the Python path used when loading lldb. This patch incorporates these paths into the hash that is written to the stamp file, so that changing the path will cause the tests to be re-run. --- src/tools/compiletest/src/runtest.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 401dec7b184..f1a275b05c9 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -224,6 +224,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()) } From aea1bd0a5908430d41b6f2d38240f2652ef5651f Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 14:56:43 -0500 Subject: [PATCH 03/16] handle proc-macros as macros instead of functions --- src/librustdoc/clean/inline.rs | 61 ++++++++++--------- src/librustdoc/clean/mod.rs | 34 ++++++++++- src/librustdoc/doctree.rs | 13 ++++ src/librustdoc/html/item_type.rs | 24 +++++++- src/librustdoc/html/render.rs | 21 +++++++ src/librustdoc/html/static/main.js | 5 +- src/librustdoc/html/static/themes/dark.css | 4 ++ src/librustdoc/html/static/themes/light.css | 4 ++ src/librustdoc/passes/mod.rs | 3 + src/librustdoc/visit_ast.rs | 66 ++++++++++++++++----- src/test/rustdoc/proc-macro.rs | 54 +++++++++++++++++ 11 files changed, 241 insertions(+), 48 deletions(-) create mode 100644 src/test/rustdoc/proc-macro.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1ea130cf16a..287637ae0da 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -105,15 +105,14 @@ 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 - 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) - } else { - return None; + Def::Macro(did, mac_kind) => { + match mac_kind { + MacroKind::Bang => record_extern_fqn(cx, did, clean::TypeKind::Macro), + MacroKind::Attr => record_extern_fqn(cx, did, clean::TypeKind::Attr), + MacroKind::Derive => record_extern_fqn(cx, did, clean::TypeKind::Derive), + MacroKind::ProcMacroStub => return None, } + build_macro(cx, did, name) } _ => return None, }; @@ -442,31 +441,35 @@ fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { } } -fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> Option { +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 = 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 = 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::()); - let source = format!("macro_rules! {} {{\n{}}}", - name.clean(cx), - matchers.iter().map(|span| { - format!(" {} => {{ ... }};\n", span.to_src(cx)) - }).collect::()); + clean::MacroItem(clean::Macro { + source, + imported_from: Some(imported_from).clean(cx), + }) + } + LoadedMacro::ProcMacro(ext) => { + clean::ProcMacroItem(clean::ProcMacro { + kind: ext.kind(), + }) + } + } - 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 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a982933f6c1..24491115004 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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), AssociatedTypeItem(Vec, Option), @@ -588,6 +590,7 @@ impl Clean 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. @@ -2189,6 +2192,8 @@ pub enum TypeKind { Typedef, Foreign, Macro, + Attr, + Derive, } pub trait GetDefId { @@ -3725,7 +3730,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 @@ -3780,6 +3790,28 @@ impl Clean for doctree::Macro { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct ProcMacro { + pub kind: MacroKind, +} + +impl Clean 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, + }), + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Stability { pub level: stability::StabilityLevel, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index dd1e1e99957..538e61fcb4d 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -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, pub foreigns: Vec, pub macros: Vec, + pub proc_macros: Vec, 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,16 @@ pub struct Import { pub whence: Span, } +pub struct ProcMacro { + pub name: Name, + pub id: NodeId, + pub kind: MacroKind, + pub attrs: hir::HirVec, + pub whence: Span, + pub stab: Option, + pub depr: Option, +} + pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType { match *vdata { hir::VariantData::Struct(..) => Plain, diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index a5131e327e0..acb8f6a66df 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -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 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, } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3e1720f8b8a..dc3255d2e52 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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}; @@ -2155,6 +2156,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 +2198,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), @@ -4523,6 +4531,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 +4608,17 @@ 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 +{ + if m.kind == MacroKind::Bang { + write!(w, "
")?;
+        write!(w, "{}!() {{ /* proc-macro */ }}", it.name.as_ref().unwrap())?;
+        write!(w, "
")?; + } + document(w, cx, it) +} + fn item_primitive(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, _p: &clean::PrimitiveType) -> fmt::Result { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 3dbefabace1..f81391ecefe 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -39,7 +39,10 @@ "associatedconstant", "union", "foreigntype", - "keyword"]; + "keyword", + "existential", + "attr", + "derive"]; var search_input = document.getElementsByClassName('search-input')[0]; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 12d22084893..34a1d71beec 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -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, diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 043d7ae23c2..8218b1b371e 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -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, diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 24fec62dd57..d00eb3257d4 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -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(..) => {} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0e12fd34eb7..dbe25c5ff8a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -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,59 @@ 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 + }; + + om.proc_macros.push(ProcMacro { + name, + id: item.id, + kind, + 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 +461,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(), diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs new file mode 100644 index 00000000000..cdf2783aec7 --- /dev/null +++ b/src/test/rustdoc/proc-macro.rs @@ -0,0 +1,54 @@ +// 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 or the MIT license +// , 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/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() +} From f05b744b083598f3a34d02ac55d27bb144d99e8a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 16:15:32 -0500 Subject: [PATCH 04/16] disable proc-macro re-export inlining Proc-macros don't emit their attributes or source spans across crates. This means that rustdoc can't actually see the docs of a proc-macro if it wasn't defined in the active crate, and attempting to inline it creates an empty page with no docs or source link. In lieu of attempting to fix that immediately, this commit forces proc-macro re-exports to never inline, which at least creates usable links to complete documentation. --- src/librustdoc/clean/inline.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 287637ae0da..4d1b6b8b1a9 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -105,14 +105,15 @@ 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)) } - Def::Macro(did, mac_kind) => { - match mac_kind { - MacroKind::Bang => record_extern_fqn(cx, did, clean::TypeKind::Macro), - MacroKind::Attr => record_extern_fqn(cx, did, clean::TypeKind::Attr), - MacroKind::Derive => record_extern_fqn(cx, did, clean::TypeKind::Derive), - MacroKind::ProcMacroStub => return None, + // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty + Def::Macro(did, MacroKind::Bang) => { + let mac = build_macro(cx, did, name); + if let clean::MacroItem(..) = mac { + record_extern_fqn(cx, did, clean::TypeKind::Macro); + mac + } else { + return None; } - build_macro(cx, did, name) } _ => return None, }; From 8f69a82513d169b8ef57cd885194fd4f9b2d8b65 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 25 Sep 2018 16:30:19 -0500 Subject: [PATCH 05/16] add test for proc-macro re-export --- .../inline_cross/auxiliary/proc_macro.rs | 37 +++++++++++++++++++ src/test/rustdoc/inline_cross/proc_macro.rs | 27 ++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs create mode 100644 src/test/rustdoc/inline_cross/proc_macro.rs diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs new file mode 100644 index 00000000000..6aac070c45b --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -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 or the MIT license +// , 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() +} + diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs new file mode 100644 index 00000000000..a879258f82a --- /dev/null +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -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 or the MIT license +// , 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}; From 869ebc4f9571a58d6af1855791ae15c864ea4bdc Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 26 Sep 2018 09:18:58 -0500 Subject: [PATCH 06/16] add declaration blocks to attribute/derive pages --- src/librustdoc/html/render.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dc3255d2e52..107858ae605 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4611,10 +4611,24 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) -> fmt::Result { - if m.kind == MacroKind::Bang { - write!(w, "
")?;
-        write!(w, "{}!() {{ /* proc-macro */ }}", it.name.as_ref().unwrap())?;
-        write!(w, "
")?; + let name = it.name.as_ref().expect("proc-macros always have names"); + match m.kind { + MacroKind::Bang => { + write!(w, "
")?;
+            write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
+            write!(w, "
")?; + } + MacroKind::Attr => { + write!(w, "
")?;
+            write!(w, "#[{}]", name)?;
+            write!(w, "
")?; + } + MacroKind::Derive => { + write!(w, "
")?;
+            write!(w, "#[derive({})]", name)?;
+            write!(w, "
")?; + } + _ => {} } document(w, cx, it) } From 243030b1408a70f073878e5a206d46d43fc60dab Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 26 Sep 2018 07:48:43 -0700 Subject: [PATCH 07/16] std: Don't let `rust_panic` get inlined It's meant for breakpoints, so if it gets inlined we can't set a breakpoint on it easily! --- src/libstd/panicking.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 6eb2db8e63b..f79c986cc89 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -517,6 +517,7 @@ pub fn update_count_then_panic(msg: Box) -> ! { } /// 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) -> ! { From 27429d94150f2d3a61ab113a9373ec2f063150a0 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 26 Sep 2018 11:29:41 -0500 Subject: [PATCH 08/16] add derive macros' helper attributes to doc output --- src/librustdoc/clean/inline.rs | 8 +++++++- src/librustdoc/clean/mod.rs | 2 ++ src/librustdoc/doctree.rs | 1 + src/librustdoc/html/render.rs | 8 ++++++++ src/librustdoc/visit_ast.rs | 16 ++++++++++++++++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4d1b6b8b1a9..a435712ac3d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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; @@ -465,8 +465,14 @@ fn build_macro(cx: &DocContext, did: DefId, name: ast::Name) -> clean::ItemEnum }) } LoadedMacro::ProcMacro(ext) => { + let helpers = match &*ext { + &SyntaxExtension::ProcMacroDerive(_, ref syms, ..) => { syms.clean(cx) } + _ => Vec::new(), + }; + clean::ProcMacroItem(clean::ProcMacro { kind: ext.kind(), + helpers, }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 24491115004..41c4ee982ff 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3793,6 +3793,7 @@ impl Clean for doctree::Macro { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ProcMacro { pub kind: MacroKind, + pub helpers: Vec, } impl Clean for doctree::ProcMacro { @@ -3807,6 +3808,7 @@ impl Clean for doctree::ProcMacro { def_id: cx.tcx.hir.local_def_id(self.id), inner: ProcMacroItem(ProcMacro { kind: self.kind, + helpers: self.helpers.clean(cx), }), } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 538e61fcb4d..4a6a4ee09ea 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -271,6 +271,7 @@ pub struct ProcMacro { pub name: Name, pub id: NodeId, pub kind: MacroKind, + pub helpers: Vec, pub attrs: hir::HirVec, pub whence: Span, pub stab: Option, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 107858ae605..998a48aca09 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4626,6 +4626,14 @@ fn item_proc_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, m: &c MacroKind::Derive => { write!(w, "
")?;
             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, "
")?; } _ => {} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index dbe25c5ff8a..92d8dbed071 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -197,10 +197,26 @@ impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { 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), From bb0abe98a7ecc92b90b1065e2544c7b25d080edc Mon Sep 17 00:00:00 2001 From: Alexander Ronald Altman Date: Wed, 26 Sep 2018 16:03:05 -0500 Subject: [PATCH 09/16] Remove useless lifetimes from `Pin` `impl`s. --- src/libcore/pin.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index d09a545aecf..0224560af4c 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -293,21 +293,21 @@ where } #[unstable(feature = "pin", issue = "49150")] -impl<'a, P: fmt::Debug> fmt::Debug for Pin

{ +impl fmt::Debug for Pin

{ 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

{ +impl fmt::Display for Pin

{ 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

{ +impl fmt::Pointer for Pin

{ 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

{ // 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> for Pin

+impl CoerceUnsized> for Pin

where P: CoerceUnsized, {} #[unstable(feature = "pin", issue = "49150")] -impl<'a, P> Unpin for Pin

{} +impl

Unpin for Pin

{} From 6bf1aa6ff2f8b401ed93f41bb248389c95458112 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 27 Sep 2018 02:32:55 +0100 Subject: [PATCH 10/16] Added help message for feature gate. --- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_resolve/lib.rs | 38 +++++++++++++++----- src/librustc_typeck/check/method/probe.rs | 9 ++--- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 23667d1b331..6187e091319 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -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 \ diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 91b0e9c1dca..5e3f7470099 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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, + /// The current self item if inside an ADT (used for better errors). + current_self_item: Option, + /// 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(&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(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T where F: FnOnce(&mut Resolver, Option) -> 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) { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 499daccf5e8..ae97cdc85ad 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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), From 4151de43aa51ffa8de8181fb4ed5592b0be0e037 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 27 Sep 2018 04:13:25 +0100 Subject: [PATCH 11/16] Updated stderr test files. --- src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr | 2 ++ src/test/ui/inference/inference_unstable.stderr | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr index 22ca92bbe13..ab04953f3e5 100644 --- a/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr +++ b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr @@ -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 diff --git a/src/test/ui/inference/inference_unstable.stderr b/src/test/ui/inference/inference_unstable.stderr index 3a5cb6f2b2e..2851af4891e 100644 --- a/src/test/ui/inference/inference_unstable.stderr +++ b/src/test/ui/inference/inference_unstable.stderr @@ -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 = 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` From 63ac3c7b94df4931e31472599976cb2a9b10a0d1 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 09:04:38 -0500 Subject: [PATCH 12/16] add attributes/derives to "all items" page --- src/librustdoc/html/render.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 998a48aca09..8adc45ea965 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1596,6 +1596,8 @@ struct AllTypes { statics: FxHashSet, constants: FxHashSet, keywords: FxHashSet, + attributes: FxHashSet, + derives: FxHashSet, } impl AllTypes { @@ -1614,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), } } @@ -1635,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, }; } @@ -1674,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")?; From 967a6b02411f2eecfcc521d4b0129cc6b03d504a Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 09:12:13 -0500 Subject: [PATCH 13/16] show "all items" link even if crate doesn't have a version --- src/librustdoc/html/render.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8adc45ea965..1c61e73fae0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4095,11 +4095,12 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "

\

Version {}

\ -
-

See all {}'s items

", - version, - it.name.as_ref().unwrap())?; + ", + version)?; } + + write!(fmt, "

See all {}'s items

", + it.name.as_ref().expect("crates always have a name"))?; } write!(fmt, "
")?; From d37f3696b167251a96b8f0e4b33336d023daa2c5 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 27 Sep 2018 10:22:29 -0500 Subject: [PATCH 14/16] check for proc-macros in "all items" --- src/test/rustdoc/proc-macro.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index cdf2783aec7..bfd194701c8 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -23,6 +23,14 @@ use proc_macro::TokenStream; // @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 From 5285d35b49e1e8976f2a8d9d2e6f5bd1324016d3 Mon Sep 17 00:00:00 2001 From: Marcus Griep Date: Fri, 28 Sep 2018 08:01:31 -0400 Subject: [PATCH 15/16] Improve docs for std::io::Seek Fixes #54562 --- src/libstd/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 278ee7951b3..e263db24fc2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -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. From e545dc9e2c1fe9852032ee753c0006b25e164d38 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 28 Sep 2018 10:32:59 -0600 Subject: [PATCH 16/16] Compute Android gdb version in compiletest compiletest has special code for running gdb for Android targets. In particular it computes a different path to gdb. However, this gdb is not used for the version test, which results in some tests being run when they should not be. You can see this in #54004. This patch moves the special case to analyze_gdb and a new helper function to decide whether the case applies. This causes the version check to work properly. Note that the bulk of the runtest.rs change is just reindentation caused by moving from a "match" to an "if" -- but there is a (small) change buried in there. --- src/tools/compiletest/src/main.rs | 44 ++- src/tools/compiletest/src/runtest.rs | 416 +++++++++++++-------------- 2 files changed, 241 insertions(+), 219 deletions(-) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a5cf45baa65..2fa459bec94 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -278,7 +278,10 @@ pub fn parse_config(args: Vec) -> 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) -> 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) -> 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) -> (Option, Option, bool) { +fn analyze_gdb(gdb: Option, target: &String, android_cross_path: &PathBuf) + -> (Option, Option, bool) { #[cfg(not(windows))] const GDB_FALLBACK: &str = "gdb"; #[cfg(windows)] @@ -789,14 +802,27 @@ fn analyze_gdb(gdb: Option) -> (Option, Option, 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) -> (Option, Option, 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 { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 306d9f8d852..de3db96155b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -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 R, R>(f: F) -> R { @@ -666,222 +667,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() {