From 0da89957f7ba6b08e5caae9de95dcf116009802d Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Tue, 14 Feb 2017 11:05:53 +0100 Subject: [PATCH 01/73] Export attributes in save-analysis data Some annotations like the "test" annotations might be of interest for other projects, especially rls. Export all attributes in a new attributes item. --- src/librustc_save_analysis/data.rs | 12 +- src/librustc_save_analysis/dump_visitor.rs | 14 ++- src/librustc_save_analysis/external_data.rs | 118 +++++++++++++++++++- src/librustc_save_analysis/json_dumper.rs | 12 ++ src/librustc_save_analysis/lib.rs | 21 +++- 5 files changed, 171 insertions(+), 6 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 0a6281bf8c54c..6caf81380e40d 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -15,7 +15,7 @@ use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId}; -use syntax::ast::{self, NodeId}; +use syntax::ast::{self, Attribute, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -136,6 +136,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for extern crates. @@ -171,6 +172,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data about a function call. @@ -256,6 +258,7 @@ pub struct MethodData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for modules. @@ -271,6 +274,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a reference to a module. @@ -295,6 +299,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -309,6 +314,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -323,6 +329,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -337,6 +344,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a typedef. @@ -351,6 +359,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } /// Data for a reference to a type or trait. @@ -396,6 +405,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 41f91a1d2acc1..a4b1d774be7df 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -47,7 +47,8 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs, + remove_docs_from_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::{Lower, make_def_id}; @@ -373,6 +374,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -448,6 +450,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: method_data.sig, + attributes: remove_docs_from_attrs(attrs), }.lower(self.tcx)); } @@ -519,6 +522,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: None, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -592,6 +596,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: None, + attributes: remove_docs_from_attrs(attrs), }.lower(self.tcx)); } @@ -636,6 +641,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -701,6 +707,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: remove_docs_from_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -727,6 +734,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: remove_docs_from_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -813,6 +821,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1079,6 +1088,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -1320,6 +1330,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, parent: None, docs: docs_for_attrs(&item.attrs), sig: Some(self.save_ctxt.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1542,6 +1553,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index fccb56e88b3de..0cfa71a349916 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -11,7 +11,7 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::NodeId; +use syntax::ast::{self, LitKind, NodeId, StrStyle}; use syntax::codemap::CodeMap; use syntax_pos::Span; @@ -64,6 +64,102 @@ impl SpanData { } } +/// Represent an arbitrary attribute on a code element +#[derive(Clone, Debug, RustcEncodable)] +pub struct Attribute { + value: AttributeItem, + span: SpanData, +} + +impl Lower for ast::Attribute { + type Target = Attribute; + + fn lower(self, tcx: TyCtxt) -> Attribute { + Attribute { + value: self.value.lower(tcx), + span: SpanData::from_span(self.span, tcx.sess.codemap()), + } + } +} + +impl Lower for Vec { + type Target = Vec; + + fn lower(self, tcx: TyCtxt) -> Vec { + self.into_iter().map(|x| x.lower(tcx)).collect() + } +} + +/// A single item as part of an attribute +#[derive(Clone, Debug, RustcEncodable)] +pub struct AttributeItem { + name: LitKind, + kind: AttributeItemKind, + span: SpanData, +} + +impl Lower for ast::MetaItem { + type Target = AttributeItem; + + fn lower(self, tcx: TyCtxt) -> AttributeItem { + AttributeItem { + name: LitKind::Str(self.name, StrStyle::Cooked), + kind: self.node.lower(tcx), + span: SpanData::from_span(self.span, tcx.sess.codemap()), + } + } +} + +impl Lower for ast::NestedMetaItem { + type Target = AttributeItem; + + fn lower(self, tcx: TyCtxt) -> AttributeItem { + match self.node { + ast::NestedMetaItemKind::MetaItem(item) => item.lower(tcx), + ast::NestedMetaItemKind::Literal(lit) => { + AttributeItem { + name: lit.node, + kind: AttributeItemKind::Literal, + span: SpanData::from_span(lit.span, tcx.sess.codemap()), + } + } + } + } +} + +#[derive(Clone, Debug, RustcEncodable)] +pub enum AttributeItemKind { + /// Word meta item. + /// + /// E.g. `test` as in `#[test]` + Literal, + /// Name value meta item. + /// + /// E.g. `feature = "foo"` as in `#[feature = "foo"]` + NameValue(LitKind, SpanData), + /// List meta item. + /// + /// E.g. the `derive(..)` as in `#[derive(..)]` + List(Vec), +} + +impl Lower for ast::MetaItemKind { + type Target = AttributeItemKind; + + fn lower(self, tcx: TyCtxt) -> AttributeItemKind { + match self { + ast::MetaItemKind::Word => AttributeItemKind::Literal, + ast::MetaItemKind::List(items) => { + AttributeItemKind::List(items.into_iter().map(|x| x.lower(tcx)).collect()) + } + ast::MetaItemKind::NameValue(lit) => { + let span = SpanData::from_span(lit.span, tcx.sess.codemap()); + AttributeItemKind::NameValue(lit.node, span) + } + } + } +} + #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { pub crate_name: String, @@ -98,6 +194,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::EnumData { @@ -115,6 +212,7 @@ impl Lower for data::EnumData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -179,6 +277,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::FunctionData { @@ -197,6 +296,7 @@ impl Lower for data::FunctionData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -346,6 +446,7 @@ pub struct MethodData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::MethodData { @@ -364,6 +465,7 @@ impl Lower for data::MethodData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -381,6 +483,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::ModData { @@ -398,6 +501,7 @@ impl Lower for data::ModData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -437,6 +541,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructData { @@ -455,6 +560,7 @@ impl Lower for data::StructData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -471,6 +577,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructVariantData { @@ -488,6 +595,7 @@ impl Lower for data::StructVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -504,6 +612,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TraitData { @@ -521,6 +630,7 @@ impl Lower for data::TraitData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -537,6 +647,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TupleVariantData { @@ -554,6 +665,7 @@ impl Lower for data::TupleVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -570,6 +682,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::TypeDefData { @@ -586,6 +699,7 @@ impl Lower for data::TypeDefData { parent: self.parent, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } @@ -675,6 +789,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::VariableData { @@ -694,6 +809,7 @@ impl Lower for data::VariableData { visibility: self.visibility, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 16c06a556df0e..03b34f8e5e461 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -87,6 +87,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, }; if def.span.file_name != def.value { // If the module is an out-of-line defintion, then we'll make the @@ -225,6 +226,7 @@ struct Def { decl_id: Option, docs: String, sig: Option, + attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -267,6 +269,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -284,6 +287,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -300,6 +304,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -316,6 +321,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -332,6 +338,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -348,6 +355,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -364,6 +372,7 @@ impl From for Def { decl_id: data.decl_id.map(|id| From::from(id)), docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -380,6 +389,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: vec![], } } } @@ -396,6 +406,7 @@ impl From for Def { decl_id: None, docs: String::new(), sig: data.sig.map(|s| From::from(s)), + attributes: data.attributes, } } } @@ -417,6 +428,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: data.attributes, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ebb33a12c8703..4fd0b443f3084 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -136,6 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -164,6 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -183,6 +185,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Mod(ref m) => { @@ -205,6 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Enum(ref def, _) => { @@ -228,6 +232,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: remove_docs_from_attrs(&item.attrs), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { @@ -313,6 +318,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), sig: Some(sig), + attributes: remove_docs_from_attrs(&field.attrs), }) } else { None @@ -325,7 +331,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, decl_id, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs, attributes) = match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) { Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) { Some(Node::NodeItem(item)) => { @@ -347,7 +353,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (result, trait_id, decl_id, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + remove_docs_from_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -372,7 +379,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (format!("::{}", self.tcx.item_path_str(def_id)), Some(def_id), None, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + remove_docs_from_attrs(&item.attrs)) } r => { span_bug!(span, @@ -421,6 +429,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: parent_scope, docs: docs, sig: sig, + attributes: attributes, }) } @@ -834,6 +843,12 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } +/// Remove all attributes which are docs +fn remove_docs_from_attrs(attrs: &[Attribute]) -> Vec { + let doc = Symbol::intern("doc"); + attrs.iter().cloned().filter(|attr| attr.name() != doc).collect() +} + #[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, From 346aed2edc146851374640555a886e610db0852f Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Thu, 23 Feb 2017 23:24:12 +0100 Subject: [PATCH 02/73] Store attributes as strings Remove the AST structure --- src/librustc_save_analysis/external_data.rs | 85 +++------------------ 1 file changed, 11 insertions(+), 74 deletions(-) diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 0cfa71a349916..38d1df2abb888 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -11,8 +11,9 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::{self, LitKind, NodeId, StrStyle}; +use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; +use syntax::print::pprust; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -67,16 +68,22 @@ impl SpanData { /// Represent an arbitrary attribute on a code element #[derive(Clone, Debug, RustcEncodable)] pub struct Attribute { - value: AttributeItem, + value: String, span: SpanData, } impl Lower for ast::Attribute { type Target = Attribute; - fn lower(self, tcx: TyCtxt) -> Attribute { + fn lower(mut self, tcx: TyCtxt) -> Attribute { + // strip #[] and #![] from the original attributes + self.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&self); + // #[] are all ASCII which makes this slice save + let value = value[2..value.len()-1].to_string(); + Attribute { - value: self.value.lower(tcx), + value: value, span: SpanData::from_span(self.span, tcx.sess.codemap()), } } @@ -90,76 +97,6 @@ impl Lower for Vec { } } -/// A single item as part of an attribute -#[derive(Clone, Debug, RustcEncodable)] -pub struct AttributeItem { - name: LitKind, - kind: AttributeItemKind, - span: SpanData, -} - -impl Lower for ast::MetaItem { - type Target = AttributeItem; - - fn lower(self, tcx: TyCtxt) -> AttributeItem { - AttributeItem { - name: LitKind::Str(self.name, StrStyle::Cooked), - kind: self.node.lower(tcx), - span: SpanData::from_span(self.span, tcx.sess.codemap()), - } - } -} - -impl Lower for ast::NestedMetaItem { - type Target = AttributeItem; - - fn lower(self, tcx: TyCtxt) -> AttributeItem { - match self.node { - ast::NestedMetaItemKind::MetaItem(item) => item.lower(tcx), - ast::NestedMetaItemKind::Literal(lit) => { - AttributeItem { - name: lit.node, - kind: AttributeItemKind::Literal, - span: SpanData::from_span(lit.span, tcx.sess.codemap()), - } - } - } - } -} - -#[derive(Clone, Debug, RustcEncodable)] -pub enum AttributeItemKind { - /// Word meta item. - /// - /// E.g. `test` as in `#[test]` - Literal, - /// Name value meta item. - /// - /// E.g. `feature = "foo"` as in `#[feature = "foo"]` - NameValue(LitKind, SpanData), - /// List meta item. - /// - /// E.g. the `derive(..)` as in `#[derive(..)]` - List(Vec), -} - -impl Lower for ast::MetaItemKind { - type Target = AttributeItemKind; - - fn lower(self, tcx: TyCtxt) -> AttributeItemKind { - match self { - ast::MetaItemKind::Word => AttributeItemKind::Literal, - ast::MetaItemKind::List(items) => { - AttributeItemKind::List(items.into_iter().map(|x| x.lower(tcx)).collect()) - } - ast::MetaItemKind::NameValue(lit) => { - let span = SpanData::from_span(lit.span, tcx.sess.codemap()); - AttributeItemKind::NameValue(lit.node, span) - } - } - } -} - #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { pub crate_name: String, From 8a64cf7fb72ca93608be19e13dd83c23168b17d7 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Sat, 25 Feb 2017 22:05:30 +0900 Subject: [PATCH 03/73] Fix suggestion span error with a line containing non-ASCIIs --- src/librustc_errors/lib.rs | 3 ++- src/test/ui/span/suggestion-non-ascii.rs | 16 ++++++++++++++++ src/test/ui/span/suggestion-non-ascii.stderr | 11 +++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/span/suggestion-non-ascii.rs create mode 100644 src/test/ui/span/suggestion-non-ascii.stderr diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d7bd5ed23c2b0..4c889dad8ca50 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -90,7 +90,8 @@ impl CodeSuggestion { hi_opt: Option<&Loc>) { let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); if let Some(line) = line_opt { - if line.len() > lo { + if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) { + let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi)); buf.push_str(match hi_opt { Some(hi) => &line[lo..hi], None => &line[lo..], diff --git a/src/test/ui/span/suggestion-non-ascii.rs b/src/test/ui/span/suggestion-non-ascii.rs new file mode 100644 index 0000000000000..67dbe1dc7b566 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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. + + +fn main() { + let tup = (1,); + println!("☃{}", tup[0]); +} + diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr new file mode 100644 index 0000000000000..385c211f393c6 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -0,0 +1,11 @@ +error: cannot index a value of type `({integer},)` + --> $DIR/suggestion-non-ascii.rs:14:21 + | +14 | println!("☃{}", tup[0]); + | ^^^^^^ + | +help: to access tuple elements, use tuple indexing syntax as shown + | println!("☃{}", tup.0); + +error: aborting due to previous error + From 5eeef8b6d350c7032e1c1ed5c5a6cd912210a069 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:21:16 -0800 Subject: [PATCH 04/73] configure: Remove git probing logic This is all in rustbuild already. --- configure | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/configure b/configure index 70952438a3559..142fbb7130a3b 100755 --- a/configure +++ b/configure @@ -820,17 +820,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# If we have no git directory then we are probably a tarball distribution -# and shouldn't attempt to load submodules -if [ ! -e ${CFG_SRC_DIR}.git ] -then - probe CFG_GIT git - msg "git: no git directory. disabling submodules" - CFG_DISABLE_MANAGE_SUBMODULES=1 -else - probe_need CFG_GIT git -fi - # Use `md5sum` on GNU platforms, or `md5 -q` on BSD probe CFG_MD5 md5 probe CFG_MD5SUM md5sum From e9b341a05682d2e74c779844d3de2e33203f571b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:21:41 -0800 Subject: [PATCH 05/73] configure: Remove md5 probing logic This is all not used any more --- configure | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/configure b/configure index 142fbb7130a3b..b52c9e67b0f61 100755 --- a/configure +++ b/configure @@ -820,20 +820,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# Use `md5sum` on GNU platforms, or `md5 -q` on BSD -probe CFG_MD5 md5 -probe CFG_MD5SUM md5sum -if [ -n "$CFG_MD5" ] -then - CFG_HASH_COMMAND="$CFG_MD5 -q | cut -c 1-8" -elif [ -n "$CFG_MD5SUM" ] -then - CFG_HASH_COMMAND="$CFG_MD5SUM | cut -c 1-8" -else - err 'could not find one of: md5 md5sum' -fi -putvar CFG_HASH_COMMAND - probe CFG_CLANG clang++ probe CFG_CCACHE ccache probe CFG_GCC gcc From 6fbe6de751c5291f609a6981a5e0ee2d4670265c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:23:09 -0800 Subject: [PATCH 06/73] configure: Remove miscellaneous program probes All of these should be handled by rustbuild in sanity.rs right now. --- configure | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) diff --git a/configure b/configure index b52c9e67b0f61..746cbf1787ffa 100755 --- a/configure +++ b/configure @@ -820,51 +820,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -probe CFG_CLANG clang++ -probe CFG_CCACHE ccache -probe CFG_GCC gcc -probe CFG_LD ld -probe CFG_VALGRIND valgrind -probe CFG_PERF perf -probe CFG_ISCC iscc -probe CFG_ANTLR4 antlr4 -probe CFG_GRUN grun -probe CFG_FLEX flex -probe CFG_BISON bison -probe CFG_GDB gdb -probe CFG_LLDB lldb - -if [ -n "$CFG_ENABLE_NINJA" ] -then - probe CFG_NINJA ninja - if [ -z "$CFG_NINJA" ] - then - # On Debian and Fedora, the `ninja` binary is an IRC bot, so the build tool was - # renamed. Handle this case. - probe CFG_NINJA ninja-build - fi -fi - -# For building LLVM -if [ -z "$CFG_LLVM_ROOT" ] -then - probe_need CFG_CMAKE cmake -fi - -# On MacOS X, invoking `javac` pops up a dialog if the JDK is not -# installed. Since `javac` is only used if `antlr4` is available, -# probe for it only in this case. -if [ -n "$CFG_ANTLR4" ] -then - CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - if [ "x" = "x$CFG_ANTLR4_JAR" ] - then - CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - fi - putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR - probe CFG_JAVAC javac -fi - # the valgrind rpass tests will fail if you don't have a valgrind, but they're # only disabled if you opt out. if [ -z "$CFG_VALGRIND" ] @@ -926,10 +881,6 @@ if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then fi fi -step_msg "looking for target specific programs" - -probe CFG_ADB adb - BIN_SUF= if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ] then From 278045cf118ecb459a16b3e99f345ba3989ad35a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 10:25:32 -0800 Subject: [PATCH 07/73] configure: Remove some lldb-specific logic All of this should already be vendored in rustbuild if necessary or otherwise it's just not used. --- configure | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/configure b/configure index 746cbf1787ffa..16dc52dafe5af 100755 --- a/configure +++ b/configure @@ -834,41 +834,6 @@ then fi fi -if [ -n "$CFG_LLDB" ] -then - # Store LLDB's version - CFG_LLDB_VERSION=$($CFG_LLDB --version 2>/dev/null | head -1) - putvar CFG_LLDB_VERSION - - # If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from - # LLDB via the -P commandline options. - if [ -z "$CFG_LLDB_PYTHON_DIR" ] || [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR=$($CFG_LLDB -P) - - # If CFG_LLDB_PYTHON_DIR is not a valid directory, set it to something more readable - if [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR="LLDB_PYTHON_DIRECTORY_NOT_FOUND" - fi - - putvar CFG_LLDB_PYTHON_DIR - fi -fi - -# LLDB tests on OSX require /usr/bin/python, not something like Homebrew's -# /usr/local/bin/python. We're loading a compiled module for LLDB tests which is -# only compatible with the system. -case $CFG_BUILD in - *-apple-darwin) - CFG_LLDB_PYTHON=/usr/bin/python - ;; - *) - CFG_LLDB_PYTHON=$CFG_PYTHON - ;; -esac -putvar CFG_LLDB_PYTHON - # Do some sanity checks if running on buildbot # (these env vars are set by rust-buildbot) if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then From 8fb06b876f2a798124903d7dd49b07bfec29639d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:12:40 -0800 Subject: [PATCH 08/73] configure: Remove SUPPORTED_TARGET support This is not used any more --- configure | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure b/configure index 16dc52dafe5af..d400ff3d6fe54 100755 --- a/configure +++ b/configure @@ -911,10 +911,6 @@ CFG_MANDIR=${CFG_MANDIR%/} CFG_DOCDIR=${CFG_DOCDIR%/} CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')" CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')" -CFG_SUPPORTED_TARGET="" -for target_file in ${CFG_SRC_DIR}mk/cfg/*.mk; do - CFG_SUPPORTED_TARGET="${CFG_SUPPORTED_TARGET} $(basename "$target_file" .mk)" -done # copy build-triples to host-triples so that builds are a subset of hosts V_TEMP="" From 49a5aa465413e0b3c6c08cdb1571f2be616e4249 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:13:41 -0800 Subject: [PATCH 09/73] configure: Remove misc unused vars None of this is used by rustbuild any more --- configure | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/configure b/configure index d400ff3d6fe54..c9d384ecfe3b2 100755 --- a/configure +++ b/configure @@ -950,31 +950,6 @@ putvar CFG_MANDIR putvar CFG_DOCDIR putvar CFG_USING_LIBCPP -# Avoid spurious warnings from clang by feeding it original source on -# ccache-miss rather than preprocessed input. -if [ -n "$CFG_ENABLE_CCACHE" ] && [ -n "$CFG_USING_CLANG" ] -then - CFG_CCACHE_CPP2=1 - putvar CFG_CCACHE_CPP2 -fi - -if [ -n "$CFG_ENABLE_CCACHE" ] -then - CFG_CCACHE_BASEDIR=${CFG_SRC_DIR} - putvar CFG_CCACHE_BASEDIR -fi - - -putvar CFG_LLVM_SRC_DIR - -for t in $CFG_HOST -do - CFG_LLVM_BUILD_DIR=$(echo CFG_LLVM_BUILD_DIR_${t} | tr - _) - CFG_LLVM_INST_DIR=$(echo CFG_LLVM_INST_DIR_${t} | tr - _) - putvar $CFG_LLVM_BUILD_DIR - putvar $CFG_LLVM_INST_DIR -done - msg copy_if_changed ${CFG_SRC_DIR}src/bootstrap/mk/Makefile.in ./Makefile move_if_changed config.tmp config.mk From bfd2f5bf3d0178ffc92d857047986665cc6513cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Feb 2017 11:27:39 -0800 Subject: [PATCH 10/73] configure: Remove --build detection This commit removes detection of CFG_OSTYPE and CFG_CPUTYPE from the configure script, which means that the default value of `--build` is no longer present in the configure script. All this logic is now available in rustbuild itself, so there's no need to duplicate it. --- configure | 203 +------------------------------------ src/bootstrap/bootstrap.py | 23 ++++- src/bootstrap/config.rs | 6 +- 3 files changed, 23 insertions(+), 209 deletions(-) diff --git a/configure b/configure index c9d384ecfe3b2..7b3f710fc7276 100755 --- a/configure +++ b/configure @@ -384,207 +384,6 @@ need_cmd sed need_cmd file need_cmd make -msg "inspecting environment" - -CFG_OSTYPE=$(uname -s) -CFG_CPUTYPE=$(uname -m) - -if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] -then - # Darwin's `uname -s` lies and always returns i386. We have to use sysctl - # instead. - if sysctl hw.optional.x86_64 | grep -q ': 1' - then - CFG_CPUTYPE=x86_64 - fi -fi - -# The goal here is to come up with the same triple as LLVM would, -# at least for the subset of platforms we're willing to target. - -case $CFG_OSTYPE in - - Linux) - CFG_OSTYPE=unknown-linux-gnu - ;; - - FreeBSD) - CFG_OSTYPE=unknown-freebsd - ;; - - DragonFly) - CFG_OSTYPE=unknown-dragonfly - ;; - - Bitrig) - CFG_OSTYPE=unknown-bitrig - ;; - - OpenBSD) - CFG_OSTYPE=unknown-openbsd - ;; - - NetBSD) - CFG_OSTYPE=unknown-netbsd - ;; - - Darwin) - CFG_OSTYPE=apple-darwin - ;; - - SunOS) - CFG_OSTYPE=sun-solaris - CFG_CPUTYPE=$(isainfo -n) - ;; - - Haiku) - CFG_OSTYPE=unknown-haiku - ;; - - MINGW*) - # msys' `uname` does not print gcc configuration, but prints msys - # configuration. so we cannot believe `uname -m`: - # msys1 is always i686 and msys2 is always x86_64. - # instead, msys defines $MSYSTEM which is MINGW32 on i686 and - # MINGW64 on x86_64. - CFG_CPUTYPE=i686 - CFG_OSTYPE=pc-windows-gnu - if [ "$MSYSTEM" = MINGW64 ] - then - CFG_CPUTYPE=x86_64 - fi - ;; - - MSYS*) - CFG_OSTYPE=pc-windows-gnu - ;; - -# Thad's Cygwin identifiers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 8 # uname -s on 64-bit cygwin does not contain WOW64, so simply use uname -m to detect arch (works in my install) - CYGWIN_NT-6.3) - CFG_OSTYPE=pc-windows-gnu - ;; -# We do not detect other OS such as XP/2003 using 64 bit using uname. -# If we want to in the future, we will need to use Cygwin - Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. - *) - err "unknown OS type: $CFG_OSTYPE" - ;; -esac - - -case $CFG_CPUTYPE in - - i386 | i486 | i686 | i786 | x86) - CFG_CPUTYPE=i686 - ;; - - xscale | arm) - CFG_CPUTYPE=arm - ;; - - armv6l) - CFG_CPUTYPE=arm - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - armv7l) - CFG_CPUTYPE=armv7 - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - aarch64 | arm64) - CFG_CPUTYPE=aarch64 - ;; - - powerpc | ppc) - CFG_CPUTYPE=powerpc - ;; - - powerpc64 | ppc64) - CFG_CPUTYPE=powerpc64 - ;; - - powerpc64le | ppc64le) - CFG_CPUTYPE=powerpc64le - ;; - - s390x) - CFG_CPUTYPE=s390x - ;; - - x86_64 | x86-64 | x64 | amd64) - CFG_CPUTYPE=x86_64 - ;; - - mips | mips64) - if [ "$CFG_CPUTYPE" = "mips64" ]; then - CFG_OSTYPE="${CFG_OSTYPE}abi64" - fi - ENDIAN=$(printf '\1' | od -dAn) - if [ "$ENDIAN" -eq 1 ]; then - CFG_CPUTYPE="${CFG_CPUTYPE}el" - elif [ "$ENDIAN" -ne 256 ]; then - err "unknown endianness: $ENDIAN (expecting 1 for little or 256 for big)" - fi - ;; - - BePC) - CFG_CPUTYPE=i686 - ;; - - *) - err "unknown CPU type: $CFG_CPUTYPE" -esac - -# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation -if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] -then - # $SHELL does not exist in standard 'sh', so probably only exists - # if configure is running in an interactive bash shell. /usr/bin/env - # exists *everywhere*. - BIN_TO_PROBE="$SHELL" - if [ ! -r "$BIN_TO_PROBE" ]; then - if [ -r "/usr/bin/env" ]; then - BIN_TO_PROBE="/usr/bin/env" - else - warn "Cannot check if the userland is i686 or x86_64" - fi - fi - file -L "$BIN_TO_PROBE" | grep -q "x86[_-]64" - if [ $? != 0 ]; then - msg "i686 userland on x86_64 Linux kernel" - CFG_CPUTYPE=i686 - fi -fi - - -DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}" - CFG_SRC_DIR="$(abs_path $(dirname $0))/" CFG_SRC_DIR_RELATIVE="$(dirname $0)/" CFG_BUILD_DIR="$(pwd)/" @@ -672,7 +471,7 @@ valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" -valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" +valopt build "" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c1ee0c29ac981..40cd084c754e9 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -295,8 +295,10 @@ def get_toml(self, key): def get_mk(self, key): for line in iter(self.config_mk.splitlines()): - if line.startswith(key): - return line[line.find(':=') + 2:].strip() + if line.startswith(key + ' :='): + var = line[line.find(':=') + 2:].strip() + if var != '': + return var return None def cargo(self): @@ -437,6 +439,8 @@ def build_triple(self): sys.exit(err) elif ostype == 'Darwin': ostype = 'apple-darwin' + elif ostype == 'Haiku': + ostype = 'unknown-haiku' elif ostype.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: @@ -464,9 +468,12 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype == 'armv7l': + elif cputype == 'armv6l': cputype = 'arm' ostype += 'eabihf' + elif cputype == 'armv7l': + cputype = 'armv7' + ostype += 'eabihf' elif cputype == 'aarch64': cputype = 'aarch64' elif cputype == 'arm64': @@ -487,12 +494,20 @@ def build_triple(self): raise ValueError('unknown byteorder: ' + sys.byteorder) # only the n64 ABI is supported, indicate it ostype += 'abi64' - elif cputype in {'powerpc', 'ppc', 'ppc64'}: + elif cputype in {'powerpc', 'ppc'}: cputype = 'powerpc' + elif cputype in {'powerpc64', 'ppc64'}: + cputype = 'powerpc64' + elif cputype in {'powerpc64le', 'ppc64le'}: + cputype = 'powerpc64le' elif cputype == 'sparcv9': pass elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: cputype = 'x86_64' + elif cputype == 's390x': + cputype = 's390x' + elif cputype == 'BePC': + cputype = 'i686' else: err = "unknown cpu type: " + cputype if self.verbose: diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 8308dc3202fff..dfcbe3da76dd1 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -456,12 +456,12 @@ impl Config { } match key { - "CFG_BUILD" => self.build = value.to_string(), - "CFG_HOST" => { + "CFG_BUILD" if value.len() > 0 => self.build = value.to_string(), + "CFG_HOST" if value.len() > 0 => { self.host = value.split(" ").map(|s| s.to_string()) .collect(); } - "CFG_TARGET" => { + "CFG_TARGET" if value.len() > 0 => { self.target = value.split(" ").map(|s| s.to_string()) .collect(); } From 53d3c8939e3cf45f9e08fd360d9289e9440b6ece Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 10:57:10 +0100 Subject: [PATCH 11/73] Dont bug! on user error --- src/librustc/infer/region_inference/graphviz.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 95ce8d39ff488..a67049f72852b 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( }; if output_template.is_empty() { - bug!("empty string provided as RUST_REGION_GRAPH"); + panic!("empty string provided as RUST_REGION_GRAPH"); } if output_template.contains('%') { From 54a1c8b1a66ce6dd4f46fc6063612607897b2638 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 10:59:36 +0100 Subject: [PATCH 12/73] Fix indentation in region infer docs --- src/librustc/infer/region_inference/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index 80da861139b42..4f24b37682eb5 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -122,14 +122,14 @@ every expression, block, and pattern (patterns are considered to relevant bindings). So, for example: fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ + // +------------+ // | + // | +-----+ // | + // | +-+ +-+ +-+ // | + // | | | | | | | // | + // v v v v v v v // | + let z = x + y; // | + ... // | + } // -+ fn bar() { ... } From 2a40918928818bdaa8bdc3780ce5d6449bb69f85 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:17:14 +0100 Subject: [PATCH 13/73] Syntax highlighting in region infer docs --- src/librustc/infer/region_inference/README.md | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index 4f24b37682eb5..f5c254a459407 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to "execute" by testing the value they are applied to and creating any relevant bindings). So, for example: - fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ - - fn bar() { ... } +```rust +fn foo(x: isize, y: isize) { // -+ +// +------------+ // | +// | +-----+ // | +// | +-+ +-+ +-+ // | +// | | | | | | | // | +// v v v v v v v // | + let z = x + y; // | + ... // | +} // -+ + +fn bar() { ... } +``` In this example, there is a region for the fn body block as a whole, and then a subregion for the declaration of the local variable. @@ -160,7 +162,9 @@ this, we get a lot of spurious errors around nested calls, in particular when combined with `&mut` functions. For example, a call like this one - self.foo(self.bar()) +```rust +self.foo(self.bar()) +``` where both `foo` and `bar` are `&mut self` functions will always yield an error. @@ -168,20 +172,22 @@ an error. Here is a more involved example (which is safe) so we can see what's going on: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn inc(p: &mut usize) -> usize { - *p += 1; *p - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, - 'b: inc(&mut (*x).f)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn inc(p: &mut usize) -> usize { + *p += 1; *p +} +fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (..) +} +``` The important part is the line marked `(..)` which contains a call to `add()`. The first argument is a mutable borrow of the field `f`. The @@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes involved with `'a` in detail. We'll break apart all the steps involved in a call expression: - 'a: { - 'a_arg1: let a_temp1: ... = add; - 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; - 'a_arg3: let a_temp3: usize = { - let b_temp1: ... = inc; - let b_temp2: &'b = &'b mut (*x).f; - 'b_call: b_temp1(b_temp2) - }; - 'a_call: a_temp1(a_temp2, a_temp3) // (**) - } +```rust +'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; + 'a_arg3: let a_temp3: usize = { + let b_temp1: ... = inc; + let b_temp2: &'b = &'b mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) // (**) +} +``` Here we see that the lifetime `'a` includes a number of substatements. In particular, there is this lifetime I've called `'a_call` that @@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second argument, it can still be *invalidated* by that evaluation. Consider this similar but unsound example: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn consume(x: Box) -> usize { - x.f + x.g - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, consume(x)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn consume(x: Box) -> usize { + x.f + x.g +} +fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (..) +} +``` In this case, the second argument to `add` actually consumes `x`, thus invalidating the first argument. From be49671df9772ee8b82a53c147f8a3cd115fd8f0 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:19:48 +0100 Subject: [PATCH 14/73] Improve a bit more --- src/librustc/infer/region_inference/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index f5c254a459407..b564faf3d0c24 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -183,7 +183,7 @@ fn inc(p: &mut usize) -> usize { *p += 1; *p } fn weird() { - let mut x: Box = box Foo { ... }; + let mut x: Box = box Foo { /* ... */ }; 'a: add(&mut (*x).f, 'b: inc(&mut (*x).f)) // (..) } From 90e94d97f2635af1f976a1c6ad2f1296df05c784 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 28 Feb 2017 11:39:00 +0100 Subject: [PATCH 15/73] Syntax highlight and note about current rust in infer docs --- src/librustc/infer/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index c835189820e51..68e64b8b7bfc8 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -152,7 +152,7 @@ course, it depends on the program. The main case which fails today that I would like to support is: -```text +```rust fn foo(x: T, y: T) { ... } fn bar() { @@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for `X`, and thus inherits its UB/LB of `@mut int`. This leaves no flexibility for `T` to later adjust to accommodate `@int`. +Note: `@` and `@mut` are replaced with `Rc` and `Rc>` in current Rust. + ### What to do when not all bounds are present In the prior discussion we assumed that A.ub was not top and B.lb was From 5bfa0f3585a91a79519dec590c2343100dbe91e7 Mon Sep 17 00:00:00 2001 From: Jonas Bushart Date: Thu, 2 Mar 2017 22:38:57 +0100 Subject: [PATCH 16/73] Move remove_docs_from_attrs into lowering step --- src/librustc_save_analysis/dump_visitor.rs | 17 +++++---- src/librustc_save_analysis/external_data.rs | 38 +++++++++++---------- src/librustc_save_analysis/lib.rs | 22 +++++------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a4b1d774be7df..b9c82b8a28be9 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -47,8 +47,7 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs, - remove_docs_from_attrs}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::{Lower, make_def_id}; @@ -450,7 +449,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: method_data.sig, - attributes: remove_docs_from_attrs(attrs), + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -596,7 +595,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: None, - attributes: remove_docs_from_attrs(attrs), + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -641,7 +640,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -707,7 +706,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, - attributes: remove_docs_from_attrs(&variant.node.attrs), + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -734,7 +733,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, - attributes: remove_docs_from_attrs(&variant.node.attrs), + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -821,7 +820,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -1330,7 +1329,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, parent: None, docs: docs_for_attrs(&item.attrs), sig: Some(self.save_ctxt.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), }.lower(self.tcx)); } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 38d1df2abb888..41658dc5b1b48 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -14,6 +14,7 @@ use rustc::ty::TyCtxt; use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; use syntax::print::pprust; +use syntax::symbol::Symbol; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -72,28 +73,29 @@ pub struct Attribute { span: SpanData, } -impl Lower for ast::Attribute { - type Target = Attribute; - - fn lower(mut self, tcx: TyCtxt) -> Attribute { - // strip #[] and #![] from the original attributes - self.style = ast::AttrStyle::Outer; - let value = pprust::attribute_to_string(&self); - // #[] are all ASCII which makes this slice save - let value = value[2..value.len()-1].to_string(); - - Attribute { - value: value, - span: SpanData::from_span(self.span, tcx.sess.codemap()), - } - } -} - impl Lower for Vec { type Target = Vec; fn lower(self, tcx: TyCtxt) -> Vec { - self.into_iter().map(|x| x.lower(tcx)).collect() + let doc = Symbol::intern("doc"); + self.into_iter() + // Only retain real attributes. Doc comments are lowered separately. + .filter(|attr| attr.name() != doc) + .map(|mut attr| { + // Remove the surrounding '#[..]' or '#![..]' of the pretty printed + // attribute. First normalize all inner attribute (#![..]) to outer + // ones (#[..]), then remove the two leading and the one trailing character. + attr.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&attr); + // This str slicing works correctly, because the leading and trailing characters + // are in the ASCII range and thus exactly one byte each. + let value = value[2..value.len()-1].to_string(); + + Attribute { + value: value, + span: SpanData::from_span(attr.span, tcx.sess.codemap()), + } + }).collect() } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4fd0b443f3084..b224ed923daf8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -136,7 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -165,7 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -185,7 +185,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Mod(ref m) => { @@ -208,7 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Enum(ref def, _) => { @@ -232,7 +232,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), - attributes: remove_docs_from_attrs(&item.attrs), + attributes: item.attrs.clone(), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { @@ -318,7 +318,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), sig: Some(sig), - attributes: remove_docs_from_attrs(&field.attrs), + attributes: field.attrs.clone(), }) } else { None @@ -354,7 +354,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (result, trait_id, decl_id, From::from(&item.vis), docs_for_attrs(&item.attrs), - remove_docs_from_attrs(&item.attrs)) + item.attrs.to_vec()) } _ => { span_bug!(span, @@ -380,7 +380,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(def_id), None, From::from(&item.vis), docs_for_attrs(&item.attrs), - remove_docs_from_attrs(&item.attrs)) + item.attrs.to_vec()) } r => { span_bug!(span, @@ -843,12 +843,6 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } -/// Remove all attributes which are docs -fn remove_docs_from_attrs(attrs: &[Attribute]) -> Vec { - let doc = Symbol::intern("doc"); - attrs.iter().cloned().filter(|attr| attr.name() != doc).collect() -} - #[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, From 5945d1dffe79f04f7dbd5fe50ef0ac613557cc89 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 3 Mar 2017 19:11:34 +0200 Subject: [PATCH 17/73] Remove ability for plugins to register a MIR pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In recent months there have been a few different people investigating how to make a plugin that registers a MIR-pass – one that isn’t intended to be eventually merged into rustc proper. The interface to register MIR passes was added primarily for miri (& later was found to make prototyping of rustc-proper MIR passes a tiny bit faster). Since miri does not use this interface anymore it seems like a good time to remove this "feature". For prototyping purposes a similar interface can be added by developers themselves in their custom rustc build. --- src/librustc_driver/driver.rs | 3 +- src/librustc_plugin/registry.rs | 11 ---- .../auxiliary/dummy_mir_pass.rs | 55 ------------------- src/test/run-pass-fulldeps/mir-pass.rs | 23 -------- 4 files changed, 1 insertion(+), 91 deletions(-) delete mode 100644 src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs delete mode 100644 src/test/run-pass-fulldeps/mir-pass.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..dda118fb4408e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -604,7 +604,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives(); let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, - llvm_passes, attributes, mir_passes, .. } = registry; + llvm_passes, attributes, .. } = registry; sess.track_errors(|| { let mut ls = sess.lint_store.borrow_mut(); @@ -620,7 +620,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, } *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - sess.mir_passes.borrow_mut().extend(mir_passes); *sess.plugin_attributes.borrow_mut() = attributes.clone(); })?; diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 3700d0295e963..cdde56f5f634b 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -13,8 +13,6 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; -use rustc::mir::transform::MirMapPass; - use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; use syntax::ext::base::MacroExpanderFn; use syntax::symbol::Symbol; @@ -53,9 +51,6 @@ pub struct Registry<'a> { #[doc(hidden)] pub late_lint_passes: Vec, - #[doc(hidden)] - pub mir_passes: Vec MirMapPass<'pcx>>>, - #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -81,7 +76,6 @@ impl<'a> Registry<'a> { lint_groups: HashMap::new(), llvm_passes: vec![], attributes: vec![], - mir_passes: Vec::new(), whitelisted_custom_derives: Vec::new(), } } @@ -157,11 +151,6 @@ impl<'a> Registry<'a> { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } - /// Register a MIR pass - pub fn register_mir_pass(&mut self, pass: Box MirMapPass<'pcx>>) { - self.mir_passes.push(pass); - } - /// Register an LLVM pass. /// /// Registration with LLVM itself is handled through static C++ objects with diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs deleted file mode 100644 index 3bc4a40a39c99..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// force-host - -#![feature(plugin_registrar, rustc_private)] -#![feature(box_syntax)] - -#[macro_use] extern crate rustc; -extern crate rustc_plugin; -extern crate rustc_const_math; -extern crate syntax; - -use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::{Mir, Literal, Location}; -use rustc::mir::visit::MutVisitor; -use rustc::ty::TyCtxt; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::ConstInt; -use rustc_plugin::Registry; - -struct Pass; - -impl transform::Pass for Pass {} - -impl<'tcx> MirPass<'tcx> for Pass { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - Visitor.visit_mir(mir) - } -} - -struct Visitor; - -impl<'tcx> MutVisitor<'tcx> for Visitor { - fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) { - if let Literal::Value { ref mut value } = *literal { - if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value { - *i = 42; - } - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_mir_pass(box Pass); -} diff --git a/src/test/run-pass-fulldeps/mir-pass.rs b/src/test/run-pass-fulldeps/mir-pass.rs deleted file mode 100644 index 8ac4bf9733757..0000000000000 --- a/src/test/run-pass-fulldeps/mir-pass.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:dummy_mir_pass.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(dummy_mir_pass)] - -fn math() -> i32 { - 11 -} - -pub fn main() { - assert_eq!(math(), 42); -} From 6698fb6029d93b992e8f89b5a89bfee2b12a80c6 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 17 Feb 2017 15:12:47 -0800 Subject: [PATCH 18/73] Add catch expr to AST and disallow catch as a struct name --- src/librustc/hir/lowering.rs | 37 +++++++++++++++++-- src/libsyntax/ast.rs | 2 + src/libsyntax/feature_gate.rs | 6 +++ src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 35 ++++++++++++++++++ src/libsyntax/print/pprust.rs | 5 +++ src/libsyntax/symbol.rs | 3 +- src/libsyntax/visit.rs | 3 ++ .../compile-fail/catch-empty-struct-name.rs | 15 ++++++++ src/test/compile-fail/catch-enum-variant.rs | 17 +++++++++ src/test/compile-fail/catch-struct-name.rs | 15 ++++++++ .../compile-fail/catch-tuple-struct-name.rs | 15 ++++++++ .../compile-fail/feature-gate-catch_expr.rs | 17 +++++++++ src/test/run-pass/catch-expr.rs | 30 +++++++++++++++ 14 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/catch-empty-struct-name.rs create mode 100644 src/test/compile-fail/catch-enum-variant.rs create mode 100644 src/test/compile-fail/catch-struct-name.rs create mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs create mode 100644 src/test/compile-fail/feature-gate-catch_expr.rs create mode 100644 src/test/run-pass/catch-expr.rs diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..3d51a64c22132 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -83,6 +83,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -121,6 +122,7 @@ pub fn lower_crate(sess: &Session, bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), + catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -259,6 +261,21 @@ impl<'a> LoweringContext<'a> { span } + fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.catch_scopes.len(); + self.catch_scopes.push(catch_id); + + let result = f(self); + assert_eq!(len + 1, self.catch_scopes.len(), + "catch scopes should be added and removed in stack order"); + + self.catch_scopes.pop().unwrap(); + + result + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -293,15 +310,17 @@ impl<'a> LoweringContext<'a> { result } - fn with_new_loop_scopes(&mut self, f: F) -> T + fn with_new_scopes(&mut self, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); let result = f(self); - mem::replace(&mut self.loop_scopes, loop_scopes); + self.catch_scopes = catch_scopes; + self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; @@ -1063,7 +1082,7 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { let body = this.lower_block(body); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); @@ -1660,13 +1679,17 @@ impl<'a> LoweringContext<'a> { this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } + ExprKind::Catch(ref body) => { + // FIXME(cramertj): Add catch to HIR + self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let expr = this.lower_expr(body); hir::ExprClosure(this.lower_capture_clause(capture_clause), @@ -2064,6 +2087,12 @@ impl<'a> LoweringContext<'a> { // Err(err) => #[allow(unreachable_code)] // return Carrier::from_error(From::from(err)), // } + + // FIXME(cramertj): implement breaking to catch + if !self.catch_scopes.is_empty() { + bug!("`?` in catch scopes is unimplemented") + } + let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 09fb369cd3568..bb0aa6e94b72a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -936,6 +936,8 @@ pub enum ExprKind { Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), + /// A catch block (`catch { ... }`) + Catch(P), /// An assignment (`a = foo()`) Assign(P, P), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6eb7d449f2692..b776441079ef0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -340,6 +340,9 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Allows the `catch {...}` expression + (active, catch_expr, "1.17.0", Some(31436)), ); declare_features! ( @@ -1288,6 +1291,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + ast::ExprKind::Catch(_) => { + gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 257b7efba5c8e..3150ab0be0bea 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1276,6 +1276,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), + ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, id: folder.new_id(id), span: folder.new_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 71274c4fdaa4e..eef252319bcc2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -515,6 +515,12 @@ impl<'a> Parser<'a> { } } + pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { + if ident.name == keywords::Catch.name() { + self.span_err(self.span, "cannot use `catch` as the name of a type"); + } + } + /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2196,6 +2202,11 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span.lo; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3006,6 +3017,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } + /// Parse a `catch {...}` expression (`catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + -> PResult<'a, P> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + let hi = body.span.hi; + Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + } + // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; @@ -3613,6 +3634,14 @@ impl<'a> Parser<'a> { }) } + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Catch) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) + } + fn is_union_item(&mut self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) @@ -4753,6 +4782,8 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4802,6 +4833,8 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -5318,6 +5351,7 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; + self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5359,6 +5393,7 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; + self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ec962d03458d1..a827d2c6bdbf2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2270,6 +2270,11 @@ impl<'a> State<'a> { self.print_expr(e)?; word(&mut self.s, "?")? } + ast::ExprKind::Catch(ref blk) => { + self.head("catch")?; + space(&mut self.s)?; + self.print_block_with_attrs(&blk, attrs)? + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c278171aa109a..6642c60d256b3 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,9 +221,10 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + (56, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (56, CrateRoot, "{{root}}") + (57, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..c76846cdf8e27 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -787,6 +787,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::Catch(ref body) => { + visitor.visit_block(body) + } } visitor.visit_expr_post(expression) diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs new file mode 100644 index 0000000000000..257cb802cc0f8 --- /dev/null +++ b/src/test/compile-fail/catch-empty-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs new file mode 100644 index 0000000000000..7aa162750d189 --- /dev/null +++ b/src/test/compile-fail/catch-enum-variant.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +enum Enum { + catch {} //~ ERROR cannot use `catch` as the name of a type +} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs new file mode 100644 index 0000000000000..63661ccf607a0 --- /dev/null +++ b/src/test/compile-fail/catch-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs new file mode 100644 index 0000000000000..1a8866d85430d --- /dev/null +++ b/src/test/compile-fail/catch-tuple-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs new file mode 100644 index 0000000000000..8a1a5ceae89e0 --- /dev/null +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +pub fn main() { + let catch_result = catch { //~ ERROR `catch` expression is experimental + let x = 5; + x + }; + assert_eq!(catch_result, 5); +} diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs new file mode 100644 index 0000000000000..c70b6100efe4f --- /dev/null +++ b/src/test/run-pass/catch-expr.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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. + +#![feature(catch_expr)] + +pub fn main() { + let catch_result = catch { + let x = 5; + x + }; + assert_eq!(catch_result, 5); + + let mut catch = true; + while catch { catch = false; } + assert_eq!(catch, false); + + catch = if catch { false } else { true }; + assert_eq!(catch, true); + + match catch { + _ => {} + }; +} From ace24bb653850e5955ec14cc6aef1af61022f85e Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 3 Mar 2017 14:41:07 -0800 Subject: [PATCH 19/73] Temporarily prefix catch block with do keyword --- src/libsyntax/parse/parser.rs | 18 +++++------------- src/libsyntax/parse/token.rs | 1 + .../compile-fail/catch-empty-struct-name.rs | 15 --------------- src/test/compile-fail/catch-enum-variant.rs | 17 ----------------- src/test/compile-fail/catch-struct-name.rs | 15 --------------- .../compile-fail/catch-tuple-struct-name.rs | 15 --------------- .../compile-fail/feature-gate-catch_expr.rs | 2 +- src/test/run-pass/catch-expr.rs | 4 +++- 8 files changed, 10 insertions(+), 77 deletions(-) delete mode 100644 src/test/compile-fail/catch-empty-struct-name.rs delete mode 100644 src/test/compile-fail/catch-enum-variant.rs delete mode 100644 src/test/compile-fail/catch-struct-name.rs delete mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index eef252319bcc2..c654ad066c861 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -515,12 +515,6 @@ impl<'a> Parser<'a> { } } - pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { - if ident.name == keywords::Catch.name() { - self.span_err(self.span, "cannot use `catch` as the name of a type"); - } - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2203,6 +2197,7 @@ impl<'a> Parser<'a> { attrs); } if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); let lo = self.prev_span.lo; return self.parse_catch_expr(lo, attrs); @@ -3017,7 +3012,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } - /// Parse a `catch {...}` expression (`catch` token already eaten) + /// Parse a `do catch {...}` expression (`do catch` token already eaten) pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) -> PResult<'a, P> { @@ -3635,8 +3630,9 @@ impl<'a> Parser<'a> { } fn is_catch_expr(&mut self) -> bool { - self.token.is_keyword(keywords::Catch) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) @@ -4782,7 +4778,6 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -4833,7 +4828,6 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -5351,7 +5345,6 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; - self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5393,7 +5386,6 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; - self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b81c..25601f2420e8a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -86,6 +86,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs deleted file mode 100644 index 257cb802cc0f8..0000000000000 --- a/src/test/compile-fail/catch-empty-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs deleted file mode 100644 index 7aa162750d189..0000000000000 --- a/src/test/compile-fail/catch-enum-variant.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -enum Enum { - catch {} //~ ERROR cannot use `catch` as the name of a type -} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs deleted file mode 100644 index 63661ccf607a0..0000000000000 --- a/src/test/compile-fail/catch-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs deleted file mode 100644 index 1a8866d85430d..0000000000000 --- a/src/test/compile-fail/catch-tuple-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs index 8a1a5ceae89e0..5568a5cf0aac2 100644 --- a/src/test/compile-fail/feature-gate-catch_expr.rs +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let catch_result = catch { //~ ERROR `catch` expression is experimental + let catch_result = do catch { //~ ERROR `catch` expression is experimental let x = 5; x }; diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index c70b6100efe4f..a9b28a534a348 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -10,8 +10,10 @@ #![feature(catch_expr)] +struct catch {} + pub fn main() { - let catch_result = catch { + let catch_result = do catch { let x = 5; x }; From 08d1c80f938255983de1adc51029eaeb5f7cb089 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Sat, 4 Mar 2017 14:03:46 +0300 Subject: [PATCH 20/73] LLVM: Update submodule to include SRet support patch for MSP430. --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm b/src/llvm index 50ab09fb43f03..859fb26936462 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621 +Subproject commit 859fb269364623b17e092efaba3f94e70ce97c5e diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 57f37ea050c1b..e30ad63d52f87 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-02 +2017-03-04 From 3055f419c7c61d90be69fbcd4770b48eaff03213 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 20 Feb 2017 14:42:47 -0500 Subject: [PATCH 21/73] add an #[used] attribute similar to GCC's __attribute((used))__. This attribute prevents LLVM from optimizing away a non-exported symbol, within a compilation unit (object file), when there are no references to it. This is better explained with an example: ``` #[used] static LIVE: i32 = 0; static REFERENCED: i32 = 0; static DEAD: i32 = 0; fn internal() {} pub fn exported() -> &'static i32 { &REFERENCED } ``` Without optimizations, LLVM pretty much preserves all the static variables and functions within the compilation unit. ``` $ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 t drop::h1be0f8f27a2ba94a 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 0000000000000000 t symbols::internal::h0ac1aadbc1e3a494 ``` With optimizations, LLVM will drop dead code. Here `internal` is dropped because it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for the same reason. `REFERENCED` is preserved, even though it's not exported, because it's referenced by the `exported` function. Finally, `LIVE` survives because of the `#[used]` attribute even though it's not exported or referenced. ``` $ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o 0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c 0000000000000000 r symbols::LIVE::h0970cf9889edb56e 0000000000000000 T symbols::exported::h6f096c2b1fc292b2 ``` Note that the linker knows nothing about `#[used]` and will drop `LIVE` because no other object references to it. ``` $ echo 'fn main() {}' >> symbols.rs $ rustc symbols.rs && nm -C symbols | grep LIVE ``` At this time, `#[used]` only works on `static` variables. --- src/librustc_trans/base.rs | 20 +++++++++++++++++++- src/librustc_trans/consts.rs | 4 ++++ src/librustc_trans/context.rs | 7 +++++++ src/libsyntax/feature_gate.rs | 7 +++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 36f6fa7643909..af9c6bca671d4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -55,7 +55,7 @@ use builder::Builder; use callee::{Callee}; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; -use common::{C_struct_in_context, C_u64, C_undef}; +use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; use common::{fulfill_obligation}; use common::{type_is_zero_size, val_ty}; @@ -1243,6 +1243,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Create llvm.used variable + if !ccx.used_statics().borrow().is_empty() { + debug!("llvm.used"); + + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.llmod(), + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + // Finalize debuginfo if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bf1d9886ae7f0..cc3ddeef53940 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -275,6 +275,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); + if attr::contains_name(attrs, "used") { + ccx.used_statics().borrow_mut().push(g); + } + Ok(g) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5f7549ece07b..77c80d2a2361d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -136,6 +136,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, + used_statics: RefCell>, + lltypes: RefCell, Type>>, llsizingtypes: RefCell, Type>>, type_hashcodes: RefCell, String>>, @@ -606,6 +608,7 @@ impl<'tcx> LocalCrateContext<'tcx> { impl_method_cache: RefCell::new(FxHashMap()), closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), llsizingtypes: RefCell::new(FxHashMap()), type_hashcodes: RefCell::new(FxHashMap()), @@ -786,6 +789,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } + pub fn used_statics<'a>(&'a self) -> &'a RefCell> { + &self.local().used_statics + } + pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().lltypes } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6eb7d449f2692..cafb622ea4691 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -340,6 +340,9 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Used to preserve symbols + (active, used, "1.17.0", None), ); declare_features! ( @@ -743,6 +746,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, From cd7bde99b127e6d7476de047ba3a5bcb0c2c25df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Jan 2017 23:17:48 -0800 Subject: [PATCH 22/73] Point to enclosing block/fn on nested unsafe When declaring nested unsafe blocks (`unsafe {unsafe {}}`) that trigger the "unnecessary `unsafe` block" error, point out the enclosing `unsafe block` or `unsafe fn` that makes it unnecessary. --- src/librustc_lint/unused.rs | 29 ++++- .../span}/lint-unused-unsafe.rs | 0 src/test/ui/span/lint-unused-unsafe.stderr | 116 ++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) rename src/test/{compile-fail => ui/span}/lint-unused-unsafe.rs (100%) create mode 100644 src/test/ui/span/lint-unused-unsafe.stderr diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 28ce9126019eb..f9b7c68587678 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -189,11 +189,38 @@ impl LintPass for UnusedUnsafe { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + /// Return the NodeId for an enclosing scope that is also `unsafe` + fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> { + let parent_id = cx.tcx.hir.get_parent_node(id); + if parent_id != id { + if cx.tcx.used_unsafe.borrow().contains(&parent_id) { + Some(("block".to_string(), parent_id)) + } else if let Some(hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _), + .. + })) = cx.tcx.hir.find(parent_id) { + Some(("fn".to_string(), parent_id)) + } else { + is_enclosed(cx, parent_id) + } + } else { + None + } + } if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && !cx.tcx.used_unsafe.borrow().contains(&blk.id) { - cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); + + let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span, + "unnecessary `unsafe` block"); + + db.span_label(blk.span, &"unnecessary `unsafe` block"); + if let Some((kind, id)) = is_enclosed(cx, blk.id) { + db.span_note(cx.tcx.hir.span(id), + &format!("because it's nested under this `unsafe` {}", kind)); + } + db.emit(); } } } diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs similarity index 100% rename from src/test/compile-fail/lint-unused-unsafe.rs rename to src/test/ui/span/lint-unused-unsafe.rs diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr new file mode 100644 index 0000000000000..0df3fa43022a4 --- /dev/null +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -0,0 +1,116 @@ +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:26:13 + | +26 | fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: lint level defined here + --> $DIR/lint-unused-unsafe.rs:14:9 + | +14 | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:27:13 + | +27 | fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:28:20 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:28:1 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:29:13 + | +29 | fn bad4() { unsafe { callback(||{}) } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:30:20 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:30:1 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:33:9 + | +33 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +34 | | unsf() +35 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` block + --> $DIR/lint-unused-unsafe.rs:32:5 + | +32 | unsafe { // don't put the warning here + | _____^ starting here... +33 | | unsafe { //~ ERROR: unnecessary `unsafe` block +34 | | unsf() +35 | | } +36 | | } + | |_____^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:39:5 + | +39 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _____^ starting here... +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } + | |_____^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:40:9 + | +40 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +41 | | unsf() +42 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: aborting due to 8 previous errors + From 9918471ee8d857d7aafd30947968e18563659ad1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 5 Mar 2017 23:03:42 -0500 Subject: [PATCH 23/73] add tracking issue and feature-gate and run-make tests --- src/libsyntax/feature_gate.rs | 2 +- src/test/compile-fail/feature-gate-used.rs | 15 +++++++++++++++ src/test/run-make/used/Makefile | 12 ++++++++++++ src/test/run-make/used/used.rs | 17 +++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/feature-gate-used.rs create mode 100644 src/test/run-make/used/Makefile create mode 100644 src/test/run-make/used/used.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cafb622ea4691..cd25303c0c965 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -342,7 +342,7 @@ declare_features! ( (active, abi_x86_interrupt, "1.17.0", Some(40180)), // Used to preserve symbols - (active, used, "1.17.0", None), + (active, used, "1.17.0", Some(40289)), ); declare_features! ( diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs new file mode 100644 index 0000000000000..68679d7dac896 --- /dev/null +++ b/src/test/compile-fail/feature-gate-used.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile new file mode 100644 index 0000000000000..70ac2e3802b81 --- /dev/null +++ b/src/test/run-make/used/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +all: + $(RUSTC) -C opt-level=3 --emit=obj used.rs + nm -C used.o | grep FOO + nm -C used.o | grep -v BAR +endif diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs new file mode 100644 index 0000000000000..186cd0fdf5e35 --- /dev/null +++ b/src/test/run-make/used/used.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +#![crate_type = "lib"] +#![feature(used)] + +#[used] +static FOO: u32 = 0; + +static BAR: u32 = 0; From 6f3f4672e4138637fc9758155854d8186918284e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 5 Mar 2017 23:51:46 -0300 Subject: [PATCH 24/73] Fix incorrect span label formatting --- src/librustc_errors/emitter.rs | 62 ++++++++++++++++------------- src/test/ui/span/issue-40157.rs | 13 ++++++ src/test/ui/span/issue-40157.stderr | 14 +++++++ 3 files changed, 61 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/span/issue-40157.rs create mode 100644 src/test/ui/span/issue-40157.stderr diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0b0a9e51cacb0..431edb3c9bc4d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -358,39 +358,45 @@ impl EmitterWriter { let mut annotations_position = vec![]; let mut line_len = 0; let mut p = 0; - let mut ann_iter = annotations.iter().peekable(); - while let Some(annotation) = ann_iter.next() { - let peek = ann_iter.peek(); - if let Some(next) = peek { - if overlaps(next, annotation) && !annotation.is_line() && !next.is_line() + for (i, annotation) in annotations.iter().enumerate() { + for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) // This label overlaps with another one and both + && !annotation.is_line() // take space (they have text and are not + && !next.is_line() // multiline lines). && annotation.has_label() + && j > i + && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. p += 1; + break; } } annotations_position.push((p, annotation)); - if let Some(next) = peek { - let l = if let Some(ref label) = next.label { - label.len() + 2 - } else { - 0 - }; - if (overlaps(next, annotation) // Do not allow two labels to be in the same line - || next.end_col + l > annotation.start_col) // if they overlap including - // padding, to avoid situations like: - // - // fn foo(x: u32) { - // -------^------ - // | | - // fn_spanx_span - // - && !annotation.is_line() // Do not add a new line if this annotation or the - && !next.is_line() // next are vertical line placeholders. - && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. - { - p += 1; + for (j, next) in annotations.iter().enumerate() { + if j > i { + let l = if let Some(ref label) = next.label { + label.len() + 2 + } else { + 0 + }; + if overlaps(next, annotation, l) // Do not allow two labels to be in the same + // line if they overlap including padding, to + // avoid situations like: + // + // fn foo(x: u32) { + // -------^------ + // | | + // fn_spanx_span + // + && !annotation.is_line() // Do not add a new line if this annotation + && !next.is_line() // or the next are vertical line placeholders. + && annotation.has_label() // Both labels must have some text, otherwise + && next.has_label() // they are not overlapping. + { + p += 1; + break; + } } } if line_len < p { @@ -1088,8 +1094,8 @@ fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclus (b_start..b_end + extra).contains(a_start) || (a_start..a_end + extra).contains(b_start) } -fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false) +fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { + num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false) } fn emit_to_destination(rendered_buffer: &Vec>, diff --git a/src/test/ui/span/issue-40157.rs b/src/test/ui/span/issue-40157.rs new file mode 100644 index 0000000000000..8f3a7ae341736 --- /dev/null +++ b/src/test/ui/span/issue-40157.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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. + +fn main () { + {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} +} diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr new file mode 100644 index 0000000000000..ad1c149d2e56f --- /dev/null +++ b/src/test/ui/span/issue-40157.stderr @@ -0,0 +1,14 @@ +error: `foo` does not live long enough + --> $DIR/issue-40157.rs:12:64 + | +12 | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} + | ----------------------------------------------------------^------------- + | | | | + | | | `foo` dropped here while still borrowed + | | borrow occurs here + | borrowed value needs to live until here + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + From 0cb9b23389246c319d57d355d84596608cb41ea0 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 6 Mar 2017 11:18:56 -0500 Subject: [PATCH 25/73] fix location of the emitted object file --- src/test/run-make/used/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile index 70ac2e3802b81..650464e4d8454 100644 --- a/src/test/run-make/used/Makefile +++ b/src/test/run-make/used/Makefile @@ -7,6 +7,6 @@ all: else all: $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm -C used.o | grep FOO - nm -C used.o | grep -v BAR + nm -C $(TMPDIR)/used.o | grep FOO + nm -C $(TMPDIR)/used.o | grep -v BAR endif From eeb7af61164c6f7bf0d328f90793a3ad48d39529 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 1 Mar 2017 15:34:54 -0800 Subject: [PATCH 26/73] rustbuild: Build documentation for `proc_macro` This commit fixes #38749 by building documentation for the `proc_macro` crate by default for configured hosts. Unfortunately did not turn out to be a trivial fix. Currently rustbuild generates documentation into multiple locations: one for std, one for test, and one for rustc. The initial fix for this issue simply actually executed `cargo doc -p proc_macro` which was otherwise completely elided before. Unfortunately rustbuild was the left to merge two documentation trees together. One for the standard library and one for the rustc tree (which only had docs for the `proc_macro` crate). Rustdoc itself knows how to merge documentation files (specifically around search indexes, etc) but rustbuild was unaware of this, so an initial fix ended up destroying the sidebar and the search bar from the libstd docs. To solve this issue the method of documentation has been tweaked slightly in rustbuild. The build system will not use symlinks (or directory junctions on Windows) to generate all documentation into the same location initially. This'll rely on rustdoc's logic to weave together all the output and ensure that it ends up all consistent. Closes #38749 --- src/bootstrap/doc.rs | 63 +++++++++++++++--- src/bootstrap/lib.rs | 7 ++ src/bootstrap/step.rs | 2 +- src/bootstrap/util.rs | 139 +++++++++++++++++++++++++++++++++++++++ src/libproc_macro/lib.rs | 2 +- 5 files changed, 202 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d19e5b1b88456..9c3f0ce62f349 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -19,10 +19,12 @@ use std::fs::{self, File}; use std::io::prelude::*; +use std::io; +use std::path::Path; use std::process::Command; use {Build, Compiler, Mode}; -use util::cp_r; +use util::{cp_r, symlink_dir}; use build_helper::up_to_date; /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book @@ -141,7 +143,22 @@ pub fn std(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // Here what we're doing is creating a *symlink* (directory junction on + // Windows) to the final output location. This is not done as an + // optimization but rather for correctness. We've got three trees of + // documentation, one for std, one for test, and one for rustc. It's then + // our job to merge them all together. + // + // Unfortunately rustbuild doesn't know nearly as well how to merge doc + // trees as rustdoc does itself, so instead of actually having three + // separate trees we just have rustdoc output to the same location across + // all of them. + // + // This way rustdoc generates output directly into the output, and rustdoc + // will also directly handle merging. + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc"); cargo.arg("--manifest-path") @@ -166,7 +183,7 @@ pub fn std(build: &Build, stage: u32, target: &str) { build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Compile all libtest documentation. @@ -187,13 +204,16 @@ pub fn test(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generate all compiler documentation. @@ -213,15 +233,28 @@ pub fn rustc(build: &Build, stage: u32, target: &str) { let out_dir = build.stage_out(&compiler, Mode::Librustc) .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() { - t!(fs::remove_dir_all(&out_dir)); - } + + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); + let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")) .arg("--features").arg(build.rustc_features()); + + // Like with libstd above if compiler docs aren't enabled then we're not + // documenting internal dependencies, so we have a whitelist. + if !build.config.compiler_docs { + cargo.arg("--no-deps"); + for krate in &["proc_macro"] { + cargo.arg("-p").arg(krate); + } + } + build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generates the HTML rendered error-index by running the @@ -240,3 +273,15 @@ pub fn error_index(build: &Build, target: &str) { build.run(&mut index); } + +fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { + if let Ok(m) = fs::symlink_metadata(dst) { + if m.file_type().is_dir() { + try!(fs::remove_dir_all(dst)); + } else { + try!(fs::remove_file(dst)); + } + } + + symlink_dir(src, dst) +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 98b68d870d375..5a5f36f1a4c9f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -707,6 +707,13 @@ impl Build { self.out.join(target).join("doc") } + /// Output directory for all crate documentation for a target (temporary) + /// + /// The artifacts here are then copied into `doc_out` above. + fn crate_doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("crate-docs") + } + /// Returns true if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index a5c0d11d21985..c24a555280ba9 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -640,7 +640,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc(&krate.doc_step, path) .dep(|s| s.name("librustc-link")) .host(true) - .default(default && build.config.compiler_docs) + .default(default && build.config.docs) .run(move |s| doc::rustc(build, s.stage, s.target)); } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 520514f5fc95a..be427b39c682f 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -16,6 +16,7 @@ use std::env; use std::ffi::OsString; use std::fs; +use std::io; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; @@ -175,3 +176,141 @@ impl Drop for TimeIt { time.subsec_nanos() / 1_000_000); } } + +/// Symlinks two directories, using junctions on Windows and normal symlinks on +/// Unix. +pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> { + let _ = fs::remove_dir(dest); + return symlink_dir_inner(src, dest); + + #[cfg(not(windows))] + fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> { + use std::os::unix::fs; + fs::symlink(src, dest) + } + + // Creating a directory junction on windows involves dealing with reparse + // points and the DeviceIoControl function, and this code is a skeleton of + // what can be found here: + // + // http://www.flexhex.com/docs/articles/hard-links.phtml + // + // Copied from std + #[cfg(windows)] + #[allow(bad_style)] + fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { + use std::ptr; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; + const GENERIC_WRITE: DWORD = 0x40000000; + const OPEN_EXISTING: DWORD = 3; + const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; + const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; + const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; + const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; + const FILE_SHARE_DELETE: DWORD = 0x4; + const FILE_SHARE_READ: DWORD = 0x1; + const FILE_SHARE_WRITE: DWORD = 0x2; + + type BOOL = i32; + type DWORD = u32; + type HANDLE = *mut u8; + type LPCWSTR = *const u16; + type LPDWORD = *mut DWORD; + type LPOVERLAPPED = *mut u8; + type LPSECURITY_ATTRIBUTES = *mut u8; + type LPVOID = *mut u8; + type WCHAR = u16; + type WORD = u16; + + #[repr(C)] + struct REPARSE_MOUNTPOINT_DATA_BUFFER { + ReparseTag: DWORD, + ReparseDataLength: DWORD, + Reserved: WORD, + ReparseTargetLength: WORD, + ReparseTargetMaximumLength: WORD, + Reserved1: WORD, + ReparseTarget: WCHAR, + } + + extern "system" { + fn CreateFileW(lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE) + -> HANDLE; + fn DeviceIoControl(hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED) -> BOOL; + } + + fn to_u16s>(s: S) -> io::Result> { + Ok(s.as_ref().encode_wide().chain(Some(0)).collect()) + } + + // We're using low-level APIs to create the junction, and these are more + // picky about paths. For example, forward slashes cannot be used as a + // path separator, so we should try to canonicalize the path first. + let target = try!(fs::canonicalize(target)); + + try!(fs::create_dir(junction)); + + let path = try!(to_u16s(junction)); + + unsafe { + let h = CreateFileW(path.as_ptr(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0 as *mut _, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut()); + + let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; + let buf = &mut (*db).ReparseTarget as *mut _; + let mut i = 0; + // FIXME: this conversion is very hacky + let v = br"\??\"; + let v = v.iter().map(|x| *x as u16); + for c in v.chain(target.as_os_str().encode_wide().skip(4)) { + *buf.offset(i) = c; + i += 1; + } + *buf.offset(i) = 0; + i += 1; + (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + (*db).ReparseTargetMaximumLength = (i * 2) as WORD; + (*db).ReparseTargetLength = ((i - 1) * 2) as WORD; + (*db).ReparseDataLength = + (*db).ReparseTargetLength as DWORD + 12; + + let mut ret = 0; + let res = DeviceIoControl(h as *mut _, + FSCTL_SET_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + ptr::null_mut(), 0, + &mut ret, + ptr::null_mut()); + + if res == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 8d7fe655c23b2..0d2a467b57702 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -21,7 +21,7 @@ //! This functionality is intended to be expanded over time as more surface //! area for macro authors is stabilized. //! -//! See [the book](../../book/procedural-macros.html) for more. +//! See [the book](../book/procedural-macros.html) for more. #![crate_name = "proc_macro"] #![stable(feature = "proc_macro_lib", since = "1.15.0")] From 4008e71da3662ecad021087c35d9fc8ac3096741 Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Mon, 6 Mar 2017 21:42:55 +0100 Subject: [PATCH 27/73] Support armhf abi on 64-bit ARM cpus They report their `uname -m` as armv8l rather than aarch64. Patch originally by Matthias Klose --- configure | 2 +- src/bootstrap/bootstrap.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index be8628de62832..d8861dacafac1 100755 --- a/configure +++ b/configure @@ -512,7 +512,7 @@ case $CFG_CPUTYPE in CFG_OSTYPE="${CFG_OSTYPE}eabihf" ;; - armv7l) + armv7l | armv8l) CFG_CPUTYPE=armv7 CFG_OSTYPE="${CFG_OSTYPE}eabihf" ;; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c1ee0c29ac981..04903893741d7 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -464,7 +464,7 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype == 'armv7l': + elif cputype in {'armv7l', 'armv8l'}: cputype = 'arm' ostype += 'eabihf' elif cputype == 'aarch64': From 7cf30f3e5e069731b1b3d0aabea4e6608f24b17d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 5 Mar 2017 05:15:58 +0000 Subject: [PATCH 28/73] Refactor out `ast::ItemKind::MacroDef`. --- src/librustc/hir/lowering.rs | 51 ++++++++++-------- src/librustc/hir/map/def_collector.rs | 6 +-- src/librustc/middle/cstore.rs | 2 +- src/librustc_driver/driver.rs | 3 -- src/librustc_metadata/cstore_impl.rs | 6 ++- src/librustc_passes/hir_stats.rs | 5 -- src/librustc_resolve/build_reduced_graph.rs | 34 ++++++------ src/librustc_resolve/lib.rs | 15 ++---- src/librustc_resolve/macros.rs | 53 +++++++------------ src/librustdoc/visit_ast.rs | 12 +++-- src/libsyntax/ast.rs | 27 +++------- src/libsyntax/ext/base.rs | 6 +-- src/libsyntax/ext/expand.rs | 17 ++---- src/libsyntax/ext/hygiene.rs | 2 +- src/libsyntax/ext/placeholders.rs | 15 ------ src/libsyntax/ext/tt/macro_rules.rs | 10 ++-- src/libsyntax/fold.rs | 11 ++-- src/libsyntax/parse/parser.rs | 46 ++++++++++++++-- src/libsyntax/print/pprust.rs | 11 +++- src/libsyntax/util/node_count.rs | 5 -- src/libsyntax/visit.rs | 10 +--- src/libsyntax_ext/deriving/mod.rs | 2 +- src/libsyntax_ext/lib.rs | 2 +- src/libsyntax_ext/proc_macro_registrar.rs | 16 +++--- .../pretty-expanded-hygiene/input.pp.rs | 1 + 25 files changed, 172 insertions(+), 196 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..f9f63ccbfde7e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -79,6 +79,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: BTreeMap, + exported_macros: Vec, trait_impls: BTreeMap>, trait_default_impl: BTreeMap, @@ -121,6 +122,7 @@ pub fn lower_crate(sess: &Session, bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), + exported_macros: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -170,9 +172,10 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { - let hir_item = self.lctx.lower_item(item); - self.lctx.items.insert(item.id, hir_item); - visit::walk_item(self, item); + if let Some(hir_item) = self.lctx.lower_item(item) { + self.lctx.items.insert(item.id, hir_item); + visit::walk_item(self, item); + } } fn visit_trait_item(&mut self, item: &'lcx TraitItem) { @@ -195,14 +198,13 @@ impl<'a> LoweringContext<'a> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); - let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); let body_ids = body_ids(&self.bodies); hir::Crate { module: module, attrs: attrs, span: c.span, - exported_macros: exported_macros, + exported_macros: hir::HirVec::from(self.exported_macros), items: self.items, trait_items: self.trait_items, impl_items: self.impl_items, @@ -1134,7 +1136,7 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::Mac(_) => panic!("Shouldn't still be around"), + ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } } @@ -1256,42 +1258,45 @@ impl<'a> LoweringContext<'a> { } } - fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef { - hir::MacroDef { - name: m.ident.name, - attrs: self.lower_attrs(&m.attrs), - id: m.id, - span: m.span, - body: m.body.clone().into(), - } - } - fn lower_item_id(&mut self, i: &Item) -> SmallVector { - if let ItemKind::Use(ref view_path) = i.node { - if let ViewPathList(_, ref imports) = view_path.node { - return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) - .map(|id| hir::ItemId { id: id }).collect(); + match i.node { + ItemKind::Use(ref view_path) => { + if let ViewPathList(_, ref imports) = view_path.node { + return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) + .map(|id| hir::ItemId { id: id }).collect(); + } } + ItemKind::MacroDef(..) => return SmallVector::new(), + _ => {} } SmallVector::one(hir::ItemId { id: i.id }) } - pub fn lower_item(&mut self, i: &Item) -> hir::Item { + pub fn lower_item(&mut self, i: &Item) -> Option { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); + if let ItemKind::MacroDef(ref tts, _) = i.node { + if i.attrs.iter().any(|attr| attr.name() == "macro_export") { + self.exported_macros.push(hir::MacroDef { + name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), + }); + } + return None; + } + let node = self.with_parent_def(i.id, |this| { this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); - hir::Item { + Some(hir::Item { id: i.id, name: name, attrs: attrs, node: node, vis: vis, span: i.span, - } + }) } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index ccaf663c7ad2a..f15e063e81e33 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -108,7 +108,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::Use(ref view_path) => { match view_path.node { @@ -269,10 +269,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); } - fn visit_macro_def(&mut self, macro_def: &'a MacroDef) { - self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); - } - fn visit_stmt(&mut self, stmt: &'a Stmt) { match stmt.node { StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4a7027b8997a5..e9fb4632fa178 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -136,7 +136,7 @@ pub struct NativeLibrary { } pub enum LoadedMacro { - MacroRules(ast::MacroDef), + MacroDef(ast::Item), ProcMacro(Rc), } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..e458d45bbd6e8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -43,7 +43,6 @@ use super::Compilation; use serialize::json; use std::env; -use std::mem; use std::ffi::{OsString, OsStr}; use std::fs; use std::io::{self, Write}; @@ -705,8 +704,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate }); - krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); - krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &mut resolver, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cf2219e0e3df5..cfe67726ab228 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -34,6 +34,7 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; +use syntax::ext::hygiene::Mark; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{mk_sp, Span}; @@ -414,12 +415,13 @@ impl CrateStore for cstore::CStore { sess.imported_macro_spans.borrow_mut() .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); - LoadedMacro::MacroRules(ast::MacroDef { + LoadedMacro::MacroDef(ast::Item { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs, - body: body.into(), + node: ast::ItemKind::MacroDef(body.into(), Mark::fresh()), + vis: ast::Visibility::Inherited, }) } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 65a60732fc807..749146fe49672 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -375,9 +375,4 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.record("Attribute", Id::None, attr); } - - fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) { - self.record("MacroDef", Id::None, macro_def); - ast_visit::walk_macro_def(self, macro_def) - } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index da08d1b7c78e2..8b20c31be03b7 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -37,7 +37,6 @@ use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; -use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token; @@ -373,7 +372,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } - ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } @@ -502,22 +501,21 @@ impl<'a> Resolver<'a> { return ext.clone(); } - let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + let macro_def = match self.session.cstore.load_macro(def_id, &self.session) { + LoadedMacro::MacroDef(macro_def) => macro_def, LoadedMacro::ProcMacro(ext) => return ext, }; - let mark = Mark::fresh(); let invocation = self.arenas.alloc_invocation_data(InvocationData { module: Cell::new(self.get_extern_crate_root(def_id.krate)), - def_index: CRATE_DEF_INDEX, - const_expr: false, - legacy_scope: Cell::new(LegacyScope::Empty), - expansion: Cell::new(LegacyScope::Empty), + // FIXME(jseyfried) the following are irrelevant + def_index: CRATE_DEF_INDEX, const_expr: false, + legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), }); - self.invocations.insert(mark, invocation); - macro_rules.body = mark_tts(macro_rules.stream(), mark).into(); - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules)); + if let ast::ItemKind::MacroDef(_, mark) = macro_def.node { + self.invocations.insert(mark, invocation); + } + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext } @@ -707,12 +705,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { fn visit_item(&mut self, item: &'a Item) { let macro_use = match item.node { - ItemKind::Mac(ref mac) => { - if mac.node.path.segments.is_empty() { - self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); - } else { - self.resolver.define_macro(item, &mut self.legacy_scope); - } + ItemKind::MacroDef(..) => { + self.resolver.define_macro(item, &mut self.legacy_scope); + return + } + ItemKind::Mac(..) => { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); return } ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 093994ba8257d..0f55b53acee26 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1065,10 +1065,6 @@ pub struct Resolver<'a> { pub definitions: Definitions, - // Maps the node id of a statement to the expansions of the `macro_rules!`s - // immediately above the statement (if appropriate). - macros_at_scope: FxHashMap>, - graph_root: Module<'a>, prelude: Option>, @@ -1144,7 +1140,6 @@ pub struct Resolver<'a> { dummy_binding: &'a NameBinding<'a>, use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` - pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, builtin_macros: FxHashMap>, @@ -1282,7 +1277,6 @@ impl<'a> Resolver<'a> { session: session, definitions: definitions, - macros_at_scope: FxHashMap(), // The outermost module has def ID 0; this is not reflected in the // AST. @@ -1338,7 +1332,6 @@ impl<'a> Resolver<'a> { // `#![feature(proc_macro)]` implies `#[feature(extern_macros)]` use_extern_macros: features.use_extern_macros || features.proc_macro, - exported_macros: Vec::new(), crate_loader: crate_loader, macro_names: FxHashSet(), builtin_macros: FxHashMap(), @@ -1669,7 +1662,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { // do nothing, these are just around to be encoded } @@ -1974,9 +1967,9 @@ impl<'a> Resolver<'a> { // Descend into the block. for stmt in &block.stmts { - if let Some(marks) = self.macros_at_scope.remove(&stmt.id) { - num_macro_definition_ribs += marks.len() as u32; - for mark in marks { + if let ast::StmtKind::Item(ref item) = stmt.node { + if let ast::ItemKind::MacroDef(_, mark) = item.node { + num_macro_definition_ribs += 1; self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); self.label_ribs.push(Rib::new(MacroDefinition(mark))); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..fc6b1baca160b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -25,7 +25,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; use syntax::ext::base::MacroKind; -use syntax::ext::expand::{Expansion, mark_tts}; +use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; @@ -33,7 +33,6 @@ use syntax::fold::{self, Folder}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::Visitor; use syntax_pos::{Span, DUMMY_SP}; #[derive(Clone)] @@ -151,7 +150,7 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.expansion.set(visitor.legacy_scope); } - fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc) { let def_id = DefId { krate: BUILTIN_MACROS_CRATE, index: DefIndex::new(self.macro_map.len()), @@ -167,10 +166,6 @@ impl<'a> base::Resolver for Resolver<'a> { self.builtin_macros.insert(ident.name, binding); } - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { - self.macros_at_scope.insert(id, macros); - } - fn resolve_imports(&mut self) { ImportResolver { resolver: self }.resolve_imports() } @@ -544,45 +539,33 @@ impl<'a> Resolver<'a> { } pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { - let tts = match item.node { - ast::ItemKind::Mac(ref mac) => mac.node.stream(), - _ => unreachable!(), - }; - if item.ident.name == "macro_rules" { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } - let mark = Mark::from_placeholder_id(item.id); - let invocation = self.invocations[&mark]; - invocation.module.set(self.current_module); - - let mut def = ast::MacroDef { - ident: item.ident, - attrs: item.attrs.clone(), - id: ast::DUMMY_NODE_ID, - span: item.span, - body: mark_tts(tts, mark).into(), - }; + let invocation = self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(self.current_module), + // FIXME(jseyfried) the following are irrelevant + def_index: CRATE_DEF_INDEX, const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), + }); + if let ast::ItemKind::MacroDef(_, mark) = item.node { + self.invocations.insert(mark, invocation); + } *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { parent: Cell::new(*legacy_scope), - name: def.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - span: def.span, + name: item.ident.name, + ext: Rc::new(macro_rules::compile(&self.session.parse_sess, item)), + span: item.span, })); - self.macro_names.insert(def.ident.name); + self.macro_names.insert(item.ident.name); - if attr::contains_name(&def.attrs, "macro_export") { - def.id = self.next_node_id(); - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(&def) - }); + if attr::contains_name(&item.attrs, "macro_export") { self.macro_exports.push(Export { - name: def.ident.name, - def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang), + name: item.ident.name, + def: Def::Macro(self.definitions.local_def_id(item.id), MacroKind::Bang), }); - self.exported_macros.push(def); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 42928427233d7..35d459422033f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -16,6 +16,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; +use syntax::tokenstream::TokenStream; use syntax_pos::Span; use rustc::hir::map as hir_map; @@ -205,14 +206,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + LoadedMacro::MacroDef(macro_def) => macro_def, // FIXME(jseyfried): document proc macro reexports LoadedMacro::ProcMacro(..) => continue, }; - // FIXME(jseyfried) merge with `self.visit_macro()` - let tts = def.stream().trees().collect::>(); - let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); + let matchers = if let ast::ItemKind::MacroDef(ref tokens, _) = def.node { + let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); + tts.chunks(4).map(|arm| arm[0].span()).collect() + } else { + unreachable!() + }; om.macros.push(Macro { def_id: def_id, attrs: def.attrs.clone().into(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..a79cfc2bceb33 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::SyntaxContext; +use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; use symbol::{Symbol, keywords}; @@ -414,7 +414,6 @@ pub struct Crate { pub module: Mod, pub attrs: Vec, pub span: Span, - pub exported_macros: Vec, } /// A spanned compile-time attribute list item. @@ -1855,10 +1854,13 @@ pub enum ItemKind { Option, // (optional) trait this impl implements P, // self Vec), - /// A macro invocation (which includes macro definition). + /// A macro invocation. /// /// E.g. `macro_rules! foo { .. }` or `foo!(..)` Mac(Mac), + + /// A macro definition. + MacroDef(ThinTokenStream, Mark /* FIXME(jseyfried) remove this */), } impl ItemKind { @@ -1877,6 +1879,7 @@ impl ItemKind { ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::Mac(..) | + ItemKind::MacroDef(..) | ItemKind::Impl(..) | ItemKind::DefaultImpl(..) => "item" } @@ -1912,24 +1915,6 @@ impl ForeignItemKind { } } -/// A macro definition, in this crate or imported from another. -/// -/// Not parsed directly, but created on macro import or `macro_rules!` expansion. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct MacroDef { - pub ident: Ident, - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub body: ThinTokenStream, -} - -impl MacroDef { - pub fn stream(&self) -> TokenStream { - self.body.clone().into() - } -} - #[cfg(test)] mod tests { use serialize; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e242cf2777fe5..39d919106147d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -552,8 +552,7 @@ pub trait Resolver { fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); - fn add_ext(&mut self, ident: ast::Ident, ext: Rc); - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc); fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. @@ -577,8 +576,7 @@ impl Resolver for DummyResolver { fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} - fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} - fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc) {} fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..8451414ec3d8a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -948,17 +948,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); - let is_macro_def = if let ItemKind::Mac(ref mac) = item.node { - mac.node.path.segments[0].identifier.name == "macro_rules" - } else { - unreachable!() - }; - - item.and_then(|mut item| match item.node { - ItemKind::Mac(_) if is_macro_def => { - item.id = Mark::fresh().as_placeholder_id(); - SmallVector::one(P(item)) - } + item.and_then(|item| match item.node { ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, @@ -1078,7 +1068,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - noop_fold_item_kind(self.cfg.configure_item_kind(item), self) + match item { + ast::ItemKind::MacroDef(..) => item, + _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self), + } } fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 2af5c2ea9995e..83c51bb9d2fcf 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -31,7 +31,7 @@ pub struct SyntaxContextData { } /// A mark is a unique id associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)] pub struct Mark(u32); impl Mark { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index e2fb1946e90db..f60b1d17a5e2f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -21,7 +21,6 @@ use util::move_map::MoveMap; use util::small_vector::SmallVector; use std::collections::HashMap; -use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { @@ -174,20 +173,11 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_block(&mut self, block: P) -> P { noop_fold_block(block, self).map(|mut block| { - let mut macros = Vec::new(); let mut remaining_stmts = block.stmts.len(); block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - // `macro_rules!` macro definition - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(_) = item.node { - macros.push(Mark::from_placeholder_id(item.id)); - return None; - } - } - match stmt.node { // Avoid wasting a node id on a trailing expression statement, // which shares a HIR node with the expression itself. @@ -201,11 +191,6 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { _ => {} } - if self.monotonic && !macros.is_empty() { - let macros = mem::replace(&mut macros, Vec::new()); - self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); - } - Some(stmt) }); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1d386c1a3ac93..8ad679b853e85 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,7 +12,7 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::expand::{Expansion, ExpansionKind}; +use ext::expand::{Expansion, ExpansionKind, mark_tts}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -153,7 +153,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -183,7 +183,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { ]; // Parse the macro_rules! invocation - let argument_map = match parse(sess, def.body.clone().into(), &argument_gram, None) { + let body = match def.node { + ast::ItemKind::MacroDef(ref body, mark) => mark_tts(body.clone().into(), mark), + _ => unreachable!(), + }; + let argument_map = match parse(sess, body, &argument_gram, None) { Success(m) => m, Failure(sp, tok) => { let s = parse_failure_msg(tok); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..d23f880bc7bac 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -899,6 +899,8 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { items.move_flat_map(|item| folder.fold_trait_item(item)), ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), + ItemKind::MacroDef(tts, mark) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into(), + mark), } } @@ -959,7 +961,7 @@ pub fn noop_fold_mod(Mod {inner, items}: Mod, folder: &mut T) -> Mod } } -pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, span}: Crate, +pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, folder: &mut T) -> Crate { let mut items = folder.fold_item(P(ast::Item { ident: keywords::Invalid.ident(), @@ -987,14 +989,9 @@ pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, spa }, vec![], span) }; - for def in &mut exported_macros { - def.id = folder.new_id(def.id); - } - Crate { module: module, attrs: attrs, - exported_macros: exported_macros, span: span, } } @@ -1387,6 +1384,6 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); + "macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..d81732489dd3d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,6 +43,7 @@ use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; +use ext::hygiene::Mark; use parse::{self, classify, token}; use parse::common::SeqSep; use parse::lexer::TokenAndSpan; @@ -1048,7 +1049,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead(&mut self, dist: usize, f: F) -> R where + pub fn look_ahead(&self, dist: usize, f: F) -> R where F: FnOnce(&token::Token) -> R, { if dist == 0 { @@ -3699,11 +3700,41 @@ impl<'a> Parser<'a> { }) } - fn is_union_item(&mut self) -> bool { + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) } + fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) + -> PResult<'a, Option>> { + let lo = self.span.lo; + match self.token { + token::Ident(ident) if ident.name == "macro_rules" => { + if self.look_ahead(1, |t| *t == token::Not) { + let prev_span = self.prev_span; + self.complain_if_pub_macro(vis, prev_span); + self.bump(); + self.bump(); + } + } + _ => return Ok(None), + }; + + let id = self.parse_ident()?; + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != token::Brace { + if !self.eat(&token::Semi) { + let msg = "macros that expand to items must either be surrounded with braces \ + or followed by a semicolon"; + self.span_err(self.prev_span, msg); + } + } + + let hi = self.prev_span.hi; + let kind = ItemKind::MacroDef(tts, Mark::fresh()); + Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + } + fn parse_stmt_without_recovery(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { @@ -3718,6 +3749,12 @@ impl<'a> Parser<'a> { node: StmtKind::Local(self.parse_local(attrs.into())?), span: mk_sp(lo, self.prev_span.hi), } + } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { + Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Item(macro_def), + span: mk_sp(lo, self.prev_span.hi), + } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && !self.token.is_qpath_start() && @@ -5767,6 +5804,10 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility)? { + return Ok(Some(macro_def)); + } + self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) } @@ -5948,7 +5989,6 @@ impl<'a> Parser<'a> { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, span: mk_sp(lo, self.span.lo), - exported_macros: Vec::new(), }) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 53ef8e8dfa49c..78212fb4b447c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1318,7 +1318,6 @@ impl<'a> State<'a> { self.bclose(item.span)?; } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { - self.print_visibility(&item.vis)?; self.print_path(&node.path, false, 0, false)?; word(&mut self.s, "! ")?; self.print_ident(item.ident)?; @@ -1329,6 +1328,16 @@ impl<'a> State<'a> { word(&mut self.s, ";")?; self.end()?; } + ast::ItemKind::MacroDef(ref tts, _) => { + word(&mut self.s, "macro_rules! ")?; + self.print_ident(item.ident)?; + self.cbox(INDENT_UNIT)?; + self.popen()?; + self.print_tts(tts.clone().into())?; + self.pclose()?; + word(&mut self.s, ";")?; + self.end()?; + } } self.ann.post(self, NodeItem(item)) } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index b90802d1e7eb8..9d9957a0f4534 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -148,9 +148,4 @@ impl<'ast> Visitor<'ast> for NodeCounter { fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; } - fn visit_macro_def(&mut self, macro_def: &MacroDef) { - self.count += 1; - walk_macro_def(self, macro_def) - } - } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..ee7dd18247b21 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -125,9 +125,6 @@ pub trait Visitor<'ast>: Sized { walk_assoc_type_binding(self, type_binding) } fn visit_attribute(&mut self, _attr: &'ast Attribute) {} - fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { - walk_macro_def(self, macro_def) - } fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } @@ -176,12 +173,6 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); walk_list!(visitor, visit_attribute, &krate.attrs); - walk_list!(visitor, visit_macro_def, &krate.exported_macros); -} - -pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) { - visitor.visit_ident(macro_def.span, macro_def.ident); - walk_list!(visitor, visit_attribute, ¯o_def.attrs); } pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) { @@ -295,6 +286,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_trait_item, methods); } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), + ItemKind::MacroDef(..) => {}, } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 3bceb02f3d6c5..b51591bf89d5e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -99,7 +99,7 @@ macro_rules! derive_traits { pub fn register_builtin_derives(resolver: &mut Resolver) { $( - resolver.add_ext( + resolver.add_builtin( ast::Ident::with_empty_ctxt(Symbol::intern($name)), Rc::new(SyntaxExtension::BuiltinDerive($func)) ); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f92cde4019f67..1e9b112b6df56 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -59,7 +59,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, deriving::register_builtin_derives(resolver); let mut register = |name, ext| { - resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); + resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; macro_rules! register { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 9c96ad547e1ae..5adaf470f2374 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -90,12 +90,7 @@ pub fn modify(sess: &ParseSess, krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros)); - if krate.exported_macros.len() > 0 { - handler.err("cannot export macro_rules! macros from a `proc-macro` \ - crate type currently"); - } - - return krate + krate } fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { @@ -251,6 +246,15 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { + if let ast::ItemKind::MacroDef(..) = item.node { + if self.is_proc_macro_crate && + item.attrs.iter().any(|attr| attr.name() == "macro_export") { + let msg = + "cannot export macro_rules! macros from a `proc-macro` crate type currently"; + self.handler.span_err(item.span, msg); + } + } + // First up, make sure we're checking a bare function. If we're not then // we're just not interested in this item. // diff --git a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs index 0717af98b30b4..3d2dd380e488e 100644 --- a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs +++ b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs @@ -12,6 +12,7 @@ #![feature(no_core)] #![no_core] +macro_rules! foo /* 60#0 */(( $ x : ident ) => { y + $ x }); fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ } From a519659b85bdf3072938ea10255a1d35ac5bce0a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 1 Mar 2017 08:44:05 +0000 Subject: [PATCH 29/73] Move `resolve_invoc` from `syntax` to `resolve`. --- src/librustc_resolve/macros.rs | 76 ++++++++++++++++++++++++++++++---- src/libsyntax/ext/base.rs | 12 ++++-- src/libsyntax/ext/expand.rs | 62 +-------------------------- 3 files changed, 78 insertions(+), 72 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fc6b1baca160b..bec8bf845a75a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,16 +17,14 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex} use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use rustc::ty; -use std::cell::Cell; -use std::rc::Rc; use syntax::ast::{self, Name, Ident}; -use syntax::attr; +use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; -use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; -use syntax::ext::base::MacroKind; -use syntax::ext::expand::Expansion; +use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; +use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; use syntax::ext::hygiene::Mark; +use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; @@ -35,6 +33,10 @@ use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; +use std::cell::Cell; +use std::mem; +use std::rc::Rc; + #[derive(Clone)] pub struct InvocationData<'a> { pub module: Cell>, @@ -235,8 +237,64 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy> { + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy> { + let (attr, traits, item) = match invoc.kind { + InvocationKind::Attr { attr: None, .. } => return Ok(None), + InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), + InvocationKind::Bang { ref mac, .. } => { + return self.resolve_macro(scope, &mac.node.path, MacroKind::Bang, force).map(Some); + } + InvocationKind::Derive { name, span, .. } => { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + return self.resolve_macro(scope, &path, MacroKind::Derive, force).map(Some); + } + }; + + let (attr_name, path) = { + let attr = attr.as_ref().unwrap(); + (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) + }; + + let mut determined = true; + match self.resolve_macro(scope, &path, MacroKind::Attr, force) { + Ok(ext) => return Ok(Some(ext)), + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), + Err(Determinacy::Determined) => {} + } + + for &(name, span) in traits { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + match self.resolve_macro(scope, &path, MacroKind::Derive, force) { + Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { + if inert_attrs.contains(&attr_name) { + // FIXME(jseyfried) Avoid `mem::replace` here. + let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + .make_items().pop().unwrap(); + let dummy_item = Annotatable::Item(dummy_item); + *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| { + let inert_attr = attr.take().unwrap(); + attr::mark_known(&inert_attr); + if self.proc_macro_enabled { + *attr = find_attr_invoc(&mut attrs); + } + attrs.push(inert_attr); + attrs + }); + } + return Err(Determinacy::Undetermined); + }, + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) => {} + } + } + + Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) + } + + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy> { let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 39d919106147d..dc7e7673eb03c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::{DiagnosticBuilder, FatalError}; -use ext::expand::{self, Expansion}; +use ext::expand::{self, Expansion, Invocation}; use ext::hygiene::Mark; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; @@ -557,8 +557,10 @@ pub trait Resolver { fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy>; + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy>; + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy>; } #[derive(Copy, Clone, Debug)] @@ -580,6 +582,10 @@ impl Resolver for DummyResolver { fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) + -> Result>, Determinacy> { + Err(Determinacy::Determined) + } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8451414ec3d8a..a208986becf72 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -251,7 +251,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; - let ext = match self.resolve_invoc(&mut invoc, scope, force) { + let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { @@ -364,64 +364,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } - fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) - -> Result>, Determinacy> { - let (attr, traits, item) = match invoc.kind { - InvocationKind::Bang { ref mac, .. } => { - return self.cx.resolver.resolve_macro(scope, &mac.node.path, - MacroKind::Bang, force).map(Some); - } - InvocationKind::Attr { attr: None, .. } => return Ok(None), - InvocationKind::Derive { name, span, .. } => { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.cx.resolver.resolve_macro(scope, &path, - MacroKind::Derive, force).map(Some) - } - InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), - }; - - let (attr_name, path) = { - let attr = attr.as_ref().unwrap(); - (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) - }; - - let mut determined = true; - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Attr, force) { - Ok(ext) => return Ok(Some(ext)), - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), - _ => {} - } - - for &(name, span) in traits { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Derive, force) { - Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { - if inert_attrs.contains(&attr_name) { - // FIXME(jseyfried) Avoid `mem::replace` here. - let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) - .make_items().pop().unwrap(); - *item = mem::replace(item, Annotatable::Item(dummy_item)) - .map_attrs(|mut attrs| { - let inert_attr = attr.take().unwrap(); - attr::mark_known(&inert_attr); - if self.cx.ecfg.proc_macro_enabled() { - *attr = find_attr_invoc(&mut attrs); - } - attrs.push(inert_attr); - attrs - }); - } - return Err(Determinacy::Undetermined); - }, - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) => {} - } - } - - Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) - } - fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), @@ -802,7 +744,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } -fn find_attr_invoc(attrs: &mut Vec) -> Option { +pub fn find_attr_invoc(attrs: &mut Vec) -> Option { for i in 0 .. attrs.len() { if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) { return Some(attrs.remove(i)); From 9057c8d31023fb682cd7aee7c09d1b3696729b90 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 1 Mar 2017 23:48:16 +0000 Subject: [PATCH 30/73] Avoid using `Mark` and `Invocation` for macro defs. --- src/librustc/hir/lowering.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 3 +- src/librustc_resolve/build_reduced_graph.rs | 19 ++--- src/librustc_resolve/lib.rs | 55 ++++++++------ src/librustc_resolve/macros.rs | 79 +++++++++++---------- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/ext/expand.rs | 10 +-- src/libsyntax/ext/hygiene.rs | 7 -- src/libsyntax/ext/tt/macro_rules.rs | 4 +- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/print/pprust.rs | 2 +- 13 files changed, 100 insertions(+), 93 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f9f63ccbfde7e..aa6614b0af4f7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1276,7 +1276,7 @@ impl<'a> LoweringContext<'a> { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); - if let ItemKind::MacroDef(ref tts, _) = i.node { + if let ItemKind::MacroDef(ref tts) = i.node { if i.attrs.iter().any(|attr| attr.name() == "macro_export") { self.exported_macros.push(hir::MacroDef { name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cfe67726ab228..2a67b79eaa52e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -34,7 +34,6 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; -use syntax::ext::hygiene::Mark; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{mk_sp, Span}; @@ -420,7 +419,7 @@ impl CrateStore for cstore::CStore { id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs, - node: ast::ItemKind::MacroDef(body.into(), Mark::fresh()), + node: ast::ItemKind::MacroDef(body.into()), vis: ast::Visibility::Inherited, }) } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8b20c31be03b7..03c61067d64c2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -492,6 +492,16 @@ impl<'a> Resolver<'a> { }) } + pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> { + let def_id = self.macro_defs[&expansion]; + if let Some(id) = self.definitions.as_local_node_id(def_id) { + self.local_macro_def_scopes[&id] + } else { + let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); + self.get_extern_crate_root(module_def_id.krate) + } + } + pub fn get_macro(&mut self, def: Def) -> Rc { let def_id = match def { Def::Macro(def_id, ..) => def_id, @@ -506,15 +516,6 @@ impl<'a> Resolver<'a> { LoadedMacro::ProcMacro(ext) => return ext, }; - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(self.get_extern_crate_root(def_id.krate)), - // FIXME(jseyfried) the following are irrelevant - def_index: CRATE_DEF_INDEX, const_expr: false, - legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), - }); - if let ast::ItemKind::MacroDef(_, mark) = macro_def.node { - self.invocations.insert(mark, invocation); - } let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0f55b53acee26..b19e5f62e275c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -752,8 +752,8 @@ enum RibKind<'a> { // We passed through a module. ModuleRibKind(Module<'a>), - // We passed through a `macro_rules!` statement with the given expansion - MacroDefinition(Mark), + // We passed through a `macro_rules!` statement + MacroDefinition(DefId), // All bindings in this rib are type parameters that can't be used // from the default of a type parameter because they're not declared @@ -970,14 +970,18 @@ impl<'a> NameBinding<'a> { } } - fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + fn def_ignoring_ambiguity(&self) -> Def { match self.kind { - NameBindingKind::Import { binding, .. } => binding.get_macro(resolver), - NameBindingKind::Ambiguity { b1, .. } => b1.get_macro(resolver), - _ => resolver.get_macro(self.def()), + NameBindingKind::Import { binding, .. } => binding.def_ignoring_ambiguity(), + NameBindingKind::Ambiguity { b1, .. } => b1.def_ignoring_ambiguity(), + _ => self.def(), } } + fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + resolver.get_macro(self.def_ignoring_ambiguity()) + } + // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() { ty::Visibility::Public } else { self.vis } @@ -1145,6 +1149,8 @@ pub struct Resolver<'a> { builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, + macro_defs: FxHashMap, + local_macro_def_scopes: FxHashMap>, macro_exports: Vec, pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, @@ -1273,6 +1279,9 @@ impl<'a> Resolver<'a> { let features = session.features.borrow(); + let mut macro_defs = FxHashMap(); + macro_defs.insert(Mark::root(), root_def_id); + Resolver { session: session, @@ -1339,6 +1348,8 @@ impl<'a> Resolver<'a> { macro_map: FxHashMap(), macro_exports: Vec::new(), invocations: invocations, + macro_defs: macro_defs, + local_macro_def_scopes: FxHashMap(), name_already_seen: FxHashMap(), whitelisted_legacy_custom_derives: Vec::new(), proc_macro_enabled: features.proc_macro, @@ -1476,12 +1487,12 @@ impl<'a> Resolver<'a> { } } - if let MacroDefinition(mac) = self.ribs[ns][i].kind { + if let MacroDefinition(def) = self.ribs[ns][i].kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } } @@ -1489,11 +1500,12 @@ impl<'a> Resolver<'a> { None } - fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> { - while crate_var_ctxt.source().0 != SyntaxContext::empty() { - crate_var_ctxt = crate_var_ctxt.source().0; + fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> { + let mut ctxt_data = crate_var_ctxt.data(); + while ctxt_data.prev_ctxt != SyntaxContext::empty() { + ctxt_data = ctxt_data.prev_ctxt.data(); } - let module = self.invocations[&crate_var_ctxt.source().1].module.get(); + let module = self.macro_def_scope(ctxt_data.outer_mark); if module.is_local() { self.graph_root } else { module } } @@ -1545,12 +1557,12 @@ impl<'a> Resolver<'a> { NormalRibKind => { // Continue } - MacroDefinition(mac) => { + MacroDefinition(def) => { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } _ => { @@ -1968,10 +1980,11 @@ impl<'a> Resolver<'a> { // Descend into the block. for stmt in &block.stmts { if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::MacroDef(_, mark) = item.node { + if let ast::ItemKind::MacroDef(..) = item.node { num_macro_definition_ribs += 1; - self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); - self.label_ribs.push(Rib::new(MacroDefinition(mark))); + let def = self.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(def))); + self.label_ribs.push(Rib::new(MacroDefinition(def))); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index bec8bf845a75a..7ad122d1c31d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -74,7 +74,7 @@ pub enum LegacyScope<'a> { pub struct LegacyBinding<'a> { pub parent: Cell>, pub name: ast::Name, - ext: Rc, + def_id: DefId, pub span: Span, } @@ -239,15 +239,34 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) -> Result>, Determinacy> { - let (attr, traits, item) = match invoc.kind { + let def = match invoc.kind { InvocationKind::Attr { attr: None, .. } => return Ok(None), + _ => match self.resolve_invoc_to_def(invoc, scope, force) { + Ok(def) => def, + Err(determinacy) => return Err(determinacy), + }, + }; + self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + Ok(Some(self.get_macro(def))) + } + + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy> { + self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def)) + } +} + +impl<'a> Resolver<'a> { + fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result { + let (attr, traits, item) = match invoc.kind { InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), InvocationKind::Bang { ref mac, .. } => { - return self.resolve_macro(scope, &mac.node.path, MacroKind::Bang, force).map(Some); + return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); } InvocationKind::Derive { name, span, .. } => { let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.resolve_macro(scope, &path, MacroKind::Derive, force).map(Some); + return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force); } }; @@ -257,8 +276,8 @@ impl<'a> base::Resolver for Resolver<'a> { }; let mut determined = true; - match self.resolve_macro(scope, &path, MacroKind::Attr, force) { - Ok(ext) => return Ok(Some(ext)), + match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { + Ok(def) => return Ok(def), Err(Determinacy::Undetermined) => determined = false, Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), Err(Determinacy::Determined) => {} @@ -293,8 +312,8 @@ impl<'a> base::Resolver for Resolver<'a> { Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) } - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) - -> Result, Determinacy> { + fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result { let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = @@ -317,10 +336,10 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let ext = match self.resolve_path(&path, Some(MacroNS), None) { + let def = match self.resolve_path(&path, Some(MacroNS), None) { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), - def @ _ => Ok(self.get_macro(def)), + def @ _ => Ok(def), }, PathResult::Module(..) => unreachable!(), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), @@ -331,15 +350,15 @@ impl<'a> base::Resolver for Resolver<'a> { }; self.current_module.macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); - return ext; + return def; } let name = path[0].name; let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), - Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)), + Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), + Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.get_macro(self)), + Ok(binding) => Ok(binding.def_ignoring_ambiguity()), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { @@ -354,9 +373,7 @@ impl<'a> base::Resolver for Resolver<'a> { result } -} -impl<'a> Resolver<'a> { // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) pub fn resolve_lexical_macro_path_segment(&mut self, ident: Ident, @@ -597,33 +614,23 @@ impl<'a> Resolver<'a> { } pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { - if item.ident.name == "macro_rules" { + self.local_macro_def_scopes.insert(item.id, self.current_module); + let ident = item.ident; + if ident.name == "macro_rules" { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(self.current_module), - // FIXME(jseyfried) the following are irrelevant - def_index: CRATE_DEF_INDEX, const_integer: false, - legacy_scope: Cell::new(LegacyScope::Empty), expansion: Cell::new(LegacyScope::Empty), - }); - if let ast::ItemKind::MacroDef(_, mark) = item.node { - self.invocations.insert(mark, invocation); - } - + let def_id = self.definitions.local_def_id(item.id); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item)); + self.macro_map.insert(def_id, ext); *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { - parent: Cell::new(*legacy_scope), - name: item.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, item)), - span: item.span, + parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, })); - self.macro_names.insert(item.ident.name); + self.macro_names.insert(ident.name); if attr::contains_name(&item.attrs, "macro_export") { - self.macro_exports.push(Export { - name: item.ident.name, - def: Def::Macro(self.definitions.local_def_id(item.id), MacroKind::Bang), - }); + let def = Def::Macro(def_id, MacroKind::Bang); + self.macro_exports.push(Export { name: ident.name, def: def }); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 35d459422033f..b80de3cc50546 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { LoadedMacro::ProcMacro(..) => continue, }; - let matchers = if let ast::ItemKind::MacroDef(ref tokens, _) = def.node { + let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node { let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); tts.chunks(4).map(|arm| arm[0].span()).collect() } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a79cfc2bceb33..981667337d59a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -20,7 +20,7 @@ pub use util::ThinVec; use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; -use ext::hygiene::{Mark, SyntaxContext}; +use ext::hygiene::SyntaxContext; use print::pprust; use ptr::P; use symbol::{Symbol, keywords}; @@ -1860,7 +1860,7 @@ pub enum ItemKind { Mac(Mac), /// A macro definition. - MacroDef(ThinTokenStream, Mark /* FIXME(jseyfried) remove this */), + MacroDef(ThinTokenStream), } impl ItemKind { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a208986becf72..96fcea7148bfa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -154,7 +154,7 @@ impl ExpansionKind { pub struct Invocation { pub kind: InvocationKind, expansion_kind: ExpansionKind, - expansion_data: ExpansionData, + pub expansion_data: ExpansionData, } pub enum InvocationKind { @@ -432,7 +432,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = mark_tts(mac.node.stream(), mark); + let marked_tts = + noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -1094,8 +1095,3 @@ impl Folder for Marker { span } } - -// apply a given mark to the given token trees. Used prior to expansion of a macro. -pub fn mark_tts(tts: TokenStream, m: Mark) -> TokenStream { - noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) -} diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 83c51bb9d2fcf..57f5ab73d3706 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -118,13 +118,6 @@ impl SyntaxContext { }) }) } - - /// If `ident` is macro expanded, return the source ident from the macro definition - /// and the mark of the expansion that created the macro definition. - pub fn source(self) -> (Self /* source context */, Mark /* source macro */) { - let macro_def_ctxt = self.data().prev_ctxt.data(); - (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark) - } } impl fmt::Debug for SyntaxContext { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 8ad679b853e85..7aa1230f9aeea 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,7 +12,7 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; use ext::base::{NormalTT, TTMacroExpander}; -use ext::expand::{Expansion, ExpansionKind, mark_tts}; +use ext::expand::{Expansion, ExpansionKind}; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; @@ -184,7 +184,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { // Parse the macro_rules! invocation let body = match def.node { - ast::ItemKind::MacroDef(ref body, mark) => mark_tts(body.clone().into(), mark), + ast::ItemKind::MacroDef(ref body) => body.clone().into(), _ => unreachable!(), }; let argument_map = match parse(sess, body, &argument_gram, None) { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d23f880bc7bac..fb4eb19be2b15 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -899,8 +899,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { items.move_flat_map(|item| folder.fold_trait_item(item)), ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), - ItemKind::MacroDef(tts, mark) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into(), - mark), + ItemKind::MacroDef(tts) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into()), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d81732489dd3d..6446d38e5ef70 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,7 +43,6 @@ use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; -use ext::hygiene::Mark; use parse::{self, classify, token}; use parse::common::SeqSep; use parse::lexer::TokenAndSpan; @@ -3731,7 +3730,7 @@ impl<'a> Parser<'a> { } let hi = self.prev_span.hi; - let kind = ItemKind::MacroDef(tts, Mark::fresh()); + let kind = ItemKind::MacroDef(tts); Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 78212fb4b447c..3efadbd00d1e0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1328,7 +1328,7 @@ impl<'a> State<'a> { word(&mut self.s, ";")?; self.end()?; } - ast::ItemKind::MacroDef(ref tts, _) => { + ast::ItemKind::MacroDef(ref tts) => { word(&mut self.s, "macro_rules! ")?; self.print_ident(item.ident)?; self.cbox(INDENT_UNIT)?; From 4f424b3c5a3e47732ca39cc14466b0e0d21f488a Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 6 Mar 2017 18:16:57 -0800 Subject: [PATCH 31/73] Add compile-fail tests for catch expr in match or condition --- src/test/compile-fail/catch-in-match.rs | 15 +++++++++++++++ src/test/compile-fail/catch-in-while.rs | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/compile-fail/catch-in-match.rs create mode 100644 src/test/compile-fail/catch-in-while.rs diff --git a/src/test/compile-fail/catch-in-match.rs b/src/test/compile-fail/catch-in-match.rs new file mode 100644 index 0000000000000..9f9968e81242a --- /dev/null +++ b/src/test/compile-fail/catch-in-match.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![feature(catch_expr)] + +fn main() { + match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do` +} diff --git a/src/test/compile-fail/catch-in-while.rs b/src/test/compile-fail/catch-in-while.rs new file mode 100644 index 0000000000000..cb8613ee60b42 --- /dev/null +++ b/src/test/compile-fail/catch-in-while.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![feature(catch_expr)] + +fn main() { + while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do` +} From 3c1ba68ebdb24e75f1764a9842357ce2c1908923 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 7 Mar 2017 17:37:45 +1300 Subject: [PATCH 32/73] Expect macro defs in save-analysis and add expn info to spans for attr proc macros --- src/librustc_save_analysis/dump_visitor.rs | 4 +++- src/libsyntax/ext/expand.rs | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3c275e0996dac..33d5c17a41921 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -327,6 +327,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: scope }.lower(self.tcx)); } + // With macros 2.0, we can legitimately get a ref to a macro, but + // we don't handle it properly for now (FIXME). + Def::Macro(..) => {} Def::Local(..) | Def::Upvar(..) | Def::SelfTy(..) | @@ -336,7 +339,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | - Def::Macro(..) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..f7dcd00e40976 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -464,8 +464,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); let item_toks = stream_for_item(&item, &self.cx.parse_sess); + let span = Span { + expn_id: self.cx.codemap().record_expansion(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + format: MacroAttribute(name), + span: None, + allow_internal_unstable: false, + }, + }), + ..attr.span + }; + let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); - self.parse_expansion(tok_result, kind, name, attr.span) + self.parse_expansion(tok_result, kind, name, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); From 9efee169583472acbc0f3acbc36c57fbe44aba0a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Mar 2017 12:51:09 +0100 Subject: [PATCH 33/73] Allow lints to check Bodys directly --- src/librustc/lint/context.rs | 6 ++++++ src/librustc/lint/mod.rs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 32bc81e947037..9279f24a57ab3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -806,6 +806,12 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.tables = old_tables; } + fn visit_body(&mut self, body: &'tcx hir::Body) { + run_lints!(self, check_body, late_passes, body); + hir_visit::walk_body(self, body); + run_lints!(self, check_body_post, late_passes, body); + } + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, late_passes, it); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e9f603db15d62..e81d09773701c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -133,6 +133,8 @@ pub trait LintPass { // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. pub trait LateLintPass<'a, 'tcx>: LintPass { + fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { } + fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { } fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } From b75116de9e23dafb705250e543f9cdf514e1ea4a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Mar 2017 06:55:24 -0800 Subject: [PATCH 34/73] Don't put Cargo into the rustc workspace This causes problems when first cloning and bootstrapping the repository unfortunately, so let's ensure that Cargo sticks around in its own workspace. Because Cargo is a submodule it's not available by default on the inital clone of the rust-lang/rust repository. Normally it's the responsibility of the rustbuild to take care of this, but unfortunately to build rustbuild itself we need to resolve the workspace conflicts. To deal with this we'll just have to ensure that all submodules are in their own workspace, which sort of makes sense anyway as updates to dependencies as bugfixes to Cargo should go to rust-lang/cargo instead of rust-lang/rust. In any case this commit removes Cargo from the global workspace which should resolve the issues that we've been seeing. To actually perform this the `cargo` submodule has been moved to the top directory to ensure it's outside the scope of `src/Cargo.toml` as a workspace. --- .gitmodules | 2 +- src/tools/cargo => cargo | 0 src/Cargo.lock | 666 --------------------------------------- src/Cargo.toml | 1 - src/bootstrap/compile.rs | 5 +- src/bootstrap/dist.rs | 1 + src/bootstrap/step.rs | 2 +- 7 files changed, 7 insertions(+), 670 deletions(-) rename src/tools/cargo => cargo (100%) diff --git a/.gitmodules b/.gitmodules index d2c96ac901fc4..59cb2ae9b04f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,7 +19,7 @@ path = src/liblibc url = https://github.com/rust-lang/libc.git [submodule "src/tools/cargo"] - path = src/tools/cargo + path = cargo url = https://github.com/rust-lang/cargo [submodule "reference"] path = src/doc/reference diff --git a/src/tools/cargo b/cargo similarity index 100% rename from src/tools/cargo rename to cargo diff --git a/src/Cargo.lock b/src/Cargo.lock index f4174693a5771..6dc71e8b602db 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -6,23 +6,6 @@ dependencies = [ "libc 0.0.0", ] -[[package]] -name = "advapi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aho-corasick" version = "0.6.2" @@ -90,11 +73,6 @@ dependencies = [ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bufstream" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "build-manifest" version = "0.1.0" @@ -110,81 +88,10 @@ dependencies = [ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cargo" -version = "0.18.0" -dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargotest 0.1.0", - "crates-io 0.7.0", - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargotest" -version = "0.1.0" -dependencies = [ - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo 0.18.0", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargotest2" version = "0.1.0" -[[package]] -name = "cfg-if" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "clap" version = "2.20.5" @@ -240,58 +147,6 @@ dependencies = [ name = "core" version = "0.0.0" -[[package]] -name = "crates-io" -version = "0.7.0" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "curl" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curl-sys" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "docopt" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dtoa" version = "0.4.1" @@ -334,48 +189,15 @@ dependencies = [ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "flate2" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fmt_macros" version = "0.0.0" -[[package]] -name = "foreign-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fs2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gcc" version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "gdi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getopts" version = "0.0.0" @@ -385,48 +207,10 @@ name = "getopts" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "git2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2-curl" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "graphviz" version = "0.0.0" -[[package]] -name = "hamcrest" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "handlebars" version = "0.25.1" @@ -441,16 +225,6 @@ dependencies = [ "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "idna" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.3.1" @@ -482,43 +256,6 @@ name = "libc" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libgit2-sys" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libz-sys" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "linkchecker" version = "0.1.0" @@ -532,11 +269,6 @@ name = "log" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "matches" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "mdbook" version = "0.0.17" @@ -554,14 +286,6 @@ dependencies = [ "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "1.0.1" @@ -570,99 +294,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz-sys" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.36" @@ -676,48 +307,11 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num_cpus" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "open" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "openssl" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-probe" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "openssl-sys" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "panic_abort" version = "0.0.0" @@ -741,11 +335,6 @@ name = "pest" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pkg-config" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc_macro" version = "0.0.0" @@ -762,15 +351,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "psapi-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pulldown-cmark" version = "0.0.8" @@ -793,11 +373,6 @@ name = "quick-error" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand" version = "0.0.0" @@ -805,26 +380,6 @@ dependencies = [ "core 0.0.0", ] -[[package]] -name = "rand" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "0.2.1" @@ -837,11 +392,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.4.0" @@ -1218,50 +768,11 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "semver" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "serde_codegen_internals" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_ignored" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_json" version = "0.9.7" @@ -1277,11 +788,6 @@ dependencies = [ name = "serialize" version = "0.0.0" -[[package]] -name = "shell-escape" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "std" version = "0.0.0" @@ -1318,24 +824,6 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntax" version = "0.0.0" @@ -1367,36 +855,10 @@ dependencies = [ "serialize 0.0.0", ] -[[package]] -name = "tar" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term" version = "0.0.0" -[[package]] -name = "term" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term_size" version = "0.2.3" @@ -1415,15 +877,6 @@ dependencies = [ "term 0.0.0", ] -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread-id" version = "3.0.0" @@ -1433,14 +886,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.3" @@ -1470,19 +915,6 @@ dependencies = [ "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-bidi" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-segmentation" version = "1.1.0" @@ -1493,11 +925,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unreachable" version = "0.1.1" @@ -1506,29 +933,6 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "url" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "user32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1554,119 +958,49 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b48dbe2ff0e98fa2f03377d204a9637d3c9816cd431bfe05a8abbd0ea11d074" -"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758" "checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" -"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" -"checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa" -"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25" -"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" -"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" "checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" -"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2" -"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" -"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b" "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" -"checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95" -"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934" -"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" "checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" -"checksum miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579" -"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2" -"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" -"checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49" -"checksum num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c78e054dd19c3fd03419ade63fa661e9c49bb890ce3beb4eee5b7baf93f92f" -"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92" -"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c" -"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf" "checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" -"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" -"checksum openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f9871ecf7629da3760599e3e547d35940cff3cead49159b49f81cd1250f24f1d" -"checksum openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "756d49c8424483a3df3b5d735112b4da22109ced9a8294f1f5cdf80fb3810919" -"checksum openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5dd48381e9e8a6dce9c4c402db143b2e243f5f872354532f7a009c289b3998ca" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" -"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" -"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" -"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0ed773960f90a78567fcfbe935284adf50c5d7cf119aa2cf43bb0b4afa69bb" -"checksum serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d52006899f910528a10631e5b727973fe668f3228109d1707ccf5bad5490b6e" -"checksum serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "789ee9f3cd78c850948b94121020147f5220b47dafbf230d7098a93a58f726cf" -"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64" "checksum serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb96d30e4e6f9fc52e08f51176d078b6f79b981dc3ed4134f7b850be9f446a8" -"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8" -"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc" -"checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" "checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f" -"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" -"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" -"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" -"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/src/Cargo.toml b/src/Cargo.toml index c5ca80accbf02..0dafbb8428e3e 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -13,7 +13,6 @@ members = [ "tools/build-manifest", "tools/qemu-test-client", "tools/qemu-test-server", - "tools/cargo", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 46d8d4b4aab2d..3459c1d2b8425 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -417,7 +417,10 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); - let dir = build.src.join("src/tools").join(tool); + let mut dir = build.src.join(tool); + if !dir.exists() { + dir = build.src.join("src/tools").join(tool); + } cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); // We don't want to build tools dynamically as they'll be running across diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 67e4dad83ce88..d437e907d1e6c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -392,6 +392,7 @@ pub fn rust_src(build: &Build) { let src_dirs = [ "man", "src", + "cargo", ]; let filter_fn = move |path: &Path| { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index a5c0d11d21985..a11726a57dbdd 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -559,7 +559,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") .dep(|s| s.name("libstd")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); - rules.build("tool-cargo", "src/tools/cargo") + rules.build("tool-cargo", "cargo") .dep(|s| s.name("libstd")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { From 12dee0ec755f758909dca1f3eafbce7cc7998ce6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Mar 2017 15:15:55 -0800 Subject: [PATCH 35/73] rustc: Exit quickly on only `--emit dep-info` This commit alters the compiler to exit quickly if the only output being emitted is `dep-info`, which doesn't need a lot of other information to generate. Closes #40328 --- src/librustc_driver/driver.rs | 4 ++++ .../run-make/dep-info-doesnt-run-much/Makefile | 4 ++++ src/test/run-make/dep-info-doesnt-run-much/foo.rs | 15 +++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 src/test/run-make/dep-info-doesnt-run-much/Makefile create mode 100644 src/test/run-make/dep-info-doesnt-run-much/foo.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..82a8d88452673 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -125,6 +125,10 @@ pub fn compile_input(sess: &Session, }; write_out_deps(sess, &outputs, &crate_name); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) && + sess.opts.output_types.keys().count() == 1 { + return Ok(()) + } let arena = DroplessArena::new(); let arenas = GlobalArenas::new(); diff --git a/src/test/run-make/dep-info-doesnt-run-much/Makefile b/src/test/run-make/dep-info-doesnt-run-much/Makefile new file mode 100644 index 0000000000000..2fd84639f2190 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit dep-info diff --git a/src/test/run-make/dep-info-doesnt-run-much/foo.rs b/src/test/run-make/dep-info-doesnt-run-much/foo.rs new file mode 100644 index 0000000000000..3591182104498 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/foo.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +// We're only emitting dep info, so we shouldn't be running static analysis to +// figure out that this program is erroneous. +fn main() { + let a: u8 = "a"; +} From eaa706d90920106b722931b7a6caf5818a0221e9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 02:50:13 +0300 Subject: [PATCH 36/73] Update syntax for `pub(restricted)` --- src/libsyntax/parse/parser.rs | 72 ++++++++++--------- .../auxiliary/pub_and_stability.rs | 8 +-- .../restricted/lookup-ignores-private.rs | 4 +- .../restricted/struct-literal-field.rs | 2 +- .../compile-fail/privacy/restricted/test.rs | 4 +- .../privacy/restricted/ty-params.rs | 7 +- .../compile-fail/resolve-bad-visibility.rs | 10 +-- .../resolve/auxiliary/privacy-struct-ctor.rs | 2 +- src/test/ui/resolve/privacy-struct-ctor.rs | 2 +- 9 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..12e3c2ff95b7d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4605,7 +4605,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4936,7 +4936,7 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility(false)?; + let mut vis = p.parse_visibility()?; let ty_is_interpolated = p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); let mut ty = p.parse_ty()?; @@ -4993,38 +4993,46 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; self.parse_single_struct_field(lo, vis, attrs) } - // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) - fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { - let pub_crate = |this: &mut Self| { - let span = this.prev_span; - this.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Crate(span)) - }; - + // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts + // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. + fn parse_visibility(&mut self) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { - Ok(Visibility::Inherited) - } else if !allow_path { - // Look ahead to avoid eating the `(` in `pub(path)` while still parsing `pub(crate)` - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { - self.bump(); self.bump(); - pub_crate(self) - } else { - Ok(Visibility::Public) - } - } else if !self.eat(&token::OpenDelim(token::Paren)) { - Ok(Visibility::Public) - } else if self.eat_keyword(keywords::Crate) { - pub_crate(self) - } else { - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); - self.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) - } + return Ok(Visibility::Inherited) + } + + if self.check(&token::OpenDelim(token::Paren)) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { + // `pub(crate)` + self.bump(); // `(` + self.bump(); // `crate` + let vis = Visibility::Crate(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { + // `pub(in path)` + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && + self.look_ahead(1, |t| t.is_keyword(keywords::Super) || + t.is_keyword(keywords::SelfValue)) { + // `pub(self)` or `pub(super)` + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } + } + + Ok(Visibility::Public) } /// Parse defaultness: DEFAULT or nothing @@ -5499,7 +5507,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5774,7 +5782,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM diff --git a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs index 9dc4cf1252ec3..6f458da9b527b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs @@ -55,7 +55,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) b_crate: i32, #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) c_mod: i32, + pub(in m) c_mod: i32, #[stable(feature = "unit_test", since = "0.0.0")] // SILLY d_priv: i32 } @@ -71,7 +71,7 @@ mod m { pub i32, pub(crate) i32, - pub(m) i32, + pub(in m) i32, i32); impl Record { @@ -124,7 +124,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) fn pub_crate(&self) -> i32 { self.d_priv } #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) fn pub_mod(&self) -> i32 { self.d_priv } + pub(in m) fn pub_mod(&self) -> i32 { self.d_priv } #[stable(feature = "unit_test", since = "0.0.0")] // SILLY fn private(&self) -> i32 { self.d_priv } } @@ -138,7 +138,7 @@ mod m { pub fn stable(&self) -> i32 { self.0 } pub(crate) fn pub_crate(&self) -> i32 { self.0 } - pub(m) fn pub_mod(&self) -> i32 { self.0 } + pub(in m) fn pub_mod(&self) -> i32 { self.0 } fn private(&self) -> i32 { self.0 } } } diff --git a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs index 4e2a69cb79e19..2d4b5545544c6 100644 --- a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs +++ b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs @@ -16,10 +16,10 @@ mod foo { mod bar { #[derive(Default)] pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } impl S { - pub(foo) fn f(&self) -> i32 { 0 } + pub(in foo) fn f(&self) -> i32 { 0 } } pub struct S2 { diff --git a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs index e254e005656c1..53786d45c73ee 100644 --- a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs +++ b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs @@ -15,7 +15,7 @@ mod foo { pub mod bar { pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } } diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs index 01e2c6cd7e828..d55ee8221cd73 100644 --- a/src/test/compile-fail/privacy/restricted/test.rs +++ b/src/test/compile-fail/privacy/restricted/test.rs @@ -57,6 +57,6 @@ fn main() { } mod pathological { - pub(bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? - pub(foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules + pub(in bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? + pub(in foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules } diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs index da7086cf554c3..cd0edc8fe7c44 100644 --- a/src/test/compile-fail/privacy/restricted/ty-params.rs +++ b/src/test/compile-fail/privacy/restricted/ty-params.rs @@ -11,16 +11,11 @@ #![feature(pub_restricted)] macro_rules! m { - ($p: path) => (pub($p) struct Z;) + ($p: path) => (pub(in $p) struct Z;) } struct S(T); m!{ S } //~ ERROR type or lifetime parameters in visibility path //~^ ERROR expected module, found struct `S` -mod foo { - struct S(pub(foo) ()); //~ ERROR type or lifetime parameters in visibility path - //~^ ERROR cannot find type `T` in this scope -} - fn main() {} diff --git a/src/test/compile-fail/resolve-bad-visibility.rs b/src/test/compile-fail/resolve-bad-visibility.rs index 6b5cd4dce265a..20878a91ede99 100644 --- a/src/test/compile-fail/resolve-bad-visibility.rs +++ b/src/test/compile-fail/resolve-bad-visibility.rs @@ -13,11 +13,11 @@ enum E {} trait Tr {} -pub(E) struct S; //~ ERROR expected module, found enum `E` -pub(Tr) struct Z; //~ ERROR expected module, found trait `Tr` -pub(std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules -pub(nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root -pub(too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root +pub(in E) struct S; //~ ERROR expected module, found enum `E` +pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` +pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules +pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root +pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root // Visibilities are resolved eagerly without waiting for modules becoming fully populated. // Visibilities can only use ancestor modules legally which are always available in time, diff --git a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs index f190f5dd0534d..383224b2f9273 100644 --- a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -14,7 +14,7 @@ pub mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } } diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs index 3d0c76c740ad6..68bd74719f55c 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -18,7 +18,7 @@ mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } use m::n::Z; // OK, only the type is imported From 779d28022692ada4fdfc9356bbe522773ee5bc27 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 15:06:53 +1300 Subject: [PATCH 37/73] save-analysis: cope with lack of method data after a type error Fixes #39957 --- src/librustc_save_analysis/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b1e435dcc751c..4298024e12d7e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -387,7 +387,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } None => { - span_bug!(span, "Could not find container for method {}", id); + debug!("Could not find container for method {} at {:?}", id, span); + // This is not necessarily a bug, if there was a compilation error, the tables + // we need might not exist. + return None; } }, }; From 234753a5cafcda561cef0e5117bad80205ee92ad Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Tue, 7 Mar 2017 21:49:43 -0500 Subject: [PATCH 38/73] Fix missing backtick typo Fixes rendering of the end of the `Configure and Make` section. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93415adc423f4..79f11144a073d 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ $ ./configure $ make && sudo make install ``` -When using the configure script, the generated config.mk` file may override the +When using the configure script, the generated `config.mk` file may override the `config.toml` file. To go back to the `config.toml` file, delete the generated `config.mk` file. From 319890487a531c38b8afd4cdabcdac2c7dd8dc5b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 7 Mar 2017 16:17:16 +0200 Subject: [PATCH 39/73] Disallow subtyping between T and U in T: Unsize. --- src/librustc/traits/select.rs | 6 ++-- src/test/compile-fail/issue-40288-2.rs | 41 ++++++++++++++++++++++++++ src/test/compile-fail/issue-40288.rs | 30 +++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-40288-2.rs create mode 100644 src/test/compile-fail/issue-40288.rs diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4c4ace0d8baf9..38ea1e4a19b91 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2461,7 +2461,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_trait, target) + self.infcx.eq_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2520,7 +2520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, a, b) + self.infcx.eq_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_struct, target) + self.infcx.eq_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); diff --git a/src/test/compile-fail/issue-40288-2.rs b/src/test/compile-fail/issue-40288-2.rs new file mode 100644 index 0000000000000..c1e8cb8b6defb --- /dev/null +++ b/src/test/compile-fail/issue-40288-2.rs @@ -0,0 +1,41 @@ +// Copyright 2017 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. + +fn prove_static(_: &'static T) {} + +fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = [x]; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let slice: &mut [_] = &mut out; + slice[0] = y; + } + out[0] +} + +struct Struct { + head: T, + _tail: U +} + +fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = Struct { head: x, _tail: [()] }; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let dst: &mut Struct<_, [()]> = &mut out; + dst.head = y; + } + out.head +} + +fn main() { + prove_static(lifetime_transmute_slice("", &String::from("foo"))); + prove_static(lifetime_transmute_struct("", &String::from("bar"))); +} diff --git a/src/test/compile-fail/issue-40288.rs b/src/test/compile-fail/issue-40288.rs new file mode 100644 index 0000000000000..b5418e85bec78 --- /dev/null +++ b/src/test/compile-fail/issue-40288.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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. + +fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) { + for val in &mut *to { + *val = refr; + } +} + +fn main() { + let ref init = 0i32; + let ref mut refr = 1i32; + + let mut out = [init]; + + save_ref(&*refr, &mut out); + + // This shouldn't be allowed as `refr` is borrowed + *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed + + // Prints 3?! + println!("{:?}", out[0]); +} From eef1cc73e7c639db0b9eb96d304b3408afdd23ba Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 7 Mar 2017 23:20:39 +0300 Subject: [PATCH 40/73] rustbuild: Add option for enabling partial LLVM rebuilds --- appveyor.yml | 8 +++---- src/bootstrap/config.rs | 4 ++++ src/bootstrap/config.toml.example | 7 ++++++ src/bootstrap/native.rs | 23 ++++++++----------- ...uto-clean-trigger => llvm-rebuild-trigger} | 2 +- 5 files changed, 26 insertions(+), 18 deletions(-) rename src/rustllvm/{llvm-auto-clean-trigger => llvm-rebuild-trigger} (66%) diff --git a/appveyor.yml b/appveyor.yml index 9a0a4d81f9b1e..7409f83d967b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,10 +137,10 @@ test_script: - sh src/ci/run.sh cache: - - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" branches: only: diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..0b36166cc794c 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -59,6 +59,7 @@ pub struct Config { pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, pub llvm_targets: Option, + pub llvm_clean_rebuild: bool, // rust codegen options pub rust_optimize: bool, @@ -179,6 +180,7 @@ struct Llvm { version_check: Option, static_libstdcpp: Option, targets: Option, + clean_rebuild: Option, } #[derive(RustcDecodable, Default, Clone)] @@ -239,6 +241,7 @@ impl Config { pub fn parse(build: &str, file: Option) -> Config { let mut config = Config::default(); config.llvm_optimize = true; + config.llvm_clean_rebuild = true; config.use_jemalloc = true; config.backtrace = true; config.rust_optimize = true; @@ -332,6 +335,7 @@ impl Config { set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); + set(&mut config.llvm_clean_rebuild, llvm.clean_rebuild); config.llvm_targets = llvm.targets.clone(); } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 30763e38a336f..f13ba076d2bdf 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -53,6 +53,13 @@ # Rust team and file an issue if you need assistance in porting! #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +# Delete LLVM build directory on LLVM rebuild. +# This option's default (`true`) is optimized for CI needs, and CI wants to +# perform clean full builds only (possibly accelerated by (s)ccache). +# You may want to override this option for local builds to enable partial LLVM +# rebuilds. +#clean-rebuild = true + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 483f45fdd6218..2534e020af276 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -41,9 +41,9 @@ pub fn llvm(build: &Build, target: &str) { } } - let clean_trigger = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); - let mut clean_trigger_contents = String::new(); - t!(t!(File::open(&clean_trigger)).read_to_string(&mut clean_trigger_contents)); + let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger"); + let mut rebuild_trigger_contents = String::new(); + t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); let out_dir = build.llvm_out(target); let done_stamp = out_dir.join("llvm-finished-building"); @@ -51,18 +51,15 @@ pub fn llvm(build: &Build, target: &str) { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); - // LLVM was already built previously. - // We don't track changes in LLVM sources, so we need to choose between reusing - // what was built previously, or cleaning the directory and doing a fresh build. - // The choice depends on contents of the clean-trigger file. - // If the contents are the same as during the previous build, then no action is required. - // If the contents differ from the previous build, then cleaning is triggered. - if done_contents == clean_trigger_contents { + // If LLVM was already built previously and contents of the rebuild-trigger file + // didn't change from the previous build, then no action is required. + if done_contents == rebuild_trigger_contents { return - } else { - t!(fs::remove_dir_all(&out_dir)); } } + if build.config.llvm_clean_rebuild { + t!(fs::remove_dir_all(&out_dir)); + } println!("Building LLVM for {}", target); let _time = util::timeit(); @@ -148,7 +145,7 @@ pub fn llvm(build: &Build, target: &str) { // tools and libs on all platforms. cfg.build(); - t!(t!(File::create(&done_stamp)).write_all(clean_trigger_contents.as_bytes())); + t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes())); } fn check_llvm_version(build: &Build, llvm_config: &Path) { diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-rebuild-trigger similarity index 66% rename from src/rustllvm/llvm-auto-clean-trigger rename to src/rustllvm/llvm-rebuild-trigger index 57f37ea050c1b..e796e187c2117 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ -# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. +# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. 2017-03-02 From 5697240f1f8a0d73629db364fa08474a1e84f790 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 16:22:08 +0300 Subject: [PATCH 41/73] Default llvm.clean-rebuild to false --- configure | 1 + src/bootstrap/config.rs | 2 +- src/bootstrap/config.toml.example | 8 +++----- src/ci/run.sh | 1 + 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure b/configure index be8628de62832..0737c3dbd1cac 100755 --- a/configure +++ b/configure @@ -638,6 +638,7 @@ opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)" +opt llvm-clean-rebuild 0 "delete LLVM build directory on rebuild" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0b36166cc794c..75176d8cccd79 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -241,7 +241,6 @@ impl Config { pub fn parse(build: &str, file: Option) -> Config { let mut config = Config::default(); config.llvm_optimize = true; - config.llvm_clean_rebuild = true; config.use_jemalloc = true; config.backtrace = true; config.rust_optimize = true; @@ -440,6 +439,7 @@ impl Config { ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), ("LLVM_LINK_SHARED", self.llvm_link_shared), + ("LLVM_CLEAN_REBUILD", self.llvm_clean_rebuild), ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index f13ba076d2bdf..bca640e061e72 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -54,11 +54,9 @@ #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" # Delete LLVM build directory on LLVM rebuild. -# This option's default (`true`) is optimized for CI needs, and CI wants to -# perform clean full builds only (possibly accelerated by (s)ccache). -# You may want to override this option for local builds to enable partial LLVM -# rebuilds. -#clean-rebuild = true +# This option defaults to `false` for local development, but CI may want to +# always perform clean full builds (possibly accelerated by (s)ccache). +#clean-rebuild = false # ============================================================================= # General build configuration options diff --git a/src/ci/run.sh b/src/ci/run.sh index 4c4836d7ca230..19bea9ced0642 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -28,6 +28,7 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-clean-rebuild" if [ "$DIST_SRC" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src" From e07e7151aaf83e5f9da06a212cbfd45606555287 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Mar 2017 15:35:34 -0500 Subject: [PATCH 42/73] isolate dep-graph tasks A task function is now given as a `fn` pointer to ensure that it carries no state. Each fn can take two arguments, because that worked out to be convenient -- these two arguments must be of some type that is `DepGraphSafe`, a new trait that is intended to prevent "leaking" information into the task that was derived from tracked state. This intentionally leaves `DepGraph::in_task()`, the more common form, alone. Eventually all uses of `DepGraph::in_task()` should be ported to `with_task()`, but I wanted to start with a smaller subset. Originally I wanted to use closures bound by an auto trait, but that approach has some limitations: - the trait cannot have a `read()` method; since the current method is unused, that may not be a problem. - more importantly, we would want the auto trait to be "undefined" for all types *by default* -- that is, this use case doesn't really fit the typical auto trait scenario. For example, imagine that there is a `u32` loaded out of a `hir::Node` -- we don't really want to be passing that `u32` into the task! --- src/librustc/dep_graph/graph.rs | 9 ++- src/librustc/dep_graph/mod.rs | 4 ++ src/librustc/dep_graph/safe.rs | 70 ++++++++++++++++++++++++ src/librustc/lib.rs | 1 + src/librustc_borrowck/borrowck/mod.rs | 13 +++-- src/librustc_incremental/persist/load.rs | 6 +- src/librustc_mir/mir_map.rs | 6 +- src/librustc_trans/base.rs | 39 +++++++++---- src/librustc_trans/context.rs | 8 ++- src/librustc_typeck/check/mod.rs | 14 +++-- src/librustc_typeck/collect.rs | 33 +++++------ 11 files changed, 155 insertions(+), 48 deletions(-) create mode 100644 src/librustc/dep_graph/safe.rs diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e6736ccafbad9..e22f56d278d55 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; +use super::safe::DepGraphSafe; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] @@ -76,11 +77,13 @@ impl DepGraph { op() } - pub fn with_task(&self, key: DepNode, op: OP) -> R - where OP: FnOnce() -> R + pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - op() + cx.read(self); + arg.read(self); + task(cx, arg) } pub fn read(&self, v: DepNode) { diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 7331756f35b8e..496375b129167 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,8 @@ mod edges; mod graph; mod query; mod raii; +#[macro_use] +mod safe; mod shadow; mod thread; mod visit; @@ -25,6 +27,8 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::safe::AssertDepGraphSafe; +pub use self::safe::DepGraphSafe; pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 0000000000000..9c5b110929e22 --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,70 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::BodyId; +use hir::def_id::DefId; +use syntax::ast::NodeId; +use ty::TyCtxt; + +use super::graph::DepGraph; + +/// The `DepGraphSafe` auto trait is used to specify what kinds of +/// values are safe to "leak" into a task. The idea is that this +/// should be only be implemented for things like the tcx, which will +/// create reads in the dep-graph whenever the trait loads anything +/// that might depend on the input program. +pub trait DepGraphSafe { + fn read(&self, graph: &DepGraph); +} + +impl DepGraphSafe for BodyId { + fn read(&self, _graph: &DepGraph) { + // a BodyId on its own doesn't give access to any particular state + } +} + +impl DepGraphSafe for NodeId { + fn read(&self, _graph: &DepGraph) { + // a DefId doesn't give any particular state + } +} + +impl DepGraphSafe for DefId { + fn read(&self, _graph: &DepGraph) { + // a DefId doesn't give any particular state + } +} + +impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { + fn read(&self, _graph: &DepGraph) { + } +} + +impl DepGraphSafe for (A, B) + where A: DepGraphSafe, B: DepGraphSafe +{ + fn read(&self, graph: &DepGraph) { + self.0.read(graph); + self.1.read(graph); + } +} + +impl DepGraphSafe for () { + fn read(&self, _graph: &DepGraph) { + } +} + +/// A convenient override. We should phase out usage of this over +/// time. +pub struct AssertDepGraphSafe(pub T); +impl DepGraphSafe for AssertDepGraphSafe { + fn read(&self, _graph: &DepGraph) { + } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c4fccdcb9eb62..2ba4054ef3f6d 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -70,6 +70,7 @@ mod macros; pub mod diagnostics; pub mod cfg; +#[macro_use] pub mod dep_graph; pub mod hir; pub mod infer; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 47b614a81ae25..b441a231874a6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -61,13 +61,16 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { - tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { - borrowck_fn(tcx, body_id); - }); + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), + tcx, + body_id, + borrowck_fn); }); - }); + } } /// Collection of conclusions determined via borrow checker analyses. diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 03411e01a5798..2789250649674 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -192,7 +192,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, clean_work_products.insert(wp.clone()); } - tcx.dep_graph.with_task(n, || ()); // create the node with no inputs + tcx.dep_graph.with_task(n, (), (), create_node); + + fn create_node((): (), (): ()) { + // just create the node with no inputs + } } } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index a41489ff89ff4..58f23a5c81bd7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -38,11 +38,13 @@ use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::MirKrate, || { + tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task); + + fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { tcx.item_mir(body_owner_def_id); }); - }); + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 36f6fa7643909..1b43491e73c8f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -41,7 +41,7 @@ use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::{DepNode, WorkProduct}; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -1211,21 +1211,40 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Instantiate translation items without filling out definitions yet... for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_decl_task); + + fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, linkage) in trans_items { trans_item.predefine(&ccx, linkage); } - }); + } } // ... and now that we have everything pre-defined, fill out those definitions. for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_def_task); + + fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, _) in trans_items { trans_item.define(&ccx); } @@ -1247,7 +1266,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } - }); + } } symbol_names_test::report_symbol_names(&shared_ccx); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5f7549ece07b..f3aa3c67831ed 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,8 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, + DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def::ExportMap; @@ -274,6 +275,11 @@ pub struct CrateContext<'a, 'tcx: 'a> { index: usize, } +impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { + fn read(&self, _graph: &DepGraph) { + } +} + pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8957bad0986c..5bfed7eb14028 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -539,13 +539,15 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - tcx.sess.track_errors(|| { - tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); - }); + return tcx.sess.track_errors(|| { + tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, tcx, (), check_item_bodies_task); + }); + + fn check_item_bodies_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_tables(body_owner_def_id); }); - }) + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index db7cf3c000ba4..2417745571910 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -165,15 +165,10 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> { /// 4. This is added by the code in `visit_expr` when we write to `item_types`. /// 5. This is added by the code in `convert_item` when we write to `item_types`; /// note that this write occurs inside the `CollectItemSig` task. - /// 6. Added by explicit `read` below - fn with_collect_item_sig(&self, id: ast::NodeId, op: OP) - where OP: FnOnce() - { + /// 6. Added by reads from within `op`. + fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) { let def_id = self.tcx.hir.local_def_id(id); - self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || { - self.tcx.hir.read(id); - op(); - }); + self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op); } } @@ -183,7 +178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - self.with_collect_item_sig(item.id, || convert_item(self.tcx, item)); + self.with_collect_item_sig(item.id, convert_item); intravisit::walk_item(self, item); } @@ -216,16 +211,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_collect_item_sig(trait_item.id, || { - convert_trait_item(self.tcx, trait_item) - }); + self.with_collect_item_sig(trait_item.id, convert_trait_item); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_collect_item_sig(impl_item.id, || { - convert_impl_item(self.tcx, impl_item) - }); + self.with_collect_item_sig(impl_item.id, convert_impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -493,9 +484,10 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt, } } -fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { +fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { + let it = tcx.hir.expect_item(item_id); debug!("convert: item {} with id {}", it.name, it.id); - let def_id = tcx.hir.local_def_id(it.id); + let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { @@ -560,7 +552,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { } } -fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) { +fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { + let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); tcx.item_generics(def_id); @@ -577,8 +570,8 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::T tcx.item_predicates(def_id); } -fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) { - let def_id = tcx.hir.local_def_id(impl_item.id); +fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { + let def_id = tcx.hir.local_def_id(impl_item_id); tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); From 19c6bfbf15d0e7102d9f42553a6dbf40917a6fac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Mar 2017 09:14:27 -0500 Subject: [PATCH 43/73] add comments and remove unused code paths --- src/librustc/dep_graph/graph.rs | 29 +++++++++++++++++-- src/librustc/dep_graph/mod.rs | 1 - src/librustc/dep_graph/safe.rs | 51 ++++++++++++++------------------- src/librustc/lib.rs | 1 - src/librustc_trans/context.rs | 2 -- 5 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e22f56d278d55..8be5d4327e72e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -77,12 +77,37 @@ impl DepGraph { op() } + /// Starts a new dep-graph task. Dep-graph tasks are specified + /// using a free function (`task`) and **not** a closure -- this + /// is intentional because we want to exercise tight control over + /// what state they have access to. In particular, we want to + /// prevent implicit 'leaks' of tracked state into the task (which + /// could then be read without generating correct edges in the + /// dep-graph -- see the [README] for more details on the + /// dep-graph). To this end, the task function gets exactly two + /// pieces of state: the context `cx` and an argument `arg`. Both + /// of these bits of state must be of some type that implements + /// `DepGraphSafe` and hence does not leak. + /// + /// The choice of two arguments is not fundamental. One argument + /// would work just as well, since multiple values can be + /// collected using tuples. However, using two arguments works out + /// to be quite convenient, since it is common to need a context + /// (`cx`) and some argument (e.g., a `DefId` identifying what + /// item to process). + /// + /// For cases where you need some other number of arguments: + /// + /// - If you only need one argument, just use `()` for the `arg` + /// parameter. + /// - If you need 3+ arguments, use a tuple for the + /// `arg` parameter. + /// + /// [README]: README.md pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - cx.read(self); - arg.read(self); task(cx, arg) } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 496375b129167..a9f0a44e4208c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,7 +15,6 @@ mod edges; mod graph; mod query; mod raii; -#[macro_use] mod safe; mod shadow; mod thread; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs index 9c5b110929e22..f85f0338ed997 100644 --- a/src/librustc/dep_graph/safe.rs +++ b/src/librustc/dep_graph/safe.rs @@ -13,58 +13,51 @@ use hir::def_id::DefId; use syntax::ast::NodeId; use ty::TyCtxt; -use super::graph::DepGraph; - -/// The `DepGraphSafe` auto trait is used to specify what kinds of -/// values are safe to "leak" into a task. The idea is that this -/// should be only be implemented for things like the tcx, which will -/// create reads in the dep-graph whenever the trait loads anything -/// that might depend on the input program. +/// The `DepGraphSafe` trait is used to specify what kinds of values +/// are safe to "leak" into a task. The idea is that this should be +/// only be implemented for things like the tcx as well as various id +/// types, which will create reads in the dep-graph whenever the trait +/// loads anything that might depend on the input program. pub trait DepGraphSafe { - fn read(&self, graph: &DepGraph); } +/// A `BodyId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for BodyId { - fn read(&self, _graph: &DepGraph) { - // a BodyId on its own doesn't give access to any particular state - } } +/// A `NodeId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for NodeId { - fn read(&self, _graph: &DepGraph) { - // a DefId doesn't give any particular state - } } +/// A `DefId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. impl DepGraphSafe for DefId { - fn read(&self, _graph: &DepGraph) { - // a DefId doesn't give any particular state - } } +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { - fn read(&self, _graph: &DepGraph) { - } } +/// Tuples make it easy to build up state. impl DepGraphSafe for (A, B) where A: DepGraphSafe, B: DepGraphSafe { - fn read(&self, graph: &DepGraph) { - self.0.read(graph); - self.1.read(graph); - } } +/// No data here! :) impl DepGraphSafe for () { - fn read(&self, _graph: &DepGraph) { - } } -/// A convenient override. We should phase out usage of this over -/// time. +/// A convenient override that lets you pass arbitrary state into a +/// task. Every use should be accompanied by a comment explaining why +/// it makes sense (or how it could be refactored away in the future). pub struct AssertDepGraphSafe(pub T); + impl DepGraphSafe for AssertDepGraphSafe { - fn read(&self, _graph: &DepGraph) { - } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2ba4054ef3f6d..c4fccdcb9eb62 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -70,7 +70,6 @@ mod macros; pub mod diagnostics; pub mod cfg; -#[macro_use] pub mod dep_graph; pub mod hir; pub mod infer; diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index f3aa3c67831ed..52851ea995d4b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -276,8 +276,6 @@ pub struct CrateContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { - fn read(&self, _graph: &DepGraph) { - } } pub struct CrateContextIterator<'a, 'tcx: 'a> { From 5f10bb5cb48b1999ab8bd9f3ea2fa240b76e8246 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Feb 2017 07:57:59 -0800 Subject: [PATCH 44/73] Remove internal liblog This commit deletes the internal liblog in favor of the implementation that lives on crates.io. Similarly it's also setting a convention for adding crates to the compiler. The main restriction right now is that we want compiler implementation details to be unreachable from normal Rust code (e.g. requires a feature), and by default everything in the sysroot is reachable via `extern crate`. The proposal here is to require that crates pulled in have these lines in their `src/lib.rs`: #![cfg_attr(rustbuild, feature(staged_api, rustc_private))] #![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] This'll mean that by default they're not using these attributes but when compiled as part of the compiler they do a few things: * Mark themselves as entirely unstable via the `staged_api` feature and the `#![unstable]` attribute. * Allow usage of other unstable crates via `feature(rustc_private)` which is required if the crate relies on any other crates to compile (other than std). --- src/Cargo.lock | 79 ++-- src/bootstrap/bin/rustc.rs | 1 + src/liblog/Cargo.toml | 9 - src/liblog/directive.rs | 193 --------- src/liblog/lib.rs | 506 ------------------------ src/liblog/macros.rs | 205 ---------- src/librustc/Cargo.toml | 2 +- src/librustc/hir/map/mod.rs | 2 +- src/librustc_back/Cargo.toml | 2 +- src/librustc_borrowck/Cargo.toml | 2 +- src/librustc_const_eval/Cargo.toml | 2 +- src/librustc_data_structures/Cargo.toml | 2 +- src/librustc_driver/Cargo.toml | 3 +- src/librustc_driver/driver.rs | 4 +- src/librustc_driver/lib.rs | 2 + src/librustc_incremental/Cargo.toml | 2 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- src/librustc_passes/Cargo.toml | 4 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_save_analysis/Cargo.toml | 4 +- src/librustc_trans/Cargo.toml | 2 +- src/librustc_typeck/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 5 +- src/librustdoc/lib.rs | 2 + src/libsyntax/Cargo.toml | 2 +- src/libsyntax_ext/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 2 +- 30 files changed, 67 insertions(+), 984 deletions(-) delete mode 100644 src/liblog/Cargo.toml delete mode 100644 src/liblog/directive.rs delete mode 100644 src/liblog/lib.rs delete mode 100644 src/liblog/macros.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index f4174693a5771..913bc91f2af89 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -121,7 +121,7 @@ dependencies = [ "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -133,7 +133,7 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -165,7 +165,7 @@ dependencies = [ "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -230,9 +230,9 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -299,18 +299,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -405,7 +397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -433,7 +425,7 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -525,11 +517,7 @@ version = "0.1.0" [[package]] name = "log" -version = "0.0.0" - -[[package]] -name = "log" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -543,9 +531,9 @@ version = "0.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -862,7 +850,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -902,7 +890,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -916,7 +904,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -931,7 +919,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -953,7 +941,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -962,8 +950,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1002,7 +991,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1014,7 +1003,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1046,7 +1035,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1065,7 +1054,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -1089,7 +1078,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -1128,7 +1117,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1139,7 +1128,7 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -1151,7 +1140,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -1183,7 +1172,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1201,8 +1190,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1340,7 +1330,7 @@ dependencies = [ name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -1353,7 +1343,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1579,8 +1569,7 @@ dependencies = [ "checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa" "checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" -"checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" +"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" @@ -1601,7 +1590,7 @@ dependencies = [ "checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95" "checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934" "checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" -"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" +"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" "checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..5e6f3e9e6cc0f 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -79,6 +79,7 @@ fn main() { cmd.args(&args) .arg("--cfg") .arg(format!("stage{}", stage)) + .arg("--cfg").arg("rustbuild") .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d034..0000000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135ef..0000000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 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. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c7257..0000000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 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. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc8b..0000000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2014 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. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7fdc..fa217acd9f9bf 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5d074903b2b99..2a938dadd28dc 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -948,7 +948,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a9f..730abc54568e1 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f176848..af99c0e938724 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32ec..907410f74dca4 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d9871..343b1ed68b804 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e0058..5b5113caa8e8c 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..4726a9b4178bf 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -195,13 +195,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9810f121ef2c1..36b67eeefd4f4 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -1127,6 +1128,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee752754504..7bf2efa4b885f 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -13,6 +13,6 @@ graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae1..c3c5461ff7c50 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216b9..e8b906092730e 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 49dcffb4830a1..396a4f53b3c4d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1055,7 +1055,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.inject_allocator_crate(); self.inject_panic_runtime(krate); - if log_enabled!(log::INFO) { + if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 531be0b6ae9f5..6e42e02d5109b 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index cc710e0ac3563..d2560c2f8203f 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -9,10 +9,10 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file +rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 5ce4c74e735fd..0968ea31b754f 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } arena = { path = "../libarena" } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 3d66e5a300787..3d12df19acbe2 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -9,8 +9,8 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b5c67ad998b69..07dcb2fc29dc6 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,7 +11,7 @@ test = false [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e50e..07998aa4a30ea 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 93c0bd6d6d836..1c479ce1d0157 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,11 +11,13 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } +env_logger = { version = "0.4", default-features = false } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } -rustc_driver = { path = "../librustc_driver" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } @@ -24,7 +26,6 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 84f69cd35045c..8dd03f6edc4d5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate arena; extern crate getopts; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_const_eval; @@ -99,6 +100,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + env_logger::init().unwrap(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b63f..97d37266130af 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 960db792a623e..bdcec26cb838b 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1fc98a78a7c47..7530b65a9b7c4 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,6 +5,6 @@ version = "0.0.0" [dependencies] log = "0.3" -env_logger = { version = "0.3.5", default-features = false } +env_logger = { version = "0.4", default-features = false } rustc-serialize = "0.3" filetime = "0.1" From c4275c2ac376c866c93982e5513f5c6cb6d4dd98 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:03:04 +0200 Subject: [PATCH 45/73] rustc_trans: don't emit ZST allocas that are only assigned to. --- src/librustc_trans/mir/analyze.rs | 3 +- src/librustc_trans/mir/mod.rs | 21 +++---------- src/librustc_trans/mir/operand.rs | 18 +++++++++++- src/librustc_trans/mir/rvalue.rs | 49 +++++++++++++++++-------------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2c3b479c7dd0f..6f0f9cabef345 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -18,7 +18,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -92,7 +91,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6d..eaedabc1f54c9 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,20 +11,18 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout, Ty, TypeFoldable}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; -use type_of; use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; use syntax::symbol::keywords; @@ -176,23 +174,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index cb77fcbbff85d..df6667afd442e 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,7 +15,7 @@ use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -77,6 +77,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b6af4e52e820b..4328f2516970e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -170,7 +170,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -478,8 +478,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -662,26 +664,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, - } + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::Box(..) | + mir::Rvalue::Use(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } - // (*) this is only true if the type is suitable + // (*) this is only true if the type is suitable + } } #[derive(Copy, Clone)] From df60044df5b531a8fc144024535d0dea43ca8b52 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 20:08:09 +0200 Subject: [PATCH 46/73] rustc_trans: avoid a separate entry BB if START_BLOCK has no backedges. --- src/librustc_trans/mir/mod.rs | 17 ++++++----- src/test/codegen/naked-functions.rs | 47 +++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index eaedabc1f54c9..3bcb6e78dce9f 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -199,15 +199,17 @@ pub fn trans_mir<'a, 'tcx: 'a>( debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir); - let bcx = Builder::new_block(ccx, llfn, "entry-block"); + let bcx = Builder::new_block(ccx, llfn, "start"); let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); let block_bcxs: IndexVec = mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - bcx.build_sibling_block("start").llbb() + if bb == mir::START_BLOCK && !reentrant_start_block { + bcx.llbb() } else { bcx.build_sibling_block(&format!("{:?}", bb)).llbb() } @@ -294,9 +296,10 @@ pub fn trans_mir<'a, 'tcx: 'a>( .collect() }; - // Branch to the START block - let start_bcx = mircx.blocks[mir::START_BLOCK]; - bcx.br(start_bcx); + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bcx.br(mircx.blocks[mir::START_BLOCK]); + } // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9de74f72005e3..9883ca6b35d04 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -20,7 +20,8 @@ #[no_mangle] #[naked] fn naked_empty() { - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret void } // CHECK: Function Attrs: naked uwtable @@ -28,9 +29,10 @@ fn naked_empty() { #[naked] // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret void } // CHECK: Function Attrs: naked uwtable @@ -38,7 +40,8 @@ fn naked_with_args(a: isize) { #[no_mangle] #[naked] fn naked_with_return() -> isize { - // CHECK: ret i{{[0-9]+}} 0 + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } @@ -47,9 +50,10 @@ fn naked_with_return() -> isize { #[no_mangle] #[naked] fn naked_with_args_and_return(a: isize) -> isize { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a } @@ -58,14 +62,37 @@ fn naked_with_args_and_return(a: isize) -> isize { #[no_mangle] #[naked] fn naked_recursive() { - // CHECK: call void @naked_empty() + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: call void @naked_empty() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb1 + // CHECK: bb1: + naked_empty(); - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb2 + // CHECK: bb2: + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb3 + // CHECK: bb3: + + // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb4 + // CHECK: bb4: + naked_with_args( - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) naked_with_args_and_return( - // CHECK: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) naked_with_return() ) ); + // CHECK-NEXT: ret void } From 2719b8493f4e9c47067ef09000ca0d182c12ef87 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 20:30:06 +0300 Subject: [PATCH 47/73] Give spans to individual path segments in AST --- src/librustc_resolve/lib.rs | 7 +++---- src/librustc_resolve/macros.rs | 5 ++++- src/libsyntax/ast.rs | 14 +++++++------- src/libsyntax/ext/build.rs | 19 ++++++++++++------- src/libsyntax/fold.rs | 3 ++- src/libsyntax/parse/mod.rs | 18 +++++++++++------- src/libsyntax/parse/parser.rs | 29 ++++++++++++++++++----------- src/libsyntax/std_inject.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/concat_idents.rs | 2 +- 10 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec217..105af23d05c05 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3124,11 +3124,10 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(ident.into()); + segms.push(ast::PathSegment::from_ident(ident, name_binding.span)); let path = Path { - span: span, + span: name_binding.span, segments: segms, }; // the entity is accessible in the following cases: @@ -3148,7 +3147,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ident.into()); + path_segments.push(ast::PathSegment::from_ident(ident, name_binding.span)); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..d81bdf17034e6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -110,8 +110,11 @@ impl<'a> base::Resolver for Resolver<'a> { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); if !module.is_local() { + let span = path.segments[0].span; path.segments.insert(1, match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), + ModuleKind::Def(_, name) => ast::PathSegment::from_ident( + ast::Ident::with_empty_ctxt(name), span + ), _ => unreachable!(), }) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..adb7e8d101fd1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -134,7 +134,7 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - segments: vec![identifier.into()], + segments: vec![PathSegment::from_ident(identifier, s)], } } @@ -159,6 +159,8 @@ impl Path { pub struct PathSegment { /// The identifier portion of this path segment. pub identifier: Ident, + /// Span of the segment identifier. + pub span: Span, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -170,16 +172,14 @@ pub struct PathSegment { pub parameters: Option>, } -impl From for PathSegment { - fn from(id: Ident) -> Self { - PathSegment { identifier: id, parameters: None } - } -} - impl PathSegment { + pub fn from_ident(ident: Ident, span: Span) -> Self { + PathSegment { identifier: ident, span: span, parameters: None } + } pub fn crate_root() -> Self { PathSegment { identifier: keywords::CrateRoot.ident(), + span: DUMMY_SP, parameters: None, } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f8d4eff80b2d1..e0fb46ff5eb09 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,11 +38,11 @@ pub trait AstBuilder { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -323,7 +323,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment::crate_root()); } - segments.extend(idents.into_iter().map(Into::into)); + segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp))); let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { None } else { @@ -333,7 +333,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }))) }; - segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); + segments.push(ast::PathSegment { + identifier: last_identifier, + span: sp, + parameters: parameters + }); ast::Path { span: sp, segments: segments, @@ -346,7 +350,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path) { self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } @@ -357,7 +361,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -369,7 +373,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }; path.segments.push(ast::PathSegment { - identifier: ident, + identifier: ident.node, + span: ident.span, parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..665f48ab45679 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -434,8 +434,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { + segments: segments.move_map(|PathSegment {identifier, span, parameters}| PathSegment { identifier: fld.fold_ident(identifier), + span: fld.new_span(span), parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b42..88535f91379f7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -617,13 +617,17 @@ mod tests { Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} } + fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { + ast::PathSegment::from_ident(Ident::from_str(s), sp(lo, hi)) + } + #[test] fn path_exprs_1() { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - segments: vec![Ident::from_str("a").into()], + segments: vec![str2seg("a", 0, 1)], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -637,8 +641,8 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), segments: vec![ast::PathSegment::crate_root(), - Ident::from_str("a").into(), - Ident::from_str("b").into()] + str2seg("a", 2, 3), + str2seg("b", 5, 6)] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -744,7 +748,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - segments: vec![Ident::from_str("d").into()], + segments: vec![str2seg("d", 7, 8)], }), span:sp(7,8), attrs: ThinVec::new(), @@ -761,7 +765,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 0, 1)], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -802,7 +806,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - segments: vec![Ident::from_str("i32").into()], + segments: vec![str2seg("i32", 10, 13)], }), span:sp(10,13) }), @@ -844,7 +848,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 17, 18)], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..002f1359b6fa5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use ast::Local; use ast::MacStmtStyle; use ast::Mac_; use ast::{MutTy, Mutability}; -use ast::{Pat, PatKind}; +use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; @@ -1811,7 +1811,7 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, ast::PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root()); } // Assemble the span. @@ -1829,11 +1829,12 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1881,7 +1882,11 @@ impl<'a> Parser<'a> { }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); + segments.push(PathSegment { + identifier: identifier, + span: ident_span, + parameters: parameters + }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1892,15 +1897,16 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); return Ok(segments); } @@ -1909,8 +1915,9 @@ impl<'a> Parser<'a> { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; - segments.push(ast::PathSegment { + segments.push(PathSegment { identifier: identifier, + span: ident_span, parameters: ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1924,7 +1931,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); } } } @@ -1932,14 +1939,14 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` pub fn parse_path_segments_without_types(&mut self) - -> PResult<'a, Vec> { + -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, self.prev_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -5902,7 +5909,7 @@ impl<'a> Parser<'a> { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![ast::PathSegment::crate_root()], + segments: vec![PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf61247c..2192d203cdc23 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -82,7 +82,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { - ast::Ident::from_str(name).into() + ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP) }).collect(), span: span, })))), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dd2756cd2b22c..e052d2cda3a42 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,7 +580,7 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - segments: ids.into_iter().map(Into::into).collect(), + segments: ids.into_iter().map(|id| ast::PathSegment::from_ident(id, DUMMY_SP)).collect(), } } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1fc1bdff593c2..dc4b8eb24cd0a 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - segments: vec![self.ident.into()], + segments: vec![ast::PathSegment::from_ident(self.ident, self.span)], } } } From 7cfe20c676e3f17a065a24cc7da8647c135cc70e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 22:15:12 +0300 Subject: [PATCH 48/73] resolve: Use path segment spans in smart_resolve_path --- src/librustc_resolve/lib.rs | 50 +++++++++---------- src/librustc_resolve/macros.rs | 1 - .../ui/resolve/enums-are-namespaced-xc.stderr | 12 ++--- src/test/ui/resolve/levenshtein.stderr | 10 ++-- ...uggest-path-instead-of-mod-dot-item.stderr | 36 +++++++++---- ...xed-closure-sugar-nonexistent-trait.stderr | 2 +- 6 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 105af23d05c05..99061747832ec 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -407,7 +407,7 @@ enum PathSource<'a> { // Trait paths in bounds or impls. Trait, // Expression paths `path`, with optional parent context. - Expr(Option<&'a ExprKind>), + Expr(Option<&'a Expr>), // Paths in path patterns `Path`. Pat, // Paths in struct expressions and patterns `Path { .. }`. @@ -464,7 +464,7 @@ impl<'a> PathSource<'a> { ValueNS => "method or associated constant", MacroNS => bug!("associated macro"), }, - PathSource::Expr(parent) => match parent { + PathSource::Expr(parent) => match parent.map(|p| &p.node) { // "function" here means "anything callable" rather than `Def::Fn`, // this is not precise but usually more helpful than just "value". Some(&ExprKind::Call(..)) => "function", @@ -2194,7 +2194,8 @@ impl<'a> Resolver<'a> { source: PathSource) -> PathResolution { let segments = &path.segments.iter().map(|seg| seg.identifier).collect::>(); - self.smart_resolve_path_fragment(id, qself, segments, path.span, source) + let ident_span = path.segments.last().map_or(path.span, |seg| seg.span); + self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source) } fn smart_resolve_path_fragment(&mut self, @@ -2202,6 +2203,7 @@ impl<'a> Resolver<'a> { qself: Option<&QSelf>, path: &[Ident], span: Span, + ident_span: Span, source: PathSource) -> PathResolution { let ns = source.namespace(); @@ -2213,9 +2215,9 @@ impl<'a> Resolver<'a> { let expected = source.descr_expected(); let path_str = names_to_string(path); let code = source.error_code(def.is_some()); - let (base_msg, fallback_label) = if let Some(def) = def { + let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), - format!("not a {}", expected)) + format!("not a {}", expected), span) } else { let item_str = path[path.len() - 1]; let (mod_prefix, mod_str) = if path.len() == 1 { @@ -2231,9 +2233,9 @@ impl<'a> Resolver<'a> { (mod_prefix, format!("`{}`", names_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str)) + format!("not found in {}", mod_str), ident_span) }; - let mut err = this.session.struct_span_err_with_code(span, &base_msg, code); + let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { @@ -2291,15 +2293,15 @@ impl<'a> Resolver<'a> { err.span_label(span, &format!("type aliases cannot be used for traits")); return err; } - (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent { + (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { ExprKind::Field(_, ident) => { - err.span_label(span, &format!("did you mean `{}::{}`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}`?", + path_str, ident.node)); return err; } ExprKind::MethodCall(ident, ..) => { - err.span_label(span, &format!("did you mean `{}::{}(...)`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}(...)`?", + path_str, ident.node)); return err; } _ => {} @@ -2324,12 +2326,12 @@ impl<'a> Resolver<'a> { // Try Levenshtein if nothing else worked. if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) { - err.span_label(span, &format!("did you mean `{}`?", candidate)); + err.span_label(ident_span, &format!("did you mean `{}`?", candidate)); return err; } // Fallback label. - err.span_label(span, &fallback_label); + err.span_label(base_span, &fallback_label); err }; let report_errors = |this: &mut Self, def: Option| { @@ -2449,7 +2451,7 @@ impl<'a> Resolver<'a> { // Make sure `A::B` in `::B::C` is a trait item. let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1], - span, PathSource::TraitItem(ns)); + span, span, PathSource::TraitItem(ns)); return Some(PathResolution::with_unresolved_segments( res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 )); @@ -2807,7 +2809,7 @@ impl<'a> Resolver<'a> { path: &[Ident], ns: Namespace, filter_fn: FilterFn) - -> Option + -> Option where FilterFn: Fn(Def) -> bool { let add_module_candidates = |module: Module, names: &mut Vec| { @@ -2821,7 +2823,7 @@ impl<'a> Resolver<'a> { }; let mut names = Vec::new(); - let prefix_str = if path.len() == 1 { + if path.len() == 1 { // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { @@ -2855,21 +2857,19 @@ impl<'a> Resolver<'a> { names.push(*name); } } - String::new() } else { // Search in module. let mod_path = &path[..path.len() - 1]; if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) { add_module_candidates(module, &mut names); } - names_to_string(mod_path) + "::" - }; + } let name = path[path.len() - 1].name; // Make sure error reporting is deterministic. names.sort_by_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { - Some(found) if found != name => Some(format!("{}{}", prefix_str, found)), + Some(found) if found != name => Some(found), _ => None, } } @@ -2892,7 +2892,7 @@ impl<'a> Resolver<'a> { self.with_resolved_label(label, id, |this| this.visit_block(block)); } - fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) { + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -2973,11 +2973,11 @@ impl<'a> Resolver<'a> { // Equivalent to `visit::walk_expr` + passing some context to children. ExprKind::Field(ref subexpression, _) => { - self.resolve_expr(subexpression, Some(&expr.node)); + self.resolve_expr(subexpression, Some(expr)); } ExprKind::MethodCall(_, ref types, ref arguments) => { let mut arguments = arguments.iter(); - self.resolve_expr(arguments.next().unwrap(), Some(&expr.node)); + self.resolve_expr(arguments.next().unwrap(), Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } @@ -2993,7 +2993,7 @@ impl<'a> Resolver<'a> { }); } ExprKind::Call(ref callee, ref arguments) => { - self.resolve_expr(callee, Some(&expr.node)); + self.resolve_expr(callee, Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index d81bdf17034e6..9d4779a06baf6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -502,7 +502,6 @@ impl<'a> Resolver<'a> { }; let ident = Ident::from_str(name); self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro) - .as_ref().map(|s| Symbol::intern(s)) }); if let Some(suggestion) = suggestion { diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr index d541aa599a48b..dd04c5ce356c6 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -1,26 +1,26 @@ error[E0425]: cannot find value `A` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:15:13 + --> $DIR/enums-are-namespaced-xc.rs:15:31 | 15 | let _ = namespaced_enums::A; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::A;` error[E0425]: cannot find function `B` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:18:13 + --> $DIR/enums-are-namespaced-xc.rs:18:31 | 18 | let _ = namespaced_enums::B(10); - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::B;` error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:21:13 + --> $DIR/enums-are-namespaced-xc.rs:21:31 | 21 | let _ = namespaced_enums::C { a: 10 }; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::C;` diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index c7c42bcf23940..4dff2620319e4 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -14,7 +14,7 @@ error[E0412]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:20:10 | 20 | type B = Opiton; // Misspelled type name from the prelude. - | ^^^^^^^^^^ did you mean `Option`? + | ^^^^^^ did you mean `Option`? error[E0412]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:23:14 @@ -35,16 +35,16 @@ error[E0425]: cannot find function `foobar` in this scope | ^^^^^^ did you mean `foo_bar`? error[E0412]: cannot find type `first` in module `m` - --> $DIR/levenshtein.rs:32:12 + --> $DIR/levenshtein.rs:32:15 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^ did you mean `m::First`? + | ^^^^^ did you mean `First`? error[E0425]: cannot find value `second` in module `m` - --> $DIR/levenshtein.rs:32:23 + --> $DIR/levenshtein.rs:32:26 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^^ did you mean `m::Second`? + | ^^^^^^ did you mean `Second`? error: aborting due to 8 previous errors diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr index 57c0ecc813505..85fb1777dea23 100644 --- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr +++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr @@ -2,55 +2,73 @@ error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5 | 27 | a.I - | ^ did you mean `a::I`? + | ^-- + | | + | did you mean `a::I`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5 | 33 | a.g() - | ^ did you mean `a::g(...)`? + | ^---- + | | + | did you mean `a::g(...)`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5 | 39 | a.b.J - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5 | 45 | a::b.J - | ^^^^ did you mean `a::b::J`? + | ^^^^-- + | | + | did you mean `a::b::J`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5 | 51 | a.b.f(); - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12 | 55 | v.push(a::b); - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5 | 61 | a::b.f() - | ^^^^ did you mean `a::b::f(...)`? + | ^^^^---- + | | + | did you mean `a::b::f(...)`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5 | 67 | a::b - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected function, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5 | 73 | a::b() - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error: main function not found diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index f0d363f7335f7..015dbfc3dc775 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -2,7 +2,7 @@ error[E0405]: cannot find trait `Nonexist` in this scope --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:11:8 | 11 | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0404]: expected trait, found type alias `Typedef` --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:17:8 From 79a7ee8d831d7bacc4d52cd76bbc0dcd15fddfe5 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Wed, 8 Mar 2017 21:17:55 +0100 Subject: [PATCH 49/73] fix UB in repr(packed) tests --- .../extern-fn-with-packed-struct/test.rs | 24 ++++++++++++++++++- src/test/run-pass/packed-struct-vec.rs | 21 +++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.rs b/src/test/run-make/extern-fn-with-packed-struct/test.rs index c0f55893a3abe..9e81636e36703 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/test.rs +++ b/src/test/run-make/extern-fn-with-packed-struct/test.rs @@ -8,14 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; + #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { a: i8, b: i16, c: i8 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let a = self.a; + let b = self.b; + let c = self.c; + + f.debug_struct("Foo") + .field("a", &a) + .field("b", &b) + .field("c", &c) + .finish() + } +} + #[link(name = "test", kind = "static")] extern { fn foo(f: Foo) -> Foo; diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 4b32b881be738..57407b8422371 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -8,15 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; use std::mem; #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { bar: u8, baz: u64 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + pub fn main() { let foos = [Foo { bar: 1, baz: 2 }; 10]; From edf5dc66c1ec243bb2a60385b094cde719c0a492 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 8 Mar 2017 21:53:28 -0500 Subject: [PATCH 50/73] Box docs: no allocation is done for ZSTs. --- src/liballoc/boxed.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d0fce70612868..43b0d72186a29 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -225,6 +225,8 @@ impl Drop for IntermediateBox { impl Box { /// Allocates memory on the heap and then places `x` into it. /// + /// This doesn't actually allocate if `T` is zero-sized. + /// /// # Examples /// /// ``` From 74bc7fda8c1cdb8bbf29d9901cbfc31a2e0da86b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Mar 2017 14:36:49 +0200 Subject: [PATCH 51/73] Overhaul coercion to use the lazy InferOk obligations passing. --- src/librustc_typeck/check/autoderef.rs | 14 +- src/librustc_typeck/check/coercion.rs | 194 +++++++++++-------------- 2 files changed, 99 insertions(+), 109 deletions(-) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index ca0ab8f1e8c77..1aab4853a4f64 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; @@ -149,6 +150,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) where I: IntoIterator + { + let fcx = self.fcx; + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + } + + pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) + -> InferOk<'tcx, ()> + where I: IntoIterator { let methods: Vec<_> = self.steps .iter() @@ -176,8 +185,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } - for obligation in self.obligations { - self.fcx.register_predicate(obligation); + InferOk { + value: (), + obligations: self.obligations } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 53759cc115d1c..651058728816e 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -64,7 +64,8 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, @@ -75,9 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; -use util::common::indent; -use std::cell::RefCell; use std::collections::VecDeque; use std::ops::Deref; @@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, - unsizing_obligations: RefCell>>, } impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { @@ -95,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; +type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } +fn identity<'tcx>() -> Adjust<'tcx> { + Adjust::DerefRef { + autoderefs: 0, + autoref: None, + unsize: false, + } +} + +fn success<'tcx>(kind: Adjust<'tcx>, + target: Ty<'tcx>, + obligations: traits::PredicateObligations<'tcx>) + -> CoerceResult<'tcx> { + Ok(InferOk { + value: Adjustment { + kind, + target + }, + obligations + }) +} + impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, cause: cause, use_lub: false, - unsizing_obligations: RefCell::new(vec![]), } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - self.fcx.register_predicates(obligations); - value - }) } }) } - /// Unify two types (using sub or lub) and produce a noop coercion. - fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - self.unify(&a, &b).and_then(|ty| self.identity(ty)) - } - - /// Synthesize an identity adjustment. - fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, Adjust::DerefRef { - autoderefs: 0, - autoref: None, - unsize: false, - })) + /// Unify two types (using sub or lub) and produce a specific coercion. + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) + -> CoerceResult<'tcx> { + self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { + success(kind, ty, obligations) + }) } fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> @@ -158,11 +165,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return self.identity(b); + return success(identity(), b, vec![]); } if a.is_never() { - return Ok((b, Adjust::NeverToAny)); + return success(Adjust::NeverToAny, b, vec![]); } // Consider coercing the subtype to a DST @@ -208,7 +215,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and_identity(a, b) + self.unify_and(a, b, identity()) } } } @@ -240,7 +247,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and_identity(a, b), + _ => return self.unify_and(a, b, identity()), }; let span = self.cause.span; @@ -248,7 +255,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut first_error = None; let mut r_borrow_var = None; let mut autoderef = self.autoderef(span, a); - let mut success = None; + let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { if autoderefs == 0 { @@ -346,8 +353,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mt_b.mutbl, // [1] above }); match self.unify(derefd_ty_a, b) { - Ok(ty) => { - success = Some((ty, autoderefs)); + Ok(ok) => { + found = Some((ok, autoderefs)); break; } Err(err) => { @@ -363,7 +370,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (ty, autoderefs) = match success { + let (InferOk { value: ty, mut obligations }, autoderefs) = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -372,12 +379,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - // This commits the obligations to the fulfillcx. After this succeeds, - // this snapshot can't be rolled back. - autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); - - // Now apply the autoref. We have to extract the region out of - // the final ref type we got. if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as @@ -391,8 +392,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return self.identity(ty); + return success(identity(), ty, obligations); } + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), @@ -402,11 +406,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty, autoderefs, autoref); - Ok((ty, Adjust::DerefRef { + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + + success(Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, unsize: false, - })) + }, ty, obligations) } @@ -451,7 +459,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut leftover_predicates = vec![]; + let mut obligations = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); @@ -467,7 +475,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - leftover_predicates.push(obligation); + obligations.push(obligation); continue; } }; @@ -495,33 +503,30 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - *self.unsizing_obligations.borrow_mut() = leftover_predicates; - - let adjustment = Adjust::DerefRef { + success(Adjust::DerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, unsize: true, - }; - debug!("Success, coerced with {:?}", adjustment); - Ok((target, adjustment)) + }, target, obligations) } fn coerce_from_safe_fn(&self, a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>) + b: Ty<'tcx>, + to_unsafe: Adjust<'tcx>, + normal: Adjust<'tcx>) -> CoerceResult<'tcx> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); + return self.unify_and(unsafe_a, b, to_unsafe); } _ => {} } } - self.unify_and_identity(a, b) + self.unify_and(a, b, normal) } fn coerce_from_fn_pointer(&self, @@ -536,7 +541,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - self.coerce_from_safe_fn(a, fn_ty_a, b) + self.coerce_from_safe_fn(a, fn_ty_a, b, + Adjust::UnsafeFnPointer, identity()) } fn coerce_from_fn_item(&self, @@ -554,10 +560,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) - .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, + Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -582,7 +588,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.cause.span, feature_gate::GateIssue::Language, feature_gate::CLOSURE_TO_FN_COERCION); - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -607,10 +613,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and_identity(pointer_ty, b) - .map(|(ty, _)| (ty, Adjust::ClosureFnPointer)) + self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -625,7 +630,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } }; @@ -634,50 +639,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mutbl_b, ty: mt_a.ty, }); - let (ty, noop) = self.unify_and_identity(a_unsafe, b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?; - // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - Ok((ty, - if is_ref { - Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - } - } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer - } else { - noop - })) - } -} - -fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Adjustment<'tcx>> - where E: Fn() -> I, - I: IntoIterator -{ - - let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; - - let fcx = coerce.fcx; - if let Adjust::DerefRef { unsize: true, .. } = adjust { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + self.unify_and(a_unsafe, b, if is_ref { + Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } + } else if mt_a.mutbl != mutbl_b { + Adjust::MutToConstPointer + } else { + identity() + }) } - - Ok(Adjustment { - kind: adjust, - target: ty - }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -694,9 +671,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); - let mut coerce = Coerce::new(self, cause); + let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; + let ok = coerce.coerce(&|| Some(expr), source, target)?; + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { @@ -773,9 +751,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); match result { - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } @@ -816,7 +795,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { @@ -828,7 +807,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); for expr in exprs() { From bee6762cac30aff22aafbabe4be2fbfed77a6e76 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 7 Mar 2017 09:08:03 -0800 Subject: [PATCH 52/73] travis: Attempt to debug sccache failures I can't find anything that'd cause unexpected EOF in the source, so let's try taking a look at the error logs on failures. --- .travis.yml | 1 + src/ci/docker/run.sh | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f12408242f47..93f1ac09868b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,6 +127,7 @@ after_failure: echo "#### Build failed; Disk usage after running script:"; df -h; du . | sort -nr | head -n100 + - cat obj/tmp/sccache.log # Save tagged docker images we created and load them if they're available before_cache: diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 1e61f2169106c..437041e0292ca 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -30,13 +30,17 @@ retry docker \ objdir=$root_dir/obj mkdir -p $HOME/.cargo -mkdir -p $objdir +mkdir -p $objdir/tmp args= if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env SCCACHE_BUCKET=$SCCACHE_BUCKET" args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" + args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" + args="$args --env SCCACHE_LOG_LEVEL=debug" + args="$args --env RUST_LOG=sccache=debug" + args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache" From 4eeede3e0f2496994b4c0bbaa59927066d642807 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Sat, 4 Mar 2017 14:59:49 +0100 Subject: [PATCH 53/73] fix emscripten test detection --- src/bootstrap/check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index dfe96b51799c0..68b3623a53f25 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -550,7 +550,7 @@ fn find_tests(dir: &Path, let filename = e.file_name().into_string().unwrap(); if (target.contains("windows") && filename.ends_with(".exe")) || (!target.contains("windows") && !filename.contains(".")) || - (target.contains("emscripten") && filename.contains(".js")){ + (target.contains("emscripten") && filename.ends_with(".js")) { dst.push(e.path()); } } From 14e9313ece743d866889215ec954013e6f310bd1 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 9 Mar 2017 13:28:26 +0200 Subject: [PATCH 54/73] emit !align attributes on stores of operand pairs cc #40373 --- src/librustc_trans/mir/block.rs | 17 ++++++++++++++-- src/librustc_trans/mir/operand.rs | 11 +++++++++-- src/test/codegen/packed.rs | 33 +++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 34d8c6500b926..9d40419d338b8 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -833,8 +833,21 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { self.trans_lvalue(bcx, dest) }; if fn_ret_ty.is_indirect() { - llargs.push(dest.llval); - ReturnDest::Nothing + match dest.alignment { + Alignment::AbiAligned => { + llargs.push(dest.llval); + ReturnDest::Nothing + }, + Alignment::Packed => { + // Currently, MIR code generation does not create calls + // that store directly to fields of packed structs (in + // fact, the calls it creates write only to temps), + // + // If someone changes that, please update this code path + // to create a temporary. + span_bug!(self.mir.span, "can't directly store to unaligned value"); + } + } } else { ReturnDest::Store(dest.llval) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index cb77fcbbff85d..3f29545ecf45a 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -268,10 +268,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.store(base::from_immediate(bcx, s), lldest, align); } OperandValue::Pair(a, b) => { + let f_align = match *bcx.ccx.layout_of(operand.ty) { + Layout::Univariant { ref variant, .. } if variant.packed => { + Some(1) + } + _ => align + }; + let a = base::from_immediate(bcx, a); let b = base::from_immediate(bcx, b); - bcx.store(a, bcx.struct_gep(lldest, 0), align); - bcx.store(b, bcx.struct_gep(lldest, 1), align); + bcx.store(a, bcx.struct_gep(lldest, 0), f_align); + bcx.store(b, bcx.struct_gep(lldest, 1), f_align); } } } diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index db2cd3b41656d..4bd471d05c711 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -27,3 +27,36 @@ pub fn write_pkd(pkd: &mut Packed) -> u32 { pkd.data = 42; result } + +pub struct Array([i32; 8]); +#[repr(packed)] +pub struct BigPacked { + dealign: u8, + data: Array +} + +// CHECK-LABEL: @call_pkd +#[no_mangle] +pub fn call_pkd(f: fn() -> Array) -> BigPacked { +// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array +// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 32, i32 1, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked { dealign: 0, data: f() } +} + +#[repr(packed)] +#[derive(Copy, Clone)] +pub struct PackedPair(u8, u32); + +// CHECK-LABEL: @pkd_pair +#[no_mangle] +pub fn pkd_pair(pair1: &mut PackedPair, pair2: &mut PackedPair) { + // CHECK: [[V1:%[a-z0-9]+]] = load i8, i8* %{{.*}}, align 1 + // CHECK: [[V2:%[a-z0-9]+]] = load i32, i32* %{{.*}}, align 1 + // CHECK: store i8 [[V1]], i8* {{.*}}, align 1 + // CHECK: store i32 [[V2]], i32* {{.*}}, align 1 + *pair2 = *pair1; +} From da6e7c8f3aa97602bf1bf67b8389c7d3ef3fe11e Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 9 Mar 2017 13:31:26 +0100 Subject: [PATCH 55/73] Distinguish the ways `CStr::from_bytes_with_nul` can fail --- src/libstd/ffi/c_str.rs | 46 +++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index bc678fcb8385b..bfb0aa6e1a122 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -154,7 +154,28 @@ pub struct NulError(usize, Vec); /// byte was found too early in the slice provided or one wasn't found at all. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub struct FromBytesWithNulError { _a: () } +pub struct FromBytesWithNulError { + kind: FromBytesWithNulErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum FromBytesWithNulErrorKind { + InteriorNul(usize), + NotNulTerminated, +} + +impl FromBytesWithNulError { + fn interior_nul(pos: usize) -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::InteriorNul(pos), + } + } + fn not_nul_terminated() -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::NotNulTerminated, + } + } +} /// An error returned from `CString::into_string` to indicate that a UTF-8 error /// was encountered during the conversion. @@ -458,14 +479,23 @@ impl From for io::Error { #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for FromBytesWithNulError { fn description(&self) -> &str { - "data provided is not null terminated or contains an interior nul byte" + match self.kind { + FromBytesWithNulErrorKind::InteriorNul(..) => + "data provided contains an interior nul byte", + FromBytesWithNulErrorKind::NotNulTerminated => + "data provided is not nul terminated", + } } } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl fmt::Display for FromBytesWithNulError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) + f.write_str(self.description())?; + if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { + write!(f, " at byte pos {}", pos)?; + } + Ok(()) } } @@ -559,10 +589,14 @@ impl CStr { #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { - if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) { - Err(FromBytesWithNulError { _a: () }) + let nul_pos = memchr::memchr(0, bytes); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != bytes.len() { + return Err(FromBytesWithNulError::interior_nul(nul_pos)); + } + Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) } else { - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Err(FromBytesWithNulError::not_nul_terminated()) } } From 57c989caa1db0b000ff5e9fd2ebb0e6557a3cf30 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 4 Mar 2017 10:07:55 -0500 Subject: [PATCH 56/73] Fix botched member variable rename --- src/tools/build-manifest/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index ceefcc9e0ec46..cbafa9e0bd272 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -218,7 +218,7 @@ impl Builder { self.package("rust-docs", &mut manifest.pkg, TARGETS); self.package("rust-src", &mut manifest.pkg, &["*"]); - if self.channel == "nightly" { + if self.rust_release == "nightly" { self.package("rust-analysis", &mut manifest.pkg, TARGETS); } @@ -271,7 +271,7 @@ impl Builder { target: target.to_string(), }); } - if self.channel == "nightly" { + if self.rust_release == "nightly" { extensions.push(Component { pkg: "rust-analysis".to_string(), target: target.to_string(), From 3e2390ff9cf95d9b35474cfb190b0c88a2b268c0 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 2 Mar 2017 23:39:15 -0500 Subject: [PATCH 57/73] Restore creating the channel-rust-$channel-date.txt files --- src/tools/build-manifest/src/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cbafa9e0bd272..b9c8a84844465 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -183,15 +183,19 @@ impl Builder { let mut manifest = BTreeMap::new(); manifest.insert("manifest-version".to_string(), toml::Value::String(manifest_version)); - manifest.insert("date".to_string(), toml::Value::String(date)); + manifest.insert("date".to_string(), toml::Value::String(date.clone())); manifest.insert("pkg".to_string(), toml::encode(&pkg)); let manifest = toml::Value::Table(manifest).to_string(); let filename = format!("channel-rust-{}.toml", self.rust_release); self.write_manifest(&manifest, &filename); + let filename = format!("channel-rust-{}-date.txt", self.rust_release); + self.write_date_stamp(&date, &filename); + if self.rust_release != "beta" && self.rust_release != "nightly" { self.write_manifest(&manifest, "channel-rust-stable.toml"); + self.write_date_stamp(&date, "channel-rust-stable-date.txt"); } } @@ -411,4 +415,11 @@ impl Builder { self.hash(&dst); self.sign(&dst); } + + fn write_date_stamp(&self, date: &str, name: &str) { + let dst = self.output.join(name); + t!(t!(File::create(&dst)).write_all(date.as_bytes())); + self.hash(&dst); + self.sign(&dst); + } } From 58ff4f67e3a1d099d3c4cb8ccb554ee9fd0a16cd Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 5 Mar 2017 16:11:11 +0100 Subject: [PATCH 58/73] rustbuild: expose LLVM_PARALLEL_LINK_JOBS This allows limiting the number of linker jobs to avoid swapping when linking LLVM with debug info. --- src/bootstrap/config.rs | 3 +++ src/bootstrap/config.toml.example | 8 ++++++++ src/bootstrap/native.rs | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..87c35e0502ce6 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -59,6 +59,7 @@ pub struct Config { pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, pub llvm_targets: Option, + pub llvm_link_jobs: Option, // rust codegen options pub rust_optimize: bool, @@ -179,6 +180,7 @@ struct Llvm { version_check: Option, static_libstdcpp: Option, targets: Option, + link_jobs: Option, } #[derive(RustcDecodable, Default, Clone)] @@ -333,6 +335,7 @@ impl Config { set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); config.llvm_targets = llvm.targets.clone(); + config.llvm_link_jobs = llvm.link_jobs; } if let Some(ref rust) = toml.rust { diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 30763e38a336f..776bd729119e2 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -53,6 +53,14 @@ # Rust team and file an issue if you need assistance in porting! #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +# Cap the number of parallel linker invocations when compiling LLVM. +# This can be useful when building LLVM with debug info, which significantly +# increases the size of binaries and consequently the memory required by +# each linker process. +# If absent or 0, linker invocations are treated like any other job and +# controlled by rustbuild's -j parameter. +#link-jobs = 0 + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 483f45fdd6218..c13235b9c7680 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -115,6 +115,12 @@ pub fn llvm(build: &Build, target: &str) { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if let Some(num_linkers) = build.config.llvm_link_jobs { + if num_linkers > 0 { + cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); + } + } + // http://llvm.org/docs/HowToCrossCompileLLVM.html if target != build.config.build { // FIXME: if the llvm root for the build triple is overridden then we From 8062cfb37294082ad5825a105e47e0b7b50a7269 Mon Sep 17 00:00:00 2001 From: Charlie Fan Date: Thu, 9 Mar 2017 07:50:48 +0000 Subject: [PATCH 59/73] Implement placement-in protocol for and `VecDeque` --- src/libcollections/vec_deque.rs | 185 ++++++++++++++++++++++++---- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/vec_deque.rs | 24 +++- 3 files changed, 184 insertions(+), 26 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 8d42045ff1637..24f57c506304c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -22,7 +22,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; -use core::ops::{Index, IndexMut}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::Shared; use core::slice; @@ -1087,14 +1087,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); self.tail = self.wrap_sub(self.tail, 1); let tail = self.tail; @@ -1117,14 +1110,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_back(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); let head = self.head; self.head = self.wrap_add(self.head, 1); @@ -1257,14 +1243,7 @@ impl VecDeque { #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { assert!(index <= self.len(), "index out of bounds"); - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); // Move the least number of elements in the ring buffer and insert // the given object @@ -1762,6 +1741,69 @@ impl VecDeque { self.truncate(len - del); } } + + // This may panic or abort + #[inline] + fn grow_if_necessary(&mut self) { + if self.is_full() { + let old_cap = self.cap(); + self.buf.double(); + unsafe { + self.handle_cap_increase(old_cap); + } + debug_assert!(!self.is_full()); + } + } + + /// Returns a place for insertion at the back of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_back() <- 3; + /// buf.place_back() <- 4; + /// assert_eq!(&buf, &[3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack { + PlaceBack { vec_deque: self } + } + + /// Returns a place for insertion at the front of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_front() <- 3; + /// buf.place_front() <- 4; + /// assert_eq!(&buf, &[4, 3]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_front(&mut self) -> PlaceFront { + PlaceFront { vec_deque: self } + } } impl VecDeque { @@ -2442,6 +2484,98 @@ impl From> for Vec { } } +/// A place for insertion at the back of a `VecDeque`. +/// +/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceBack<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceBack<'a, T> { + type Place = PlaceBack<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceBack<'a, T> { + fn pointer(&mut self) -> *mut T { + unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceBack<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + let head = self.vec_deque.head; + self.vec_deque.head = self.vec_deque.wrap_add(head, 1); + &mut *(self.vec_deque.ptr().offset(head as isize)) + } +} + +/// A place for insertion at the front of a `VecDeque`. +/// +/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceFront<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceFront<'a, T> { + type Place = PlaceFront<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceFront<'a, T> { + fn pointer(&mut self) -> *mut T { + let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + unsafe { self.vec_deque.ptr().offset(tail as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceFront<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize)) + } +} + #[cfg(test)] mod tests { use test; @@ -2797,4 +2931,5 @@ mod tests { } } } + } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 849d240169169..d97d9b8ab83f6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -32,6 +32,7 @@ extern crate collections; extern crate test; extern crate std_unicode; +extern crate core; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 1541061a19842..f2935c05d4f7a 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; use std::fmt::Debug; -use std::collections::vec_deque::Drain; +use std::collections::vec_deque::{Drain}; use self::Taggy::*; use self::Taggypar::*; @@ -1000,3 +1000,25 @@ fn test_is_empty() { assert!(v.iter_mut().is_empty()); assert!(v.into_iter().is_empty()); } + +#[test] +fn test_placement_in() { + let mut buf: VecDeque = VecDeque::new(); + buf.place_back() <- 1; + buf.place_back() <- 2; + assert_eq!(buf, [1,2]); + + buf.place_front() <- 3; + buf.place_front() <- 4; + assert_eq!(buf, [4,3,1,2]); + + { + let ptr_head = buf.place_front() <- 5; + assert_eq!(*ptr_head, 5); + } + { + let ptr_tail = buf.place_back() <- 6; + assert_eq!(*ptr_tail, 6); + } + assert_eq!(buf, [5,4,3,1,2,6]); +} From 3be02fc41032febc28e22a8a41ec7dc85ca1ce19 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 3 Feb 2017 17:12:58 -0800 Subject: [PATCH 60/73] rustbuild: Use copies instead of hard links The original motivation for hard links was to speed up the various stages of rustbuild, but in the end this is causing problems on Windows (#39504). This commit tweaks the build system to use copies instead of hard links unconditionally to ensure that the files accessed by Windows are always disjoint. Locally this added .3s to a noop build, so it shouldn't be too much of a regression hopefully! --- src/bootstrap/util.rs | 12 ++++++++++-- src/stage0.txt | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 520514f5fc95a..fc63655d79b6c 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -20,6 +20,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; +use filetime::{self, FileTime}; + /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { if target.contains("windows") { @@ -38,12 +40,18 @@ pub fn copy(src: &Path, dst: &Path) { // Attempt to "easy copy" by creating a hard link (symlinks don't work on // windows), but if that fails just fall back to a slow `copy` operation. - let res = fs::hard_link(src, dst); - let res = res.or_else(|_| fs::copy(src, dst).map(|_| ())); + // let res = fs::hard_link(src, dst); + let res = fs::copy(src, dst); if let Err(e) = res { panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) } + let metadata = t!(src.metadata()); + t!(fs::set_permissions(dst, metadata.permissions())); + let atime = FileTime::from_last_access_time(&metadata); + let mtime = FileTime::from_last_modification_time(&metadata); + t!(filetime::set_file_times(dst, atime, mtime)); + } /// Copies the `src` directory recursively to `dst`. Both are assumed to exist diff --git a/src/stage0.txt b/src/stage0.txt index cda9a5a96432b..772029ab0c253 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -13,4 +13,4 @@ # released on `$date` rustc: beta-2017-02-01 -cargo: bfee18f73287687c543bda8c35e4e33808792715 +cargo: 407edef22e894266eb562618cba5ca9757051946 From 6f431491d0c9b96858c05c0ea30edaf44f9e7c12 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Mar 2017 14:44:38 -0800 Subject: [PATCH 61/73] rustc: Prefer loading crates in the sysroot This commit is a random stab in the dark to fix the spurious failures on #39518. The leading theory of the spurious failures on Windows is that the compiler is loading a path in the `deps` folder, passing it to `link.exe`, and then this is racing with Cargo itself updating those paths. This race, however, has a few unique properties: * It's isolated to just libstd. Most crates are never passed to the linker and simultaneously being worked on by Cargo. Cargo's typical execution of the dependency graph never hits this problem. * The crates are already all located in the sysroot in addition to the `deps` folder. This means that the compiler actually has two candidates of crates to load, and it's just arbitrarily rejecting one. Together this means that we shouldn't need to fix this problem "in the large" and we can instead just fix it in this isolated situation (hopefully). To solve this the compiler's been updated to prefer crates from the sysroot to leave Cargo's structure to itself. We'll see if this actually allows the PR to land... --- src/librustc_metadata/locator.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index de465ea92f6b8..a6771083fc34e 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -639,6 +639,34 @@ impl<'a> Context<'a> { lib.display())); continue; } + + // Ok so at this point we've determined that `(lib, kind)` above is + // a candidate crate to load, and that `slot` is either none (this + // is the first crate of its kind) or if some the previous path has + // the exact same hash (e.g. it's the exact same crate). + // + // In principle these two candidate crates are exactly the same so + // we can choose either of them to link. As a stupidly gross hack, + // however, we favor crate in the sysroot. + // + // You can find more info in rust-lang/rust#39518 and various linked + // issues, but the general gist is that during testing libstd the + // compilers has two candidates to choose from: one in the sysroot + // and one in the deps folder. These two crates are the exact same + // crate but if the compiler chooses the one in the deps folder + // it'll cause spurious errors on Windows. + // + // As a result, we favor the sysroot crate here. Note that the + // candidates are all canonicalized, so we canonicalize the sysroot + // as well. + if let Some((ref prev, _)) = ret { + let sysroot = self.sess.sysroot(); + let sysroot = sysroot.canonicalize() + .unwrap_or(sysroot.to_path_buf()); + if prev.starts_with(&sysroot) { + continue + } + } *slot = Some((hash, metadata)); ret = Some((lib, kind)); } From 84d1f6aa82123c2951042aff99e43bdb894d3d81 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 8 Mar 2017 22:17:42 +0200 Subject: [PATCH 62/73] Do not bother creating StorageLive for TyNever Keeps MIR cleaner, `StorageLive(_: !)` makes no sense anyway. --- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/test/mir-opt/issue-38669.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 69b9570200921..42d9ab4d2bf27 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (https://github.com/rust-lang/rust/issues/39283)"); } - if temp_lifetime.is_some() { + if !expr_ty.is_never() && temp_lifetime.is_some() { this.cfg.push(block, Statement { source_info: source_info, kind: StatementKind::StorageLive(temp.clone()) diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 1d452907cf59a..fbbffe8953b38 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -35,7 +35,6 @@ fn main() { // } // // bb2: { -// StorageLive(_6); // _0 = (); // StorageDead(_4); // StorageDead(_1); From 4078b255897d0cdba8a864bd8bb1da92d827a32d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 9 Mar 2017 19:02:59 +0100 Subject: [PATCH 63/73] Clean up rustdoc css --- src/librustdoc/html/static/rustdoc.css | 33 ++---- src/librustdoc/html/static/styles/main.css | 114 +++++++++++++++------ 2 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 6bd9cf6620b0e..4047f6045bcc5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -377,13 +377,13 @@ h4 > code, h3 > code, .invisible > code { .content .method .where, .content .fn .where, .content .where.fmt-newline { - display: block; + display: block; } /* Bit of whitespace to indent it */ .content .method .where::before, .content .fn .where::before, .content .where.fmt-newline::before { - content: ' '; + content: ' '; } .content .methods > div { margin-left: 40px; } @@ -506,17 +506,15 @@ body.blur > :not(#help) { } #help > div { flex: 0 0 auto; - background: #e9e9e9; box-shadow: 0 0 6px rgba(0,0,0,.2); width: 550px; height: 330px; - border: 1px solid #bfbfbf; + border: 1px solid; } #help dt { float: left; border-radius: 4px; - border: 1px solid #bfbfbf; - background: #fff; + border: 1px solid; width: 23px; text-align: center; clear: left; @@ -567,7 +565,6 @@ body.blur > :not(#help) { .since { font-weight: normal; font-size: initial; - color: grey; position: absolute; right: 0; top: 0; @@ -589,24 +586,12 @@ td.summary-column { padding-right: 0px; } -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .kw { color: #8959A8; } -pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } -pre.rust .number, pre.rust .string { color: #718C00; } -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } -pre.rust .lifetime { color: #B76514; } pre.rust .question-mark { - color: #ff9011; font-weight: bold; } pre.rust { position: relative; } a.test-arrow { - background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; padding: 5px 10px 5px 10px; @@ -616,7 +601,6 @@ a.test-arrow { right: 5px; } a.test-arrow:hover{ - background-color: #4e8bca; text-decoration: none; } @@ -660,10 +644,6 @@ a.test-arrow:hover{ text-align: center; } -.toggle-label { - color: #999; -} - .ghost { display: none; } @@ -719,8 +699,7 @@ span.since { } :target > code { - background: #FDFFD3; - opacity: 1; + opacity: 1; } /* Media Queries */ @@ -793,4 +772,4 @@ span.since { nav.sub, .content .out-of-band, .collapse-toggle { display: none; } -} +} \ No newline at end of file diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index f1e81900d1eec..40561597e93e0 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -13,28 +13,36 @@ /* General structure and fonts */ body { - background-color: white; - color: black; + background-color: white; + color: black; } h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - color: black; + color: black; } h1.fqn { - border-bottom-color: #D5D5D5; + border-bottom-color: #D5D5D5; } h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - border-bottom-color: #DDDDDD; + border-bottom-color: #DDDDDD; } .in-band { - background-color: white; + background-color: white; } .docblock code, .docblock-short code { - background-color: #F5F5F5; + background-color: #F5F5F5; } pre { - background-color: #F5F5F5; + background-color: #F5F5F5; +} + +.sidebar { + background-color: #F1F1F1; +} + +.sidebar .current { + background-color: #fff; } .sidebar { @@ -46,24 +54,24 @@ pre { } .sidebar .location { - border-color: #000; - background-color: #fff; - color: #333; + border-color: #000; + background-color: #fff; + color: #333; } .block a:hover { - background: #F5F5F5; + background: #F5F5F5; } .line-numbers span { color: #c67e2d; } .line-numbers .line-highlighted { - background-color: #f6fdb0 !important; + background-color: #f6fdb0 !important; } :target { background: #FDFFD3; } .content .highlighted { - color: #000 !important; - background-color: #ccc; + color: #000 !important; + background-color: #ccc; } .content .highlighted a, .content .highlighted span { color: #000 !important; } .content .highlighted.trait { background-color: #fece7e; } @@ -76,21 +84,21 @@ pre { .content .highlighted.type { background-color: #c6afb3; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { - border-bottom-color: #DDD; + border-bottom-color: #DDD; } .docblock table { - border-color: #ddd; + border-color: #ddd; } .docblock table td { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .docblock table th { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .content span.primitive, .content a.primitive, .block a.current.primitive { color: #39a7bf; } @@ -105,34 +113,78 @@ pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } nav { - border-bottom-color: #e0e0e0; + border-bottom-color: #e0e0e0; } nav.main .current { - border-top-color: #000; - border-bottom-color: #000; + border-top-color: #000; + border-bottom-color: #000; } nav.main .separator { - border: 1px solid #000; + border: 1px solid #000; } a { - color: #000; + color: #000; } .docblock a, .docblock-short a, .stability a { - color: #3873AD; + color: #3873AD; } a.test-arrow { - color: #f5f5f5; + color: #f5f5f5; } .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } .search-input { - color: #555; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; - background-color: white; + color: #555; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; + background-color: white; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } + +#help > div { + background: #e9e9e9; + border-color: #bfbfbf;; +} + +#help dt { + border-color: #bfbfbf; + background: #fff; +} + +.since { + color: grey; +} + +.line-numbers :target { background-color: transparent; } + +/* Code highlighting */ +pre.rust .kw { color: #8959A8; } +pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } +pre.rust .number, pre.rust .string { color: #718C00; } +pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, +pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } +pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } +pre.rust .lifetime { color: #B76514; } +pre.rust .question-mark { + color: #ff9011; +} + +a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); +} + +a.test-arrow:hover{ + background-color: #4e8bca; +} + +.toggle-label { + color: #999; +} + +:target > code { + background: #FDFFD3; +} \ No newline at end of file From cfb41aedd3a5e21c169a0a91dfd600e8e370d291 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 9 Mar 2017 05:54:52 +0200 Subject: [PATCH 64/73] Use subtyping on the target of unsizing coercions. --- src/librustc_typeck/check/coercion.rs | 28 +++++++---- .../object-lifetime-default-elision.rs | 2 +- .../object-lifetime-default-from-box-error.rs | 4 +- ...ions-close-over-type-parameter-multiple.rs | 2 +- .../regions-proc-bound-capture.rs | 2 +- .../regions-trait-object-subtyping.rs | 4 +- .../variance-contravariant-arg-object.rs | 4 +- .../variance-covariant-arg-object.rs | 4 +- .../variance-invariant-arg-object.rs | 4 +- src/test/run-pass/coerce-unsize-subtype.rs | 48 +++++++++++++++++++ 10 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 src/test/run-pass/coerce-unsize-subtype.rs diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 651058728816e..c43291557f7fa 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -453,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => (source, None), }; - let source = source.adjust_for_autoref(self.tcx, reborrow); + let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); + + let adjust = Adjust::DerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: true, + }; + + // Setup either a subtyping or a LUB relationship between + // the `CoerceUnsized` target type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let coerce_target = self.next_ty_var(origin); + let mut coercion = self.unify_and(coerce_target, target, adjust)?; let mut selcx = traits::SelectionContext::new(self); // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut obligations = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx - .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); + .predicate_for_trait_def(cause, coerce_unsized_did, 0, + coerce_source, &[coerce_target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -475,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - obligations.push(obligation); + coercion.obligations.push(obligation); continue; } }; @@ -503,11 +517,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - success(Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, - }, target, obligations) + Ok(coercion) } fn coerce_from_safe_fn(&self, diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index fb75b9aa1dd94..e37b6a2bb9c99 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR lifetime bound not satisfied + //~^ ERROR cannot infer //~| ERROR cannot infer } diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index dd94dfe1e0823..c0dd5200f6cb4 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR lifetime bound not satisfied + ss.r //~ ERROR cannot infer an appropriate lifetime } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR lifetime bound not satisfied + ss.r = b; //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index c5cf43e355d5a..ad6c5a31bbbd3 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR lifetime bound not satisfied + box v as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index fb726e31af586..17fd55b031b61 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime + Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index b4e527972e476..e8ada6a175571 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR lifetime bound not satisfied - //~^ ERROR cannot infer + x //~ ERROR cannot infer an appropriate lifetime + //~^ ERROR cannot infer an appropriate lifetime } struct Wrapper(T); diff --git a/src/test/compile-fail/variance-contravariant-arg-object.rs b/src/test/compile-fail/variance-contravariant-arg-object.rs index 1795ac95358d7..d3bf92e85f411 100644 --- a/src/test/compile-fail/variance-contravariant-arg-object.rs +++ b/src/test/compile-fail/variance-contravariant-arg-object.rs @@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) @@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box>) where 'max : 'min { // Previously OK: - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-covariant-arg-object.rs b/src/test/compile-fail/variance-covariant-arg-object.rs index ad059a467f570..0e94e35df2839 100644 --- a/src/test/compile-fail/variance-covariant-arg-object.rs +++ b/src/test/compile-fail/variance-covariant-arg-object.rs @@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) where 'max : 'min { // Previously OK, now an error as traits are invariant. - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-invariant-arg-object.rs b/src/test/compile-fail/variance-invariant-arg-object.rs index 9edb510b826a1..aa3e06c015d50 100644 --- a/src/test/compile-fail/variance-invariant-arg-object.rs +++ b/src/test/compile-fail/variance-invariant-arg-object.rs @@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs new file mode 100644 index 0000000000000..b19708f5a8931 --- /dev/null +++ b/src/test/run-pass/coerce-unsize-subtype.rs @@ -0,0 +1,48 @@ +// Copyright 2017 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. + +// pretty-expanded FIXME #23616 + +use std::rc::Rc; + +fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {} + +// The two arguments are a subtype of their LUB, after coercion. +fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) { + lub_short(xs, ys); +} + +// The argument coerces to a subtype of the return type. +fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] { + xs +} + +// Rc is covariant over T just like &T. +fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> { + xs +} + +// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]` +// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`), +// regardless of the order they appear (in if-else/match/array). +fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]` +// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but +// rather the `&'b [&'a T]` LUB. +fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +fn main() {} From b95b5db163adfe24117aa25e42a775c7b5b91dc5 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 9 Mar 2017 22:11:23 +0100 Subject: [PATCH 65/73] update gdbr tests gdb will now reliably detect the lanugage as rust even before any code is run. --- src/test/debuginfo/c-style-enum.rs | 21 ++++++++++++++------- src/test/debuginfo/limited-debuginfo.rs | 12 ++++++++---- src/test/debuginfo/simple-struct.rs | 3 --- src/test/debuginfo/simple-tuple.rs | 3 --- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 2452c18f54347..900b0829530f3 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -15,31 +15,38 @@ // === GDB TESTS =================================================================================== -// gdb-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbg-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbr-command:print c_style_enum::SINGLE_VARIANT // gdbg-check:$1 = TheOnlyVariant // gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant -// gdb-command:print 'c_style_enum::AUTO_ONE' +// gdbg-command:print 'c_style_enum::AUTO_ONE' +// gdbr-command:print c_style_enum::AUTO_ONE // gdbg-check:$2 = One // gdbr-check:$2 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_TWO' +// gdbg-command:print 'c_style_enum::AUTO_TWO' +// gdbr-command:print c_style_enum::AUTO_TWO // gdbg-check:$3 = One // gdbr-check:$3 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_THREE' +// gdbg-command:print 'c_style_enum::AUTO_THREE' +// gdbr-command:print c_style_enum::AUTO_THREE // gdbg-check:$4 = One // gdbr-check:$4 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::MANUAL_ONE' +// gdbg-command:print 'c_style_enum::MANUAL_ONE' +// gdbr-command:print c_style_enum::MANUAL_ONE // gdbg-check:$5 = OneHundred // gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_TWO' +// gdbg-command:print 'c_style_enum::MANUAL_TWO' +// gdbr-command:print c_style_enum::MANUAL_TWO // gdbg-check:$6 = OneHundred // gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_THREE' +// gdbg-command:print 'c_style_enum::MANUAL_THREE' +// gdbr-command:print c_style_enum::MANUAL_THREE // gdbg-check:$7 = OneHundred // gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred diff --git a/src/test/debuginfo/limited-debuginfo.rs b/src/test/debuginfo/limited-debuginfo.rs index 3d21def3953b8..e8c3597b8c8dd 100644 --- a/src/test/debuginfo/limited-debuginfo.rs +++ b/src/test/debuginfo/limited-debuginfo.rs @@ -15,10 +15,14 @@ // Make sure functions have proper names // gdb-command:info functions -// gdb-check:[...]void[...]main([...]); -// gdb-check:[...]void[...]some_function([...]); -// gdb-check:[...]void[...]some_other_function([...]); -// gdb-check:[...]void[...]zzz([...]); +// gdbg-check:[...]void[...]main([...]); +// gdbr-check:fn limited_debuginfo::main(); +// gdbg-check:[...]void[...]some_function([...]); +// gdbr-check:fn limited_debuginfo::some_function(); +// gdbg-check:[...]void[...]some_other_function([...]); +// gdbr-check:fn limited_debuginfo::some_other_function(); +// gdbg-check:[...]void[...]zzz([...]); +// gdbr-check:fn limited_debuginfo::zzz(); // gdb-command:run diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index 4956313ad2214..ae05bafe5adaa 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print 'simple_struct::NO_PADDING_16' // gdbr-command:print simple_struct::NO_PADDING_16 // gdbg-check:$1 = {x = 1000, y = -1001} diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 354a2c26cb36d..b3c2704115095 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print/d 'simple_tuple::NO_PADDING_8' // gdbr-command:print simple_tuple::NO_PADDING_8 // gdbg-check:$1 = {__0 = -50, __1 = 50} From 7f19f1f91ba7d082b03f36716909eae39c24ddb3 Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Fri, 10 Mar 2017 02:51:47 +0300 Subject: [PATCH 66/73] fix #40294 obligation cause.body_id is not always a NodeExpr --- src/librustc/traits/error_reporting.rs | 21 ++++++++++------- .../issue-38812-2.rs | 0 .../issue-38812-2.stderr | 0 .../{codemap_tests => resolve}/issue-38812.rs | 0 .../issue-38812.stderr | 0 src/test/ui/resolve/issue-40294.rs | 23 +++++++++++++++++++ src/test/ui/resolve/issue-40294.stderr | 15 ++++++++++++ 7 files changed, 51 insertions(+), 8 deletions(-) rename src/test/ui/{codemap_tests => resolve}/issue-38812-2.rs (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812-2.stderr (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812.rs (100%) rename src/test/ui/{codemap_tests => resolve}/issue-38812.stderr (100%) create mode 100644 src/test/ui/resolve/issue-40294.rs create mode 100644 src/test/ui/resolve/issue-40294.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 99db5f9b62435..0e5c786cd8dcf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -23,11 +23,17 @@ use super::{ ObjectSafetyViolation, }; +use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; +use hir::{intravisit, Local, Pat}; +use hir::intravisit::{Visitor, NestedVisitorMap}; +use hir::map::NodeExpr; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; +use std::fmt; +use syntax::ast; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; @@ -35,12 +41,8 @@ use ty::fold::TypeFolder; use ty::subst::Subst; use util::nodemap::{FxHashMap, FxHashSet}; -use std::fmt; -use syntax::ast; -use hir::{intravisit, Local, Pat}; -use hir::intravisit::{Visitor, NestedVisitorMap}; use syntax_pos::{DUMMY_SP, Span}; -use errors::DiagnosticBuilder; + #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { @@ -848,15 +850,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); - let expr = self.tcx.hir.expect_expr(cause.body_id); - let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, found_pattern: None, }; - local_visitor.visit_expr(expr); + // #40294: cause.body_id can also be a fn declaration. + // Currently, if it's anything other than NodeExpr, we just ignore it + match self.tcx.hir.find(cause.body_id) { + Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), + _ => () + } if let Some(pattern) = local_visitor.found_pattern { let pattern_span = pattern.span; diff --git a/src/test/ui/codemap_tests/issue-38812-2.rs b/src/test/ui/resolve/issue-38812-2.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.rs rename to src/test/ui/resolve/issue-38812-2.rs diff --git a/src/test/ui/codemap_tests/issue-38812-2.stderr b/src/test/ui/resolve/issue-38812-2.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.stderr rename to src/test/ui/resolve/issue-38812-2.stderr diff --git a/src/test/ui/codemap_tests/issue-38812.rs b/src/test/ui/resolve/issue-38812.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.rs rename to src/test/ui/resolve/issue-38812.rs diff --git a/src/test/ui/codemap_tests/issue-38812.stderr b/src/test/ui/resolve/issue-38812.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.stderr rename to src/test/ui/resolve/issue-38812.stderr diff --git a/src/test/ui/resolve/issue-40294.rs b/src/test/ui/resolve/issue-40294.rs new file mode 100644 index 0000000000000..d30a425d1099b --- /dev/null +++ b/src/test/ui/resolve/issue-40294.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +trait Foo: Sized { + fn foo(self); +} + +fn foo<'a,'b,T>(x: &'a T, y: &'b T) + where &'a T : Foo, + &'b T : Foo +{ + x.foo(); + y.foo(); +} + +fn main() { } diff --git a/src/test/ui/resolve/issue-40294.stderr b/src/test/ui/resolve/issue-40294.stderr new file mode 100644 index 0000000000000..5c388c9d602ea --- /dev/null +++ b/src/test/ui/resolve/issue-40294.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/issue-40294.rs:15:1 + | +15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T) + | _^ starting here... +16 | | where &'a T : Foo, +17 | | &'b T : Foo +18 | | { +19 | | x.foo(); +20 | | y.foo(); +21 | | } + | |_^ ...ending here: cannot infer type for `&'a T` + +error: aborting due to previous error + From d708a4072a9fa35be3cb6a1e74557925507ba606 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:19:22 +1300 Subject: [PATCH 67/73] Add extra methods to IndexVec and implement TypeFoldable for it Adds `get`/`get_mut` accessors and `drain`/`drain_enumerated` iterators to IndexVec. Implements TypeFoldable for IndexVec. --- src/librustc/ty/structural_impls.rs | 11 ++++++++++ src/librustc_data_structures/indexed_vec.rs | 23 +++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 3 files changed, 35 insertions(+) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 48f6fcd11b8ac..49824e8a738d7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -12,6 +12,7 @@ use infer::type_variable; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::rc::Rc; use syntax::abi; @@ -834,3 +835,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun self.expected.visit_with(visitor) || self.found.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + self.iter().map(|x| x.fold_with(folder)).collect() + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 00cea9cbdf6b7..3f478d7c165d1 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; @@ -145,6 +146,18 @@ impl IndexVec { self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) } + #[inline] + pub fn drain<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range) + } + + #[inline] + pub fn drain_enumerated<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + } + #[inline] pub fn last(&self) -> Option { self.len().checked_sub(1).map(I::new) @@ -164,6 +177,16 @@ impl IndexVec { pub fn truncate(&mut self, a: usize) { self.raw.truncate(a) } + + #[inline] + pub fn get(&self, index: I) -> Option<&T> { + self.raw.get(index.index()) + } + + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut T> { + self.raw.get_mut(index.index()) + } } impl Index for IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 3dce4398f3b91..f278325ebec74 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -38,6 +38,7 @@ #![feature(associated_consts)] #![feature(unsize)] #![feature(i128_type)] +#![feature(conservative_impl_trait)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] From 540b52e145afb09f1784c6094220a7f8268f09ed Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:23:09 +1300 Subject: [PATCH 68/73] Fix recursion depth counting in `layout` --- src/librustc/ty/util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index be1582066e393..a81c3a177f885 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -654,11 +654,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(self, infcx)?; + let layout = Layout::compute_uncached(self, infcx); + tcx.layout_depth.set(depth); + let layout = layout?; if can_cache { tcx.layout_cache.borrow_mut().insert(self, layout); } - tcx.layout_depth.set(depth); Ok(layout) } From 71d0d921c2f38a13ae9c538225f6181f77d604b3 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 8 Feb 2017 22:24:49 +1300 Subject: [PATCH 69/73] Initial implementation of inlining for MIR Fairly basic implementation of inlining for MIR. Uses conservative heuristics for inlining. --- src/librustc/mir/mod.rs | 348 +++++++++- src/librustc/ty/mod.rs | 14 + src/librustc_driver/driver.rs | 1 + src/librustc_mir/callgraph.rs | 252 ++++++++ src/librustc_mir/lib.rs | 3 +- src/librustc_mir/transform/inline.rs | 842 +++++++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 1 + src/librustc_mir/transform/simplify.rs | 18 +- 8 files changed, 1473 insertions(+), 6 deletions(-) create mode 100644 src/librustc_mir/callgraph.rs create mode 100644 src/librustc_mir/transform/inline.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ed72fe1801663..fea576f706780 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -19,6 +19,7 @@ use hir::def::CtorKind; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use util::ppaux; use rustc_back::slice; use hir::InlineAsm; @@ -63,8 +64,7 @@ macro_rules! newtype_index { } /// Lowered representation of a single function. -// Do not implement clone for Mir, which can be accidently done and kind of expensive. -#[derive(RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. @@ -1333,3 +1333,347 @@ impl Location { } } } + + +/* + * TypeFoldable implementations for MIR types + */ + +impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Mir { + basic_blocks: self.basic_blocks.fold_with(folder), + visibility_scopes: self.visibility_scopes.clone(), + promoted: self.promoted.fold_with(folder), + return_ty: self.return_ty.fold_with(folder), + local_decls: self.local_decls.fold_with(folder), + arg_count: self.arg_count, + upvar_decls: self.upvar_decls.clone(), + spread_arg: self.spread_arg, + span: self.span, + cache: cache::Cache::new() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.basic_blocks.visit_with(visitor) || + self.promoted.visit_with(visitor) || + self.return_ty.visit_with(visitor) || + self.local_decls.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + LocalDecl { + ty: self.ty.fold_with(folder), + ..self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + BasicBlockData { + statements: self.statements.fold_with(folder), + terminator: self.terminator.fold_with(folder), + is_cleanup: self.is_cleanup + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.statements.visit_with(visitor) || self.terminator.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::StatementKind::*; + + let kind = match self.kind { + Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)), + SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant { + lvalue: lvalue.fold_with(folder), + variant_index: variant_index + }, + StorageLive(ref lval) => StorageLive(lval.fold_with(folder)), + StorageDead(ref lval) => StorageDead(lval.fold_with(folder)), + InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm { + asm: asm.clone(), + outputs: outputs.fold_with(folder), + inputs: inputs.fold_with(folder) + }, + Nop => Nop, + }; + Statement { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::StatementKind::*; + + match self.kind { + Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) } + SetDiscriminant { ref lvalue, .. } | + StorageLive(ref lvalue) | + StorageDead(ref lvalue) => lvalue.visit_with(visitor), + InlineAsm { ref outputs, ref inputs, .. } => + outputs.visit_with(visitor) || inputs.visit_with(visitor), + Nop => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::TerminatorKind::*; + + let kind = match self.kind { + Goto { target } => Goto { target: target }, + SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + discr: discr.fold_with(folder), + switch_ty: switch_ty.fold_with(folder), + values: values.clone(), + targets: targets.clone() + }, + Drop { ref location, target, unwind } => Drop { + location: location.fold_with(folder), + target: target, + unwind: unwind + }, + DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { + location: location.fold_with(folder), + value: value.fold_with(folder), + target: target, + unwind: unwind + }, + Call { ref func, ref args, ref destination, cleanup } => { + let dest = destination.as_ref().map(|&(ref loc, dest)| { + (loc.fold_with(folder), dest) + }); + + Call { + func: func.fold_with(folder), + args: args.fold_with(folder), + destination: dest, + cleanup: cleanup + } + }, + Assert { ref cond, expected, ref msg, target, cleanup } => { + let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + AssertMessage::BoundsCheck { + len: len.fold_with(folder), + index: index.fold_with(folder), + } + } else { + msg.clone() + }; + Assert { + cond: cond.fold_with(folder), + expected: expected, + msg: msg, + target: target, + cleanup: cleanup + } + }, + Resume => Resume, + Return => Return, + Unreachable => Unreachable, + }; + Terminator { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::TerminatorKind::*; + + match self.kind { + SwitchInt { ref discr, switch_ty, .. } => + discr.visit_with(visitor) || switch_ty.visit_with(visitor), + Drop { ref location, ..} => location.visit_with(visitor), + DropAndReplace { ref location, ref value, ..} => + location.visit_with(visitor) || value.visit_with(visitor), + Call { ref func, ref args, ref destination, .. } => { + let dest = if let Some((ref loc, _)) = *destination { + loc.visit_with(visitor) + } else { false }; + dest || func.visit_with(visitor) || args.visit_with(visitor) + }, + Assert { ref cond, ref msg, .. } => { + if cond.visit_with(visitor) { + if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + len.visit_with(visitor) || index.visit_with(visitor) + } else { + false + } + } else { + false + } + }, + Goto { .. } | + Resume | + Return | + Unreachable => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Lvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match self { + &Lvalue::Projection(ref p) => Lvalue::Projection(p.fold_with(folder)), + _ => self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + if let &Lvalue::Projection(ref p) = self { + p.visit_with(visitor) + } else { + false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::Rvalue::*; + match *self { + Use(ref op) => Use(op.fold_with(folder)), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Ref(region, bk, ref lval) => Ref(region.fold_with(folder), bk, lval.fold_with(folder)), + Len(ref lval) => Len(lval.fold_with(folder)), + Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, ref rhs, ref lhs) => + BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + CheckedBinaryOp(op, ref rhs, ref lhs) => + CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(ref lval) => Discriminant(lval.fold_with(folder)), + Box(ty) => Box(ty.fold_with(folder)), + Aggregate(ref kind, ref fields) => { + let kind = match *kind { + AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), + AggregateKind::Tuple => AggregateKind::Tuple, + AggregateKind::Adt(def, v, substs, n) => + AggregateKind::Adt(def, v, substs.fold_with(folder), n), + AggregateKind::Closure(id, substs) => + AggregateKind::Closure(id, substs.fold_with(folder)) + }; + Aggregate(kind, fields.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::Rvalue::*; + match *self { + Use(ref op) => op.visit_with(visitor), + Repeat(ref op, _) => op.visit_with(visitor), + Ref(region, _, ref lval) => region.visit_with(visitor) || lval.visit_with(visitor), + Len(ref lval) => lval.visit_with(visitor), + Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), + BinaryOp(_, ref rhs, ref lhs) | + CheckedBinaryOp(_, ref rhs, ref lhs) => + rhs.visit_with(visitor) || lhs.visit_with(visitor), + UnaryOp(_, ref val) => val.visit_with(visitor), + Discriminant(ref lval) => lval.visit_with(visitor), + Box(ty) => ty.visit_with(visitor), + Aggregate(ref kind, ref fields) => { + (match *kind { + AggregateKind::Array(ty) => ty.visit_with(visitor), + AggregateKind::Tuple => false, + AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), + AggregateKind::Closure(_, substs) => substs.visit_with(visitor) + }) || fields.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)), + Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Operand::Consume(ref lval) => lval.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor) + } + } +} + +impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V> + where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx> +{ + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::ProjectionElem::*; + + let base = self.base.fold_with(folder); + let elem = match self.elem { + Deref => Deref, + Field(f, ty) => Field(f, ty.fold_with(folder)), + Index(ref v) => Index(v.fold_with(folder)), + ref elem => elem.clone() + }; + + Projection { + base: base, + elem: elem + } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + use mir::ProjectionElem::*; + + self.base.visit_with(visitor) || + match self.elem { + Field(_, ty) => ty.visit_with(visitor), + Index(ref v) => v.visit_with(visitor), + _ => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Constant { + span: self.span.clone(), + ty: self.ty.fold_with(folder), + literal: self.literal.fold_with(folder) + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) || self.literal.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Literal::Item { def_id, substs } => Literal::Item { + def_id: def_id, + substs: substs.fold_with(folder) + }, + _ => self.clone() + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Literal::Item { substs, .. } => substs.visit_with(visitor), + _ => false + } + } +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be04b0e6577f0..3c37c7353d683 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2302,6 +2302,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::mir::get(self, DUMMY_SP, did).borrow() } + /// Given the DefId of an item, returns its MIR, borrowed immutably. + /// Returns None if there is no MIR for the DefId + pub fn maybe_item_mir(self, did: DefId) -> Option>> { + if did.is_local() && !self.maps.mir.borrow().contains_key(&did) { + return None; + } + + if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) { + return None; + } + + Some(self.item_mir(did)) + } + /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..7790a84da4944 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1048,6 +1048,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(box mir::transform::inline::Inline); passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs new file mode 100644 index 0000000000000..69416289d8e26 --- /dev/null +++ b/src/librustc_mir/callgraph.rs @@ -0,0 +1,252 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! MIR-based callgraph. +//! +//! This only considers direct calls + +use rustc::hir::def_id::DefId; +use rustc_data_structures::graph; + +use rustc::mir::*; +use rustc::mir::visit::*; + +use rustc::ty; + +use rustc::util::nodemap::DefIdMap; + +pub struct CallGraph { + node_map: DefIdMap, + graph: graph::Graph +} + +impl CallGraph { + // FIXME: allow for construction of a callgraph that inspects + // cross-crate MIRs if available. + pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph { + let def_ids = tcx.maps.mir.borrow().keys(); + + let mut callgraph = CallGraph { + node_map: DefIdMap(), + graph: graph::Graph::new() + }; + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let idx = callgraph.add_node(def_id); + + let mut call_visitor = CallVisitor { + caller: idx, + graph: &mut callgraph + }; + + let mir = tcx.item_mir(def_id); + call_visitor.visit_mir(&mir); + } + + callgraph + } + + // Iterate over the strongly-connected components of the graph + pub fn scc_iter(&self) -> SCCIterator { + SCCIterator::new(&self.graph) + } + + // Get the def_id for the given graph node + pub fn def_id(&self, node: graph::NodeIndex) -> DefId { + *self.graph.node_data(node) + } + + fn add_node(&mut self, id: DefId) -> graph::NodeIndex { + let graph = &mut self.graph; + *self.node_map.entry(id).or_insert_with(|| { + graph.add_node(id) + }) + } +} + +struct CallVisitor<'a> { + caller: graph::NodeIndex, + graph: &'a mut CallGraph +} + +impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> { + fn visit_terminator_kind(&mut self, _block: BasicBlock, + kind: &TerminatorKind<'tcx>, _loc: Location) { + if let TerminatorKind::Call { + func: Operand::Constant(ref f) + , .. } = *kind { + if let ty::TyFnDef(def_id, _, _) = f.ty.sty { + let callee = self.graph.add_node(def_id); + self.graph.graph.add_edge(self.caller, callee, ()); + } + } + } +} + +struct StackElement<'g> { + node: graph::NodeIndex, + lowlink: usize, + children: graph::AdjacentTargets<'g, DefId, ()> +} + +/** + * Iterator over strongly-connected-components using Tarjan's algorithm[1] + * + * [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + */ +pub struct SCCIterator<'g> { + graph: &'g graph::Graph, + index: usize, + node_indices: Vec>, + scc_stack: Vec, + current_scc: Vec, + visit_stack: Vec>, +} + +impl<'g> SCCIterator<'g> { + pub fn new(graph: &'g graph::Graph) -> SCCIterator<'g> { + if graph.len_nodes() == 0 { + return SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::new(), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + } + + let first = graph::NodeIndex(0); + + SCCIterator::with_entry(graph, first) + } + + pub fn with_entry(graph: &'g graph::Graph, + entry: graph::NodeIndex) -> SCCIterator<'g> { + let mut iter = SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::with_capacity(graph.len_nodes()), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + + iter.visit_one(entry); + + iter + } + + fn get_next(&mut self) { + self.current_scc.clear(); + + while !self.visit_stack.is_empty() { + self.visit_children(); + + let node = self.visit_stack.pop().unwrap(); + + if let Some(last) = self.visit_stack.last_mut() { + if last.lowlink > node.lowlink { + last.lowlink = node.lowlink; + } + } + + debug!("TarjanSCC: Popped node {:?} : lowlink = {:?}; index = {:?}", + node.node, node.lowlink, self.node_index(node.node).unwrap()); + + if node.lowlink != self.node_index(node.node).unwrap() { + continue; + } + + loop { + let n = self.scc_stack.pop().unwrap(); + self.current_scc.push(n); + self.set_node_index(n, !0); + if n == node.node { return; } + } + } + } + + fn visit_one(&mut self, node: graph::NodeIndex) { + self.index += 1; + let idx = self.index; + self.set_node_index(node, idx); + self.scc_stack.push(node); + self.visit_stack.push(StackElement { + node: node, + lowlink: self.index, + children: self.graph.successor_nodes(node) + }); + debug!("TarjanSCC: Node {:?} : index = {:?}", node, idx); + } + + fn visit_children(&mut self) { + while let Some(child) = self.visit_stack.last_mut().unwrap().children.next() { + if let Some(child_num) = self.node_index(child) { + let cur = self.visit_stack.last_mut().unwrap(); + if cur.lowlink > child_num { + cur.lowlink = child_num; + } + } else { + self.visit_one(child); + } + } + } + + fn node_index(&self, node: graph::NodeIndex) -> Option { + self.node_indices.get(node.node_id()).and_then(|&idx| idx) + } + + fn set_node_index(&mut self, node: graph::NodeIndex, idx: usize) { + let i = node.node_id(); + if i >= self.node_indices.len() { + self.node_indices.resize(i + 1, None); + } + self.node_indices[i] = Some(idx); + } +} + +impl<'g> Iterator for SCCIterator<'g> { + type Item = Vec; + + fn next(&mut self) -> Option> { + self.get_next(); + + if self.current_scc.is_empty() { + // Try a new root for the next SCC, if the node_indices + // map is doesn't contain all nodes, use the smallest one + // with no entry, otherwise find the first empty node. + // + // FIXME: This should probably use a set of precomputed + // roots instead + if self.node_indices.len() < self.graph.len_nodes() { + let idx = graph::NodeIndex(self.node_indices.len()); + self.visit_one(idx); + } else { + for idx in 0..self.node_indices.len() { + if self.node_indices[idx].is_none() { + let idx = graph::NodeIndex(idx); + self.visit_one(idx); + break; + } + } + } + self.get_next(); + } + + if self.current_scc.is_empty() { + None + } else { + Some(self.current_scc.clone()) + } + } +} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index a97495a0ebcc4..f21f1881c832e 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,6 +46,7 @@ extern crate rustc_const_eval; pub mod diagnostics; pub mod build; +pub mod callgraph; pub mod def_use; pub mod graphviz; mod hair; @@ -58,4 +59,4 @@ use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { mir_map::provide(providers); transform::qualify_consts::provide(providers); -} +} \ No newline at end of file diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs new file mode 100644 index 0000000000000..4b8e2bf49b9ee --- /dev/null +++ b/src/librustc_mir/transform/inline.rs @@ -0,0 +1,842 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Inlining pass for MIR functions + +use rustc::hir::def_id::DefId; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::graph; + +use rustc::dep_graph::DepNode; +use rustc::mir::*; +use rustc::mir::transform::{MirMapPass, MirPassHook, MirSource, Pass}; +use rustc::mir::visit::*; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Subst,Substs}; +use rustc::util::nodemap::{DefIdSet}; + +use super::simplify::{remove_dead_blocks, CfgSimplifier}; + +use syntax::attr; +use syntax::abi::Abi; + +use callgraph; + +const DEFAULT_THRESHOLD: usize = 50; +const HINT_THRESHOLD: usize = 100; + +const INSTR_COST: usize = 5; +const CALL_PENALTY: usize = 25; + +const UNKNOWN_SIZE_COST: usize = 10; + +pub struct Inline; + +impl<'tcx> MirMapPass<'tcx> for Inline { + fn run_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) { + + //if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + + let _ignore = tcx.dep_graph.in_ignore(); + + let callgraph = callgraph::CallGraph::build(tcx); + + let mut inliner = Inliner { + tcx: tcx, + }; + + let def_ids = tcx.maps.mir.borrow().keys(); + for &def_id in &def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = if let Some(mir) = tcx.maps.mir.borrow().get(&def_id) { + mir.borrow_mut() + } else { + continue; + }; + + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, false); + } + } + + for scc in callgraph.scc_iter() { + inliner.inline_scc(&callgraph, &scc); + } + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = tcx.maps.mir.borrow()[&def_id].borrow_mut(); + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, true); + } + } + } +} + +impl<'tcx> Pass for Inline { } + +struct Inliner<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +#[derive(Copy, Clone)] +struct CallSite<'tcx> { + caller: DefId, + callee: DefId, + substs: &'tcx Substs<'tcx>, + bb: BasicBlock, + location: SourceInfo, +} + +impl<'a, 'tcx> Inliner<'a, 'tcx> { + fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool { + let mut callsites = Vec::new(); + let mut in_scc = DefIdSet(); + + let mut inlined_into = DefIdSet(); + + for &node in scc { + let def_id = callgraph.def_id(node); + + // Don't inspect functions from other crates + let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { + id + } else { + continue; + }; + let src = MirSource::from_node(self.tcx, id); + if let MirSource::Fn(_) = src { + if let Some(mir) = self.tcx.maybe_item_mir(def_id) { + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + // Don't inline calls that are in cleanup blocks. + if bb_data.is_cleanup { continue; } + + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + callsites.push(CallSite { + caller: def_id, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + + in_scc.insert(def_id); + } + } + } + + // Move callsites that are in the the SCC to the end so + // they're inlined after calls to outside the SCC + let mut first_call_in_scc = callsites.len(); + + let mut i = 0; + while i < first_call_in_scc { + let f = callsites[i].caller; + if in_scc.contains(&f) { + first_call_in_scc -= 1; + callsites.swap(i, first_call_in_scc); + } else { + i += 1; + } + } + + let mut local_change; + let mut changed = false; + + loop { + local_change = false; + let mut csi = 0; + while csi < callsites.len() { + let callsite = callsites[csi]; + csi += 1; + + let callee_mir = { + if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) { + if !self.should_inline(callsite, &callee_mir) { + continue; + } + + callee_mir.subst(self.tcx, callsite.substs) + } else { + continue; + } + + }; + + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&callsite.caller).unwrap(); + mir.borrow_mut() + }; + + let start = caller_mir.basic_blocks().len(); + + if !self.inline_call(callsite, &mut caller_mir, callee_mir) { + continue; + } + + inlined_into.insert(callsite.caller); + + // Add callsites from inlined function + for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + // Don't inline the same function multiple times. + if callsite.callee != callee_def_id { + callsites.push(CallSite { + caller: callsite.caller, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + } + + + csi -= 1; + if scc.len() == 1 { + callsites.swap_remove(csi); + } else { + callsites.remove(csi); + } + + local_change = true; + changed = true; + } + + if !local_change { + break; + } + } + + // Simplify functions we inlined into. + for def_id in inlined_into { + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&def_id).unwrap(); + mir.borrow_mut() + }; + + debug!("Running simplify cfg on {:?}", def_id); + CfgSimplifier::new(&mut caller_mir).simplify(); + remove_dead_blocks(&mut caller_mir); + } + changed + } + + fn should_inline(&self, callsite: CallSite<'tcx>, + callee_mir: &'a Mir<'tcx>) -> bool { + + let tcx = self.tcx; + + // Don't inline closures that have captures + // FIXME: Handle closures better + if callee_mir.upvar_decls.len() > 0 { + return false; + } + + // Don't inline calls to trait methods + // FIXME: Should try to resolve it to a concrete method, and + // only bail if that isn't possible + let trait_def = tcx.trait_of_item(callsite.callee); + if trait_def.is_some() { return false; } + + let attrs = tcx.get_attrs(callsite.callee); + let hint = attr::find_inline_attr(None, &attrs[..]); + + let hinted = match hint { + // Just treat inline(always) as a hint for now, + // there are cases that prevent inlining that we + // need to check for first. + attr::InlineAttr::Always => true, + attr::InlineAttr::Never => return false, + attr::InlineAttr::Hint => true, + attr::InlineAttr::None => false, + }; + + // Only inline local functions if they would be eligible for + // cross-crate inlining. This ensures that any symbols they + // use are reachable cross-crate + // FIXME(#36594): This shouldn't be necessary, and is more conservative + // than it could be, but trans should generate the reachable set from + // the MIR anyway, making any check obsolete. + if callsite.callee.is_local() { + // No type substs and no inline hint means this function + // wouldn't be eligible for cross-crate inlining + if callsite.substs.types().count() == 0 && !hinted { + return false; + } + + } + + let mut threshold = if hinted { + HINT_THRESHOLD + } else { + DEFAULT_THRESHOLD + }; + + // Significantly lower the threshold for inlining cold functions + if attr::contains_name(&attrs[..], "cold") { + threshold /= 5; + } + + // Give a bonus functions with a small number of blocks, + // We normally have two or three blocks for even + // very small functions. + if callee_mir.basic_blocks().len() <= 3 { + threshold += threshold / 4; + } + + // FIXME: Give a bonus to functions with only a single caller + + let id = tcx.hir.as_local_node_id(callsite.caller).expect("Caller not local"); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + + let mut first_block = true; + let mut cost = 0; + + // Traverse the MIR manually so we can account for the effects of + // inlining on the CFG. + let mut work_list = vec![START_BLOCK]; + let mut visited = BitVector::new(callee_mir.basic_blocks().len()); + while let Some(bb) = work_list.pop() { + if !visited.insert(bb.index()) { continue; } + let blk = &callee_mir.basic_blocks()[bb]; + + for stmt in &blk.statements { + // Don't count StorageLive/StorageDead in the inlining cost. + match stmt.kind { + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) | + StatementKind::Nop => {} + _ => cost += INSTR_COST + } + } + let term = blk.terminator(); + let mut is_drop = false; + match term.kind { + TerminatorKind::Drop { ref location, target, unwind } | + TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => { + is_drop = true; + work_list.push(target); + // If the location doesn't actually need dropping, treat it like + // a regular goto. + let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); + let ty = ty.to_ty(tcx); + if tcx.type_needs_drop_given_env(ty, ¶m_env) { + cost += CALL_PENALTY; + if let Some(unwind) = unwind { + work_list.push(unwind); + } + } else { + cost += INSTR_COST; + } + } + + TerminatorKind::Unreachable | + TerminatorKind::Call { destination: None, .. } if first_block => { + // If the function always diverges, don't inline + // unless the cost is zero + threshold = 0; + } + + TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { + if let ty::TyFnDef(.., f) = f.ty.sty { + // Don't give intrinsics the extra penalty for calls + if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { + cost += INSTR_COST; + } else { + cost += CALL_PENALTY; + } + } + } + TerminatorKind::Assert { .. } => cost += CALL_PENALTY, + _ => cost += INSTR_COST + } + + if !is_drop { + for &succ in &term.successors()[..] { + work_list.push(succ); + } + } + + first_block = false; + } + + // Count up the cost of local variables and temps, if we know the size + // use that, otherwise we use a moderately-large dummy cost. + + let ptr_size = tcx.data_layout.pointer_size.bytes(); + + for v in callee_mir.vars_and_temps_iter() { + let v = &callee_mir.local_decls[v]; + let ty = v.ty.subst(tcx, callsite.substs); + // Cost of the var is the size in machine-words, if we know + // it. + if let Some(size) = type_size_of(tcx, param_env.clone(), ty) { + cost += (size / ptr_size) as usize; + } else { + cost += UNKNOWN_SIZE_COST; + } + } + + debug!("Inline cost for {:?} is {}", callsite.callee, cost); + + if let attr::InlineAttr::Always = hint { + true + } else { + cost <= threshold + } + } + + + fn inline_call(&self, callsite: CallSite<'tcx>, + caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { + + // Don't inline a function into itself + if callsite.caller == callsite.callee { return false; } + + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + + + let terminator = caller_mir[callsite.bb].terminator.take().unwrap(); + match terminator.kind { + // FIXME: Handle inlining of diverging calls + TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { + + debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller); + + let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn(); + + let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); + let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); + let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); + + for mut scope in callee_mir.visibility_scopes.iter().cloned() { + if scope.parent_scope.is_none() { + scope.parent_scope = Some(callsite.location.scope); + scope.span = callee_mir.span; + } + + scope.span = callsite.location.span; + + let idx = caller_mir.visibility_scopes.push(scope); + scope_map.push(idx); + } + + for loc in callee_mir.vars_and_temps_iter() { + let mut local = callee_mir.local_decls[loc].clone(); + + if let Some(ref mut source_info) = local.source_info { + source_info.scope = scope_map[source_info.scope]; + + source_info.span = callsite.location.span; + } + + let idx = caller_mir.local_decls.push(local); + local_map.push(idx); + } + + for p in callee_mir.promoted.iter().cloned() { + let idx = caller_mir.promoted.push(p); + promoted_map.push(idx); + } + + // If the call is something like `a[*i] = f(i)`, where + // `i : &mut usize`, then just duplicating the `a[*i]` + // Lvalue could result in two different locations if `f` + // writes to `i`. To prevent this we need to create a temporary + // borrow of the lvalue and pass the destination as `*temp` instead. + fn dest_needs_borrow(lval: &Lvalue) -> bool { + match *lval { + Lvalue::Projection(ref p) => { + match p.elem { + ProjectionElem::Deref | + ProjectionElem::Index(_) => true, + _ => dest_needs_borrow(&p.base) + } + } + // Static variables need a borrow because the callee + // might modify the same static. + Lvalue::Static(_) => true, + _ => false + } + } + + let dest = if dest_needs_borrow(&destination.0) { + debug!("Creating temp for return destination"); + let dest = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + destination.0); + + let ty = dest.ty(caller_mir, self.tcx); + + let temp = LocalDecl::new_temp(ty); + + let tmp = caller_mir.local_decls.push(temp); + let tmp = Lvalue::Local(tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(tmp.clone(), dest) + }; + caller_mir[callsite.bb] + .statements.push(stmt); + tmp.deref() + } else { + destination.0 + }; + + let return_block = destination.1; + + let args : Vec<_> = if is_box_free { + assert!(args.len() == 1); + // box_free takes a Box, but is defined with a *mut T, inlining + // needs to generate the cast. + // FIXME: we should probably just generate correct MIR in the first place... + + let arg = if let Operand::Consume(ref lval) = args[0] { + lval.clone() + } else { + bug!("Constant arg to \"box_free\""); + }; + + let ptr_ty = args[0].ty(caller_mir, self.tcx); + vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] + } else { + // Copy the arguments if needed. + self.make_call_args(args, &callsite, caller_mir) + }; + + let bb_len = caller_mir.basic_blocks().len(); + let mut integrator = Integrator { + block_idx: bb_len, + args: &args, + local_map: local_map, + scope_map: scope_map, + promoted_map: promoted_map, + _callsite: callsite, + destination: dest, + return_block: return_block, + cleanup_block: cleanup, + in_cleanup_block: false + }; + + + for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) { + integrator.visit_basic_block_data(bb, &mut block); + caller_mir.basic_blocks_mut().push(block); + } + + let terminator = Terminator { + source_info: callsite.location, + kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) } + }; + + caller_mir[callsite.bb].terminator = Some(terminator); + + true + } + kind => { + caller_mir[callsite.bb].terminator = Some(Terminator { + source_info: terminator.source_info, + kind: kind + }); + false + } + } + } + + fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { + let arg = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + arg.deref()); + + let ty = arg.ty(caller_mir, self.tcx); + let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = caller_mir.local_decls.push(ref_tmp); + let ref_tmp = Lvalue::Local(ref_tmp); + + let ref_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(ref_tmp.clone(), arg) + }; + + caller_mir[callsite.bb] + .statements.push(ref_stmt); + + let pointee_ty = match ptr_ty.sty { + ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, + _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), + _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) + }; + let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); + + let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); + + let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = caller_mir.local_decls.push(cast_tmp); + let cast_tmp = Lvalue::Local(cast_tmp); + + let cast_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr) + }; + + caller_mir[callsite.bb] + .statements.push(cast_stmt); + + Operand::Consume(cast_tmp) + } + + fn make_call_args(&self, args: Vec>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Vec> { + let tcx = self.tcx; + // FIXME: Analysis of the usage of the arguments to avoid + // unnecessary temporaries. + args.into_iter().map(|a| { + if let Operand::Consume(Lvalue::Local(local)) = a { + if caller_mir.local_kind(local) == LocalKind::Temp { + // Reuse the operand if it's a temporary already + return a; + } + } + + debug!("Creating temp for argument"); + // Otherwise, create a temporary for the arg + let arg = Rvalue::Use(a); + + let ty = arg.ty(caller_mir, tcx); + + let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = caller_mir.local_decls.push(arg_tmp); + let arg_tmp = Lvalue::Local(arg_tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(arg_tmp.clone(), arg) + }; + caller_mir[callsite.bb].statements.push(stmt); + Operand::Consume(arg_tmp) + }).collect() + } +} + +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>, + ty: Ty<'tcx>) -> Option { + tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| { + ty.layout(&infcx).ok().map(|layout| { + layout.size(&tcx.data_layout).bytes() + }) + }) +} + +/** + * Integrator. + * + * Integrates blocks from the callee function into the calling function. + * Updates block indices, references to locals and other control flow + * stuff. + */ +struct Integrator<'a, 'tcx: 'a> { + block_idx: usize, + args: &'a [Operand<'tcx>], + local_map: IndexVec, + scope_map: IndexVec, + promoted_map: IndexVec, + _callsite: CallSite<'tcx>, + destination: Lvalue<'tcx>, + return_block: BasicBlock, + cleanup_block: Option, + in_cleanup_block: bool, +} + +impl<'a, 'tcx> Integrator<'a, 'tcx> { + fn update_target(&self, tgt: BasicBlock) -> BasicBlock { + let new = BasicBlock::new(tgt.index() + self.block_idx); + debug!("Updating target `{:?}`, new: `{:?}`", tgt, new); + new + } + + fn update_local(&self, local: Local) -> Option { + let idx = local.index(); + if idx < (self.args.len() + 1) { + return None; + } + let idx = idx - (self.args.len() + 1); + let local = Local::new(idx); + self.local_map.get(local).cloned() + } + + fn arg_index(&self, arg: Local) -> Option { + let idx = arg.index(); + if idx > 0 && idx <= self.args.len() { + Some(idx - 1) + } else { + None + } + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + _ctxt: LvalueContext<'tcx>, + _location: Location) { + if let Lvalue::Local(ref mut local) = *lvalue { + if let Some(l) = self.update_local(*local) { + // Temp or Var; update the local reference + *local = l; + return; + } + } + if let Lvalue::Local(local) = *lvalue { + if local == RETURN_POINTER { + // Return pointer; update the lvalue itself + *lvalue = self.destination.clone(); + } else if local.index() < (self.args.len() + 1) { + // Argument, once again update the the lvalue itself + let idx = local.index() - 1; + if let Operand::Consume(ref lval) = self.args[idx] { + *lvalue = lval.clone(); + } else { + bug!("Arg operand `{:?}` is not an Lvalue use.", idx) + } + } + } else { + self.super_lvalue(lvalue, _ctxt, _location) + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { + if let Operand::Consume(Lvalue::Local(arg)) = *operand { + if let Some(idx) = self.arg_index(arg) { + let new_arg = self.args[idx].clone(); + *operand = new_arg; + return; + } + } + self.super_operand(operand, location); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + self.in_cleanup_block = data.is_cleanup; + self.super_basic_block_data(block, data); + self.in_cleanup_block = false; + } + + fn visit_terminator_kind(&mut self, block: BasicBlock, + kind: &mut TerminatorKind<'tcx>, loc: Location) { + self.super_terminator_kind(block, kind, loc); + + match *kind { + TerminatorKind::Goto { ref mut target} => { + *target = self.update_target(*target); + } + TerminatorKind::SwitchInt { ref mut targets, .. } => { + for tgt in targets { + *tgt = self.update_target(*tgt); + } + } + TerminatorKind::Drop { ref mut target, ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *unwind { + *unwind = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this drop is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *unwind = self.cleanup_block; + } + } + TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { + if let Some((_, ref mut tgt)) = *destination { + *tgt = self.update_target(*tgt); + } + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this call is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this assert is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Return => { + *kind = TerminatorKind::Goto { target: self.return_block }; + } + TerminatorKind::Resume => { + if let Some(tgt) = self.cleanup_block { + *kind = TerminatorKind::Goto { target: tgt } + } + } + TerminatorKind::Unreachable => { } + } + } + + fn visit_visibility_scope(&mut self, scope: &mut VisibilityScope) { + *scope = self.scope_map[*scope]; + } + + fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) { + if let Literal::Promoted { ref mut index } = *literal { + if let Some(p) = self.promoted_map.get(*index).cloned() { + *index = p; + } + } else { + self.super_literal(literal, loc); + } + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index ae255f70fb788..cbd054a72499b 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -20,3 +20,4 @@ pub mod dump_mir; pub mod deaggregator; pub mod instcombine; pub mod copy_prop; +pub mod inline; diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index e93a412dc744f..a762507f35e7e 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -79,7 +79,7 @@ pub struct CfgSimplifier<'a, 'tcx: 'a> { } impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { - fn new(mir: &'a mut Mir<'tcx>) -> Self { + pub fn new(mir: &'a mut Mir<'tcx>) -> Self { let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks()); // we can't use mir.predecessors() here because that counts @@ -102,7 +102,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } } - fn simplify(mut self) { + pub fn simplify(mut self) { loop { let mut changed = false; @@ -137,6 +137,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { if !changed { break } } + + self.strip_nops() } // Collapse a goto chain starting from `start` @@ -231,9 +233,19 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { terminator.kind = TerminatorKind::Goto { target: first_succ }; true } + + fn strip_nops(&mut self) { + for blk in self.basic_blocks.iter_mut() { + blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { + false + } else { + true + }) + } + } } -fn remove_dead_blocks(mir: &mut Mir) { +pub fn remove_dead_blocks(mir: &mut Mir) { let mut seen = BitVector::new(mir.basic_blocks().len()); for (bb, _) in traversal::preorder(mir) { seen.insert(bb.index()); From f55e92b2a7a83f424f661c777e76054403b008b5 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 Feb 2017 06:31:47 +1300 Subject: [PATCH 70/73] Add dep-graph tasks where needed --- src/librustc_mir/transform/inline.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4b8e2bf49b9ee..4b4bd44230163 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -27,7 +27,7 @@ use rustc::util::nodemap::{DefIdSet}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; -use syntax::attr; +use syntax::{attr}; use syntax::abi::Abi; use callgraph; @@ -184,6 +184,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let callsite = callsites[csi]; csi += 1; + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + self.tcx.dep_graph.write(DepNode::Mir(callsite.caller)); + let callee_mir = { if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) { if !self.should_inline(callsite, &callee_mir) { @@ -232,7 +235,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - csi -= 1; if scc.len() == 1 { callsites.swap_remove(csi); @@ -251,6 +253,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // Simplify functions we inlined into. for def_id in inlined_into { + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id)); + self.tcx.dep_graph.write(DepNode::Mir(def_id)); + let mut caller_mir = { let map = self.tcx.maps.mir.borrow(); let mir = map.get(&def_id).unwrap(); @@ -275,11 +280,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } - // Don't inline calls to trait methods - // FIXME: Should try to resolve it to a concrete method, and - // only bail if that isn't possible - let trait_def = tcx.trait_of_item(callsite.callee); - if trait_def.is_some() { return false; } let attrs = tcx.get_attrs(callsite.callee); let hint = attr::find_inline_attr(None, &attrs[..]); @@ -294,19 +294,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { attr::InlineAttr::None => false, }; - // Only inline local functions if they would be eligible for - // cross-crate inlining. This ensures that any symbols they - // use are reachable cross-crate - // FIXME(#36594): This shouldn't be necessary, and is more conservative - // than it could be, but trans should generate the reachable set from - // the MIR anyway, making any check obsolete. + // Only inline local functions if they would be eligible for cross-crate + // inlining. This is to ensure that the final crate doesn't have MIR that + // reference unexported symbols if callsite.callee.is_local() { - // No type substs and no inline hint means this function - // wouldn't be eligible for cross-crate inlining if callsite.substs.types().count() == 0 && !hinted { return false; } - } let mut threshold = if hinted { From 3eb26d1f2bd9bd8d2c8f72d624d45f94bfe39695 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 Feb 2017 06:50:08 +1300 Subject: [PATCH 71/73] Only run inlining if mir opts are enabled --- src/librustc_mir/transform/inline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 4b4bd44230163..80a9c06f11b28 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -48,7 +48,7 @@ impl<'tcx> MirMapPass<'tcx> for Inline { tcx: TyCtxt<'a, 'tcx, 'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { - //if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } let _ignore = tcx.dep_graph.in_ignore(); From 889337da06e764369897ef15a6dfca6f27879a45 Mon Sep 17 00:00:00 2001 From: Cengiz Can Date: Fri, 10 Mar 2017 11:43:34 +0300 Subject: [PATCH 72/73] move related tests to type-check ui test directory --- src/test/ui/{resolve => type-check}/issue-38812-2.rs | 0 src/test/ui/{resolve => type-check}/issue-38812-2.stderr | 0 src/test/ui/{resolve => type-check}/issue-38812.rs | 0 src/test/ui/{resolve => type-check}/issue-38812.stderr | 0 src/test/ui/{resolve => type-check}/issue-40294.rs | 0 src/test/ui/{resolve => type-check}/issue-40294.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{resolve => type-check}/issue-38812-2.rs (100%) rename src/test/ui/{resolve => type-check}/issue-38812-2.stderr (100%) rename src/test/ui/{resolve => type-check}/issue-38812.rs (100%) rename src/test/ui/{resolve => type-check}/issue-38812.stderr (100%) rename src/test/ui/{resolve => type-check}/issue-40294.rs (100%) rename src/test/ui/{resolve => type-check}/issue-40294.stderr (100%) diff --git a/src/test/ui/resolve/issue-38812-2.rs b/src/test/ui/type-check/issue-38812-2.rs similarity index 100% rename from src/test/ui/resolve/issue-38812-2.rs rename to src/test/ui/type-check/issue-38812-2.rs diff --git a/src/test/ui/resolve/issue-38812-2.stderr b/src/test/ui/type-check/issue-38812-2.stderr similarity index 100% rename from src/test/ui/resolve/issue-38812-2.stderr rename to src/test/ui/type-check/issue-38812-2.stderr diff --git a/src/test/ui/resolve/issue-38812.rs b/src/test/ui/type-check/issue-38812.rs similarity index 100% rename from src/test/ui/resolve/issue-38812.rs rename to src/test/ui/type-check/issue-38812.rs diff --git a/src/test/ui/resolve/issue-38812.stderr b/src/test/ui/type-check/issue-38812.stderr similarity index 100% rename from src/test/ui/resolve/issue-38812.stderr rename to src/test/ui/type-check/issue-38812.stderr diff --git a/src/test/ui/resolve/issue-40294.rs b/src/test/ui/type-check/issue-40294.rs similarity index 100% rename from src/test/ui/resolve/issue-40294.rs rename to src/test/ui/type-check/issue-40294.rs diff --git a/src/test/ui/resolve/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr similarity index 100% rename from src/test/ui/resolve/issue-40294.stderr rename to src/test/ui/type-check/issue-40294.stderr From d76b226eae87d86c6faf6cde9598f68c8012a4c0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 10 Mar 2017 07:21:28 -0800 Subject: [PATCH 73/73] Test fixes and rebase conflicts --- src/bootstrap/bootstrap.py | 2 +- src/bootstrap/native.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b15bc77ec1365..b326f95e505fb 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -296,7 +296,7 @@ def get_toml(self, key): def get_mk(self, key): for line in iter(self.config_mk.splitlines()): - if line.startswith(key + ' :='): + if line.startswith(key + ' '): var = line[line.find(':=') + 2:].strip() if var != '': return var diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a7754f2669ef0..6cc1ca8d02ed0 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -58,7 +58,7 @@ pub fn llvm(build: &Build, target: &str) { } } if build.config.llvm_clean_rebuild { - t!(fs::remove_dir_all(&out_dir)); + drop(fs::remove_dir_all(&out_dir)); } println!("Building LLVM for {}", target); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 52f6ec0c6ffa5..8f66c1a2b8cf6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3731,7 +3731,7 @@ impl<'a> Parser<'a> { !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) } - fn is_union_item(&mut self) -> bool { + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) }