diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a8..c1af7bd794cbf 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -144,6 +144,7 @@ struct Rust { rpath: Option, optimize_tests: Option, debuginfo_tests: Option, + codegen_tests: Option, } /// TOML representation of how each build target is configured. @@ -232,6 +233,7 @@ impl Config { set(&mut config.rust_optimize, rust.optimize); set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); + set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef622..fcbd1d33309ff 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -1,5 +1,8 @@ # Sample TOML configuration file for building Rust. # +# To configure rustbuild, copy this file to the directory from which you will be +# running the build, and name it config.toml. +# # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for # `config.toml` in the current directory of a build for build configuration, but @@ -130,6 +133,10 @@ #optimize-tests = true #debuginfo-tests = true +# Flag indicating whether codegen tests will be run or not. If you get an error +# saying that the FileCheck executable is missing, you may want to disable this. +#codegen-tests = true + # ============================================================================= # Options for specific targets # diff --git a/src/doc/book/nightly-rust.md b/src/doc/book/nightly-rust.md index b3be71038a992..25570cb5503c9 100644 --- a/src/doc/book/nightly-rust.md +++ b/src/doc/book/nightly-rust.md @@ -54,7 +54,7 @@ binary downloads][install-page]. Oh, we should also mention the officially supported platforms: -* Windows (7, 8, Server 2008 R2) +* Windows (7+) * Linux (2.6.18 or later, various distributions), x86 and x86-64 * OSX 10.7 (Lion) or greater, x86 and x86-64 diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a2f926aa92c52..e80f004f150a2 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -849,9 +849,13 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate"), save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information in addition to normal output"), + "write syntax and type analysis (in JSON format) information, in \ + addition to normal output"), save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in CSV format) information in addition to normal output"), + "write syntax and type analysis (in CSV format) information, in addition to normal output"), + save_analysis_api: bool = (false, parse_bool, [UNTRACKED], + "write syntax and type analysis information for opaque libraries (in JSON format), \ + in addition to normal output"), print_move_fragments: bool = (false, parse_bool, [UNTRACKED], "print out move-fragment data for every fn"), flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED], @@ -2365,6 +2369,8 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis_csv = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + opts.debugging_opts.save_analysis_api = true; + assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.print_move_fragments = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.flowgraph_print_loans = true; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 47a0399b63283..e059b6445c120 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -250,7 +250,8 @@ fn keep_hygiene_data(sess: &Session) -> bool { fn keep_ast(sess: &Session) -> bool { sess.opts.debugging_opts.keep_ast || sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } /// The name used for source code that doesn't originate in a file diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6616e9579e818..ef2234a5f6192 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -555,7 +555,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn save_analysis(sess: &Session) -> bool { sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } fn save_analysis_format(sess: &Session) -> save::Format { @@ -563,6 +564,8 @@ fn save_analysis_format(sess: &Session) -> save::Format { save::Format::Json } else if sess.opts.debugging_opts.save_analysis_csv { save::Format::Csv + } else if sess.opts.debugging_opts.save_analysis_api { + save::Format::JsonApi } else { unreachable!(); } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2524348dc1a96..62e5d670fb69a 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1056,8 +1056,9 @@ impl<'a> LocalCrateReader<'a> { Some("dylib") => cstore::NativeUnknown, Some("framework") => cstore::NativeFramework, Some(k) => { - span_err!(self.sess, m.span, E0458, - "unknown kind: `{}`", k); + struct_span_err!(self.sess, m.span, E0458, + "unknown kind: `{}`", k) + .span_label(m.span, &format!("unknown kind")).emit(); cstore::NativeUnknown } None => cstore::NativeUnknown @@ -1068,8 +1069,9 @@ impl<'a> LocalCrateReader<'a> { let n = match n { Some(n) => n, None => { - span_err!(self.sess, m.span, E0459, - "#[link(...)] specified without `name = \"foo\"`"); + struct_span_err!(self.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`") + .span_label(m.span, &format!("missing `name` argument")).emit(); InternedString::new("foo") } }; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 6c6a5f7fc74b0..02a643b76d548 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -18,6 +18,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::dep_graph::DepNode; use rustc::hir; +use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; @@ -252,14 +253,46 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg); + if self.mode != Mode::Const { help!(&mut err, "in Nightly builds, add `#![feature(drop_types_in_const)]` \ to the crate attributes to enable"); + } else { + self.find_drop_implementation_method_span() + .map(|span| err.span_label(span, &format!("destructor defined here"))); + + err.span_label(self.span, &format!("constants cannot have destructors")); } + err.emit(); } + fn find_drop_implementation_method_span(&self) -> Option { + self.tcx.lang_items + .drop_trait() + .and_then(|drop_trait_id| { + let mut span = None; + + self.tcx + .lookup_trait_def(drop_trait_id) + .for_each_relevant_impl(self.tcx, self.mir.return_ty, |impl_did| { + self.tcx.map + .as_local_node_id(impl_did) + .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) + .map(|node| { + if let hir_map::NodeItem(item) = node { + if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node { + span = methods.first().map(|method| method.span); + } + } + }); + }); + + span + }) + } + /// Check if an Lvalue with the current qualifications could /// be consumed, by either an operand or a Deref projection. fn try_consume(&mut self) -> bool { diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 493f7669337fe..a58cce0745f30 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -13,8 +13,9 @@ //! The `Dump` trait can be used together with `DumpVisitor` in order to //! retrieve the data from a crate. +use rustc::hir; use rustc::hir::def_id::DefId; -use syntax::ast::{CrateNum, NodeId}; +use syntax::ast::{self, CrateNum, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -76,6 +77,35 @@ pub enum Data { VariableRefData(VariableRefData), } +#[derive(Eq, PartialEq, Clone, Copy, Debug, RustcEncodable)] +pub enum Visibility { + Public, + Restricted, + Inherited, +} + +impl<'a> From<&'a ast::Visibility> for Visibility { + fn from(v: &'a ast::Visibility) -> Visibility { + match *v { + ast::Visibility::Public => Visibility::Public, + ast::Visibility::Crate(_) => Visibility::Restricted, + ast::Visibility::Restricted { .. } => Visibility::Restricted, + ast::Visibility::Inherited => Visibility::Inherited, + } + } +} + +impl<'a> From<&'a hir::Visibility> for Visibility { + fn from(v: &'a hir::Visibility) -> Visibility { + match *v { + hir::Visibility::Public => Visibility::Public, + hir::Visibility::Crate => Visibility::Restricted, + hir::Visibility::Restricted { .. } => Visibility::Restricted, + hir::Visibility::Inherited => Visibility::Inherited, + } + } +} + /// Data for the prelude of a crate. #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { @@ -103,7 +133,7 @@ pub struct EnumData { pub span: Span, pub scope: NodeId, pub variants: Vec, - + pub visibility: Visibility, } /// Data for extern crates. @@ -135,6 +165,8 @@ pub struct FunctionData { pub span: Span, pub scope: NodeId, pub value: String, + pub visibility: Visibility, + pub parent: Option, } /// Data about a function call. @@ -215,6 +247,7 @@ pub struct MethodData { pub scope: NodeId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, } /// Data for modules. @@ -227,6 +260,7 @@ pub struct ModData { pub scope: NodeId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } /// Data for a reference to a module. @@ -248,6 +282,7 @@ pub struct StructData { pub scope: NodeId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -258,7 +293,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } #[derive(Debug, RustcEncodable)] @@ -270,6 +306,7 @@ pub struct TraitData { pub scope: NodeId, pub value: String, pub items: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -280,7 +317,8 @@ pub struct TupleVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } /// Data for a typedef. @@ -291,6 +329,8 @@ pub struct TypeDefData { pub span: Span, pub qualname: String, pub value: String, + pub visibility: Visibility, + pub parent: Option, } /// Data for a reference to a type or trait. @@ -308,7 +348,8 @@ pub struct UseData { pub span: Span, pub name: String, pub mod_id: Option, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -316,7 +357,8 @@ pub struct UseGlobData { pub id: NodeId, pub span: Span, pub names: Vec, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } /// Data for local and global variables (consts and statics). @@ -328,8 +370,10 @@ pub struct VariableData { pub qualname: String, pub span: Span, pub scope: NodeId, + pub parent: Option, pub value: String, pub type_value: String, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f9a20cec42d14..a695a07066205 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -365,7 +365,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}::{}", qualname, path_to_string(p)), type_value: typ, value: String::new(), - scope: 0 + scope: 0, + parent: None, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -377,6 +379,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { body: Option<&ast::Block>, id: ast::NodeId, name: ast::Name, + vis: Visibility, span: Span) { debug!("process_method: {}:{}", id, name); @@ -417,6 +420,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: method_data.qualname.clone(), value: sig_str, decl_id: decl_id, + visibility: vis, }.lower(self.tcx)); } @@ -484,7 +488,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: name, id: param.id, qualname: qualname, - value: String::new() + value: String::new(), + visibility: Visibility::Inherited, + parent: None, }.lower(self.tcx)); } } @@ -528,12 +534,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_expr(expr); } - fn process_const(&mut self, - id: ast::NodeId, - name: ast::Name, - span: Span, - typ: &ast::Ty, - expr: &ast::Expr) { + fn process_assoc_const(&mut self, + id: ast::NodeId, + name: ast::Name, + span: Span, + typ: &ast::Ty, + expr: &ast::Expr, + parent_id: NodeId, + vis: Visibility) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -547,7 +555,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, value: self.span.snippet(expr.span), type_value: ty_to_string(&typ), - scope: self.cur_scope + scope: self.cur_scope, + parent: Some(parent_id), + visibility: vis, }.lower(self.tcx)); } @@ -589,6 +599,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, fields: fields, + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -640,7 +651,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -663,7 +675,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -716,7 +729,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { - self.visit_impl_item(impl_item); + self.process_impl_item(impl_item, item.id); } } @@ -745,6 +758,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, items: methods.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -785,7 +799,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // walk generics and methods self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { - self.visit_trait_item(method) + self.process_trait_item(method, item.id) } } @@ -990,7 +1004,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: typ, - scope: 0 + scope: 0, + parent: None, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -1038,6 +1054,57 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } + + fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: NodeId) { + self.process_macro_use(trait_item.span, trait_item.id); + match trait_item.node { + ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { + self.process_assoc_const(trait_item.id, + trait_item.ident.name, + trait_item.span, + &ty, + &expr, + trait_id, + Visibility::Public); + } + ast::TraitItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + body.as_ref().map(|x| &**x), + trait_item.id, + trait_item.ident.name, + Visibility::Public, + trait_item.span); + } + ast::TraitItemKind::Const(_, None) | + ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Macro(_) => {} + } + } + + fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: NodeId) { + self.process_macro_use(impl_item.span, impl_item.id); + match impl_item.node { + ast::ImplItemKind::Const(ref ty, ref expr) => { + self.process_assoc_const(impl_item.id, + impl_item.ident.name, + impl_item.span, + &ty, + &expr, + impl_id, + From::from(&impl_item.vis)); + } + ast::ImplItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + Some(body), + impl_item.id, + impl_item.ident.name, + From::from(&impl_item.vis), + impl_item.span); + } + ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Macro(_) => {} + } + } } impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> { @@ -1073,7 +1140,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> id: item.id, mod_id: mod_id, name: ident.to_string(), - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths_truncated(path, true); @@ -1096,7 +1164,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> span: sub_span.expect("No span found for use glob"), id: item.id, names: names, - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths(path, true); @@ -1168,7 +1237,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> name: item.ident.to_string(), id: item.id, qualname: qualname.clone(), - value: value + value: value, + visibility: From::from(&item.vis), + parent: None, }.lower(self.tcx)); } @@ -1193,51 +1264,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { - self.process_macro_use(trait_item.span, trait_item.id); - match trait_item.node { - ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { - self.process_const(trait_item.id, - trait_item.ident.name, - trait_item.span, - &ty, - &expr); - } - ast::TraitItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - body.as_ref().map(|x| &**x), - trait_item.id, - trait_item.ident.name, - trait_item.span); - } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | - ast::TraitItemKind::Macro(_) => {} - } - } - - fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { - self.process_macro_use(impl_item.span, impl_item.id); - match impl_item.node { - ast::ImplItemKind::Const(ref ty, ref expr) => { - self.process_const(impl_item.id, - impl_item.ident.name, - impl_item.span, - &ty, - &expr); - } - ast::ImplItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - Some(body), - impl_item.id, - impl_item.ident.name, - impl_item.span); - } - ast::ImplItemKind::Type(_) | - ast::ImplItemKind::Macro(_) => {} - } - } - fn visit_ty(&mut self, t: &ast::Ty) { self.process_macro_use(t.span, t.id); match t.node { @@ -1400,7 +1426,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: String::new(), - scope: 0 + scope: 0, + parent: None, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 65e4f7e869b0d..4333c6dd18e60 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -15,7 +15,7 @@ use syntax::ast::{CrateNum, NodeId}; use syntax::codemap::CodeMap; use syntax_pos::Span; -use data; +use data::{self, Visibility}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { @@ -91,7 +91,8 @@ pub struct EnumData { pub qualname: String, pub span: SpanData, pub scope: DefId, - pub variants: Vec + pub variants: Vec, + pub visibility: Visibility, } impl Lower for data::EnumData { @@ -106,6 +107,7 @@ impl Lower for data::EnumData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -166,6 +168,8 @@ pub struct FunctionData { pub span: SpanData, pub scope: DefId, pub value: String, + pub visibility: Visibility, + pub parent: Option, } impl Lower for data::FunctionData { @@ -180,6 +184,8 @@ impl Lower for data::FunctionData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), value: self.value, + visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -323,6 +329,8 @@ pub struct MethodData { pub scope: DefId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, + pub parent: Option } impl Lower for data::MethodData { @@ -337,6 +345,8 @@ impl Lower for data::MethodData { qualname: self.qualname, value: self.value, decl_id: self.decl_id, + visibility: self.visibility, + parent: Some(make_def_id(self.scope, &tcx.map)), } } } @@ -351,6 +361,7 @@ pub struct ModData { pub scope: DefId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::ModData { @@ -365,6 +376,7 @@ impl Lower for data::ModData { scope: make_def_id(self.scope, &tcx.map), filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -401,6 +413,7 @@ pub struct StructData { pub scope: DefId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } impl Lower for data::StructData { @@ -416,6 +429,7 @@ impl Lower for data::StructData { scope: make_def_id(self.scope, &tcx.map), value: self.value, fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -428,7 +442,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: DefId + pub scope: DefId, + pub parent: Option, } impl Lower for data::StructVariantData { @@ -443,6 +458,7 @@ impl Lower for data::StructVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -456,6 +472,7 @@ pub struct TraitData { pub scope: DefId, pub value: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::TraitData { @@ -470,6 +487,7 @@ impl Lower for data::TraitData { scope: make_def_id(self.scope, &tcx.map), value: self.value, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -483,6 +501,7 @@ pub struct TupleVariantData { pub type_value: String, pub value: String, pub scope: DefId, + pub parent: Option, } impl Lower for data::TupleVariantData { @@ -497,6 +516,7 @@ impl Lower for data::TupleVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -509,6 +529,8 @@ pub struct TypeDefData { pub span: SpanData, pub qualname: String, pub value: String, + pub visibility: Visibility, + pub parent: Option, } impl Lower for data::TypeDefData { @@ -521,6 +543,8 @@ impl Lower for data::TypeDefData { span: SpanData::from_span(self.span, tcx.sess.codemap()), qualname: self.qualname, value: self.value, + visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -553,7 +577,8 @@ pub struct UseData { pub span: SpanData, pub name: String, pub mod_id: Option, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseData { @@ -566,6 +591,7 @@ impl Lower for data::UseData { name: self.name, mod_id: self.mod_id, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -575,7 +601,8 @@ pub struct UseGlobData { pub id: DefId, pub span: SpanData, pub names: Vec, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseGlobData { @@ -587,6 +614,7 @@ impl Lower for data::UseGlobData { span: SpanData::from_span(self.span, tcx.sess.codemap()), names: self.names, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -602,6 +630,8 @@ pub struct VariableData { pub scope: DefId, pub value: String, pub type_value: String, + pub parent: Option, + pub visibility: Visibility, } impl Lower for data::VariableData { @@ -617,6 +647,8 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + visibility: self.visibility, } } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs new file mode 100644 index 0000000000000..874babb907e4c --- /dev/null +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -0,0 +1,393 @@ +// 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. + +use std::io::Write; + +use rustc::hir::def_id::DefId; +use rustc_serialize::json::as_json; + +use external_data::*; +use data::{VariableKind, Visibility}; +use dump::Dump; + +// A dumper to dump a restricted set of JSON information, designed for use with +// libraries distributed without their source. Clients are likely to use type +// information here, and (for example) generate Rustdoc URLs, but don't need +// information for navigating the source of the crate. +// Relative to the regular JSON save-analysis info, this form is filtered to +// remove non-visible items, but includes some extra info for items (e.g., the +// parent field for finding the struct to which a field belongs). +pub struct JsonApiDumper<'b, W: Write + 'b> { + output: &'b mut W, + result: Analysis, +} + +impl<'b, W: Write> JsonApiDumper<'b, W> { + pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> { + JsonApiDumper { output: writer, result: Analysis::new() } + } +} + +impl<'b, W: Write> Drop for JsonApiDumper<'b, W> { + fn drop(&mut self) { + if let Err(_) = write!(self.output, "{}", as_json(&self.result)) { + error!("Error writing output"); + } + } +} + +macro_rules! impl_fn { + ($fn_name: ident, $data_type: ident, $bucket: ident) => { + fn $fn_name(&mut self, data: $data_type) { + if let Some(datum) = From::from(data) { + self.result.$bucket.push(datum); + } + } + } +} + +impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { + fn crate_prelude(&mut self, data: CratePreludeData) { + self.result.prelude = Some(data) + } + + impl_fn!(use_data, UseData, imports); + impl_fn!(use_glob, UseGlobData, imports); + + impl_fn!(enum_data, EnumData, defs); + impl_fn!(tuple_variant, TupleVariantData, defs); + impl_fn!(struct_variant, StructVariantData, defs); + impl_fn!(struct_data, StructData, defs); + impl_fn!(trait_data, TraitData, defs); + impl_fn!(function, FunctionData, defs); + impl_fn!(method, MethodData, defs); + impl_fn!(macro_data, MacroData, defs); + impl_fn!(mod_data, ModData, defs); + impl_fn!(typedef, TypeDefData, defs); + impl_fn!(variable, VariableData, defs); +} + +// FIXME methods. The defs have information about possible overriding and the +// refs have decl information (e.g., a trait method where we know the required +// method, but not the supplied method). In both cases, we are currently +// ignoring it. + +#[derive(Debug, RustcEncodable)] +struct Analysis { + prelude: Option, + imports: Vec, + defs: Vec, +} + +impl Analysis { + fn new() -> Analysis { + Analysis { + prelude: None, + imports: vec![], + defs: vec![], + } + } +} + +// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore +// we use our own Id which is the same, but without the newtype. +#[derive(Debug, RustcEncodable)] +struct Id { + krate: u32, + index: u32, +} + +impl From for Id { + fn from(id: DefId) -> Id { + Id { + krate: id.krate, + index: id.index.as_u32(), + } + } +} + +#[derive(Debug, RustcEncodable)] +struct Import { + kind: ImportKind, + id: Id, + span: SpanData, + name: String, + value: String, +} + +#[derive(Debug, RustcEncodable)] +enum ImportKind { + Use, + GlobUse, +} + +impl From for Option { + fn from(data: UseData) -> Option { + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: UseGlobData) -> Option { + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::GlobUse, + id: From::from(data.id), + span: data.span, + name: "*".to_owned(), + value: data.names.join(", "), + }), + _ => None, + } + } +} + +#[derive(Debug, RustcEncodable)] +struct Def { + kind: DefKind, + id: Id, + span: SpanData, + name: String, + qualname: String, + value: String, + parent: Option, + children: Vec, + decl_id: Option, +} + +#[derive(Debug, RustcEncodable)] +enum DefKind { + // value = variant names + Enum, + // value = enum name + variant name + types + Tuple, + // value = [enum name +] name + fields + Struct, + // value = signature + Trait, + // value = type + generics + Function, + // value = type + generics + Method, + // No id, no value. + Macro, + // value = file_name + Mod, + // value = aliased type + Type, + // value = type and init expression (for all variable kinds). + Static, + Const, + Field, +} + +impl From for Option { + fn from(data: EnumData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Enum, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.variants.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }), + _ => None, + } + } +} + +impl From for Option { + fn from(data: TupleVariantData) -> Option { + Some(Def { + kind: DefKind::Tuple, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: data.parent.map(|id| From::from(id)), + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructVariantData) -> Option { + Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: data.parent.map(|id| From::from(id)), + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.fields.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: TraitData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Trait, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: FunctionData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Function, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: data.parent.map(|id| From::from(id)), + decl_id: None, + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: MethodData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Method, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: data.parent.map(|id| From::from(id)), + decl_id: data.decl_id.map(|id| From::from(id)), + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: MacroData) -> Option { + Some(Def { + kind: DefKind::Macro, + id: From::from(null_def_id()), + span: data.span, + name: data.name, + qualname: data.qualname, + value: String::new(), + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data:ModData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Mod, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: TypeDefData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Type, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: data.parent.map(|id| From::from(id)), + decl_id: None, + }), + _ => None, + } + } +} +impl From for Option { + fn from(data: VariableData) -> Option { + match data.visibility { + Visibility::Public => Some(Def { + kind: match data.kind { + VariableKind::Static => DefKind::Static, + VariableKind::Const => DefKind::Const, + VariableKind::Local => { return None } + VariableKind::Field => DefKind::Field, + }, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: data.parent.map(|id| From::from(id)), + decl_id: None, + }), + _ => None, + } + } +} diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 47f3a06de1bd1..f32baf30ff42e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -30,6 +30,7 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; mod csv_dumper; +mod json_api_dumper; mod json_dumper; mod data; mod dump; @@ -57,6 +58,7 @@ use syntax::codemap::MacroAttribute; use syntax_pos::*; pub use self::csv_dumper::CsvDumper; +pub use self::json_api_dumper::JsonApiDumper; pub use self::json_dumper::JsonDumper; pub use self::data::*; pub use self::dump::Dump; @@ -138,6 +140,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), value: make_signature(decl, generics), + visibility: From::from(&item.vis), + parent: None, })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -160,8 +164,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: value, type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -175,8 +181,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Mod(ref m) => { @@ -195,6 +203,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), filename: filename, items: m.items.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Enum(ref def, _) => { @@ -215,6 +224,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, scope: self.enclosing_scope(item.id), variants: def.variants.iter().map(|v| v.node.data.id()).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => { @@ -277,8 +287,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: scope, + parent: Some(scope), value: "".to_owned(), type_value: typ, + visibility: From::from(&field.vis), }) } else { None @@ -291,7 +303,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 = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, vis) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -304,7 +316,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - result + (result, From::from(&item.vis)) } _ => { span_bug!(span, @@ -325,8 +337,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) { Some(def_id) => { match self.tcx.map.get_if_local(def_id) { - Some(NodeItem(_)) => { - format!("::{}", self.tcx.item_path_str(def_id)) + Some(NodeItem(item)) => { + (format!("::{}", self.tcx.item_path_str(def_id)), From::from(&item.vis)) } r => { span_bug!(span, @@ -358,6 +370,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); + let parent_scope = self.enclosing_scope(id); Some(FunctionData { id: id, name: name.to_string(), @@ -367,6 +380,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(id), // FIXME you get better data here by using the visitor. value: String::new(), + visibility: vis, + parent: Some(parent_scope), }) } @@ -728,13 +743,14 @@ impl Visitor for PathCollector { pub enum Format { Csv, Json, + JsonApi, } impl Format { fn extension(&self) -> &'static str { match *self { Format::Csv => ".csv", - Format::Json => ".json", + Format::Json | Format::JsonApi => ".json", } } } @@ -804,6 +820,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, match format { Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), + Format::JsonApi => dump!(JsonApiDumper::new(output)), } } diff --git a/src/test/compile-fail/E0458.rs b/src/test/compile-fail/E0458.rs index 21bedc6b84c2b..e87158ae3b03f 100644 --- a/src/test/compile-fail/E0458.rs +++ b/src/test/compile-fail/E0458.rs @@ -9,7 +9,9 @@ // except according to those terms. #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 - //~^ ERROR E0459 + //~| NOTE unknown kind + //~| ERROR E0459 + //~| NOTE missing `name` argument fn main() { } diff --git a/src/test/compile-fail/E0459.rs b/src/test/compile-fail/E0459.rs index dc7ac714f2239..41376bd9ef5a2 100644 --- a/src/test/compile-fail/E0459.rs +++ b/src/test/compile-fail/E0459.rs @@ -9,6 +9,7 @@ // except according to those terms. #[link(kind = "dylib")] extern {} //~ ERROR E0459 + //~| NOTE missing `name` argument fn main() { } diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile index 3c636baaedc5f..3711b6ea8959b 100644 --- a/src/test/run-make/save-analysis/Makefile +++ b/src/test/run-make/save-analysis/Makefile @@ -5,3 +5,4 @@ krate2: krate2.rs code: foo.rs krate2 $(RUSTC) foo.rs -Zsave-analysis-csv $(RUSTC) foo.rs -Zsave-analysis + $(RUSTC) foo.rs -Zsave-analysis-api diff --git a/src/test/compile-fail/E0493.rs b/src/test/ui/span/E0493.rs similarity index 83% rename from src/test/compile-fail/E0493.rs rename to src/test/ui/span/E0493.rs index 689f469533d96..ea4526b70f6a8 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/ui/span/E0493.rs @@ -16,7 +16,15 @@ impl Drop for Foo { fn drop(&mut self) {} } -const F : Foo = Foo { a : 0 }; //~ ERROR E0493 +struct Bar { + a: u32 +} + +impl Drop for Bar { + fn drop(&mut self) {} +} + +const F : Foo = Foo { a : 0 }; fn main() { } diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr new file mode 100644 index 0000000000000..afcc9a240eb4e --- /dev/null +++ b/src/test/ui/span/E0493.stderr @@ -0,0 +1,11 @@ +error[E0493]: constants are not allowed to have destructors + --> $DIR/E0493.rs:27:17 + | +16 | fn drop(&mut self) {} + | --------------------- destructor defined here +... +27 | const F : Foo = Foo { a : 0 }; + | ^^^^^^^^^^^^^ constants cannot have destructors + +error: aborting due to previous error +