From faf73028c9afe5790e9b4d83a348d93e4a098852 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Mon, 22 Jun 2015 20:55:57 -0600 Subject: Fix issue #23302, ICE on recursively defined enum variant discriminant. --- src/libsyntax/visit.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 710928a00c1..649052d123c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -90,6 +90,11 @@ pub trait Visitor<'v> : Sized { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, + generics: &'v Generics) { + walk_enum_def(self, enum_definition, generics) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding @@ -268,7 +273,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - walk_enum_def(visitor, enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) -- cgit 1.4.1-3-g733a5 From 599bf45ac9afc309332388fe4bc42a100e3d1586 Mon Sep 17 00:00:00 2001 From: Theo Belaire Date: Fri, 1 May 2015 21:13:27 +0200 Subject: Indent code past the widest line number Fixes #11715 --- src/libsyntax/diagnostic.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 14dd9978b87..6c2e3dc6330 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -594,12 +594,18 @@ fn highlight_lines(err: &mut EmitterWriter, let display_line_infos = &lines.lines[..display_lines]; let display_line_strings = &line_strings[..display_lines]; + // Calculate the widest number to format evenly and fix #11715 + assert!(display_line_infos.len() > 0); + let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; + let mut digits = 0; + while max_line_num > 0 { max_line_num /= 10; digits += 1; } // Print the offending lines for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { - try!(write!(&mut err.dst, "{}:{} {}\n", + try!(write!(&mut err.dst, "{}:{:>width$} {}\n", fm.name, line_info.line_index + 1, - line)); + line, + width=digits)); } // If we elided something, put an ellipsis. -- cgit 1.4.1-3-g733a5 From c5dfd34c615b0586a101e9e66770a5c4fd31c852 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 23 Jun 2015 11:43:27 +0200 Subject: Added unit test for code indent of multi-line errors --- src/libsyntax/diagnostic.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 6c2e3dc6330..ec93d2c5536 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -598,7 +598,11 @@ fn highlight_lines(err: &mut EmitterWriter, assert!(display_line_infos.len() > 0); let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; let mut digits = 0; - while max_line_num > 0 { max_line_num /= 10; digits += 1; } + while max_line_num > 0 { + max_line_num /= 10; + digits += 1; + } + // Print the offending lines for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { try!(write!(&mut err.dst, "{}:{:>width$} {}\n", @@ -801,3 +805,64 @@ pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where None => diag.handler().bug(&msg()), } } + +#[cfg(test)] +mod test { + use super::{EmitterWriter, highlight_lines, Level}; + use codemap::{mk_sp, CodeMap, BytePos}; + use std::sync::{Arc, Mutex}; + use std::io::{self, Write}; + use std::str::from_utf8; + + // Diagnostic doesn't align properly in span where line number increases by one digit + #[test] + fn test_hilight_suggestion_issue_11715() { + struct Sink(Arc>>); + impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + let data = Arc::new(Mutex::new(Vec::new())); + let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None); + let cm = CodeMap::new(); + let content = "abcdefg + koksi + line3 + line4 + cinq + line6 + line7 + line8 + line9 + line10 + e-lä-vän + tolv + dreizehn + "; + let file = cm.new_filemap("dummy.txt".to_string(), content.to_string()); + for (i, b) in content.bytes().enumerate() { + if b == b'\n' { + file.next_line(BytePos(i as u32)); + } + } + let start = file.lines.borrow()[7]; + let end = file.lines.borrow()[11]; + let sp = mk_sp(start, end); + let lvl = Level::Error; + println!("span_to_lines"); + let lines = cm.span_to_lines(sp); + println!("highlight_lines"); + highlight_lines(&mut ew, &cm, sp, lvl, lines).unwrap(); + println!("done"); + let vec = data.lock().unwrap().clone(); + let vec: &[u8] = &vec; + println!("{}", from_utf8(vec).unwrap()); + assert_eq!(vec, "dummy.txt: 8 \n\ + dummy.txt: 9 \n\ + dummy.txt:10 \n\ + dummy.txt:11 \n\ + dummy.txt:12 \n".as_bytes()); + } +} -- cgit 1.4.1-3-g733a5 From a18d9842ed94ecca3e7161945bb2f749d98d18ee Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 18 Jun 2015 01:02:58 +0300 Subject: Make the unused_mut lint smarter with respect to locals. Fixes #26332 --- src/libcore/iter.rs | 4 ++-- src/libfmt_macros/lib.rs | 2 +- src/librustc/middle/infer/error_reporting.rs | 2 +- src/librustc_borrowck/borrowck/check_loans.rs | 25 +++++++--------------- src/librustc_trans/save/dump_csv.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/test/compile-fail/lint-unused-mut-variables.rs | 9 ++++++++ 7 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3026f91e853..4c8511eb190 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2655,8 +2655,8 @@ macro_rules! step_impl_signed { #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t, by: &$t) -> Option { if *by == 0 { return None; } - let mut diff: usize; - let mut by_u: usize; + let diff: usize; + let by_u: usize; if *by > 0 { if *start >= *end { return Some(0); diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index c2b28bd134d..7ca89cfd0c9 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { } Some(..) | None => { return &self.input[..0]; } }; - let mut end; + let end; loop { match self.cur.clone().next() { Some((_, c)) if c.is_xid_continue() => { diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 17075c0cba6..6d5b47d8ed9 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1854,7 +1854,7 @@ impl LifeGiver { } fn give_lifetime(&self) -> ast::Lifetime { - let mut lifetime; + let lifetime; loop { let mut s = String::from("'"); s.push_str(&num_to_string(self.counter.get())); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index f06dc105d9c..237add6ff86 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { None => { } } - self.check_assignment(assignment_id, assignment_span, assignee_cmt, mode); + self.check_assignment(assignment_id, assignment_span, assignee_cmt); } fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) { } @@ -782,16 +782,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { fn check_assignment(&self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, - mode: euv::MutateMode) { + assignee_cmt: mc::cmt<'tcx>) { debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); - // Initializations never cause borrow errors as they only - // affect a fresh local. - if mode == euv::Init { - return - } - // Check that we don't invalidate any outstanding loans if let Some(loan_path) = opt_loan_path(&assignee_cmt) { let scope = region::CodeExtent::from_node_id(assignment_id); @@ -801,17 +794,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { }); } - // Local variables can always be assigned to, expect for reassignments - // of immutable variables (or assignments that invalidate loans, - // of course). + // Check for reassignments to (immutable) local variables. This + // needs to be done here instead of in check_loans because we + // depend on move data. if let mc::cat_local(local_id) = assignee_cmt.cat { - if assignee_cmt.mutbl.is_mutable() { - self.tcx().used_mut_nodes.borrow_mut().insert(local_id); - } - let lp = opt_loan_path(&assignee_cmt).unwrap(); self.move_data.each_assignment_of(assignment_id, &lp, |assign| { - if !assignee_cmt.mutbl.is_mutable() { + if assignee_cmt.mutbl.is_mutable() { + self.tcx().used_mut_nodes.borrow_mut().insert(local_id); + } else { self.bccx.report_reassigned_immutable_variable( assignment_span, &*lp, diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index d86242f39ce..f747f2deec4 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -308,7 +308,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { debug!("process_method: {}:{}", id, token::get_name(name)); - let mut scope_id; + let scope_id; // 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(ast_util::local_def(id)) { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b6b5ac5c01e..507bd9de2a1 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -598,7 +598,7 @@ impl<'a> StringReader<'a> { /// Lex a LIT_INTEGER or a LIT_FLOAT fn scan_number(&mut self, c: char) -> token::Lit { - let mut num_digits; + let num_digits; let mut base = 10; let start_bpos = self.last_pos; diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index dcc82b8920f..8165dd0fa29 100644 --- a/src/test/compile-fail/lint-unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs @@ -23,6 +23,15 @@ fn main() { let mut b = 3; //~ ERROR: variable does not need to be mutable let mut a = vec!(3); //~ ERROR: variable does not need to be mutable let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable + let mut a; //~ ERROR: variable does not need to be mutable + a = 3; + + let mut b; //~ ERROR: variable does not need to be mutable + if true { + b = 3; + } else { + b = 4; + } match 30 { mut x => {} //~ ERROR: variable does not need to be mutable -- cgit 1.4.1-3-g733a5 From 7850c8d0aa14cd561fcdce816c94532a3d54ff60 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Tue, 30 Jun 2015 16:41:00 -0700 Subject: fallout of bitvec/bitset deprecation --- src/libcollections/bit.rs | 2 +- src/libcollections/lib.rs | 4 ++++ src/librustc_lint/builtin.rs | 3 +++ src/libsyntax/attr.rs | 3 +++ 4 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 7e7481e4f2f..a8d638028be 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deprecated(reason = "BitVec and BitSet have been migrated to cargo as bit-vec and bit-set", - since = "1.2.0")] + since = "1.3.0")] #![unstable(feature = "collections", reason = "deprecated")] #![allow(deprecated)] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 8d0f57de4c5..42adbe10e50 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -77,7 +77,9 @@ extern crate alloc; #[cfg(test)] extern crate test; pub use binary_heap::BinaryHeap; +#[allow(deprecated)] pub use bit_vec::BitVec; +#[allow(deprecated)] pub use bit_set::BitSet; pub use btree_map::BTreeMap; pub use btree_set::BTreeSet; @@ -111,11 +113,13 @@ pub mod vec_map; #[unstable(feature = "bitvec", reason = "RFC 509")] pub mod bit_vec { + #![allow(deprecated)] pub use bit::{BitVec, Iter}; } #[unstable(feature = "bitset", reason = "RFC 509")] pub mod bit_set { + #![allow(deprecated)] pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference}; pub use bit::SetIter as Iter; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 190e2965e76..577fe3979dd 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -28,6 +28,9 @@ //! Use the former for unit-like structs and the latter for structs with //! a `pub fn new()`. +// BitSet +#![allow(deprecated)] + use metadata::{csearch, decoder}; use middle::def::*; use middle::mem_categorization::Typer; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 3ee8ffe3636..3cc141106bb 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -10,6 +10,9 @@ // Functions dealing with attributes and meta items +// BitSet +#![allow(deprecated)] + pub use self::StabilityLevel::*; pub use self::ReprAttr::*; pub use self::IntType::*; -- cgit 1.4.1-3-g733a5 From 0b7c4f57f6ba59dabe4db2808fe45e8bd8bbce22 Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Tue, 30 Jun 2015 20:37:11 -0700 Subject: Add netbsd amd64 support --- configure | 4 ++ mk/cfg/x86_64-unknown-netbsd.mk | 22 +++++++ src/compiletest/util.rs | 1 + src/doc/reference.md | 2 +- src/etc/snapshot.py | 11 ++-- src/liblibc/lib.rs | 28 +++++---- src/librustc_back/arm.rs | 2 +- src/librustc_back/mips.rs | 2 +- src/librustc_back/mipsel.rs | 2 +- src/librustc_back/target/mod.rs | 2 + src/librustc_back/target/netbsd_base.rs | 32 ++++++++++ src/librustc_back/target/x86_64_unknown_netbsd.rs | 29 +++++++++ src/librustc_back/x86.rs | 2 +- src/librustc_back/x86_64.rs | 2 +- src/librustdoc/flock.rs | 1 + src/libstd/dynamic_lib.rs | 2 + src/libstd/env.rs | 12 ++++ src/libstd/net/tcp.rs | 2 +- src/libstd/net/udp.rs | 4 +- src/libstd/os/mod.rs | 1 + src/libstd/os/netbsd/mod.rs | 20 +++++++ src/libstd/os/netbsd/raw.rs | 71 +++++++++++++++++++++++ src/libstd/rt/args.rs | 1 + src/libstd/rt/libunwind.rs | 2 +- src/libstd/rtdeps.rs | 1 + src/libstd/sys/common/stack.rs | 2 + src/libstd/sys/unix/backtrace.rs | 1 + src/libstd/sys/unix/c.rs | 10 +++- src/libstd/sys/unix/mod.rs | 1 + src/libstd/sys/unix/os.rs | 15 +---- src/libstd/sys/unix/process.rs | 1 + src/libstd/sys/unix/stack_overflow.rs | 2 + src/libstd/sys/unix/sync.rs | 1 + src/libstd/sys/unix/thread.rs | 6 +- src/libstd/sys/unix/thread_local.rs | 2 + src/libstd/sys/unix/time.rs | 1 + src/libstd/thread/scoped_tls.rs | 3 + src/libsyntax/abi.rs | 2 + src/test/parse-fail/issue-5806.rs | 1 + src/test/run-pass/intrinsic-alignment.rs | 1 + src/test/run-pass/rec-align-u64.rs | 1 + src/test/run-pass/tcp-stress.rs | 3 +- src/test/run-pass/x86stdcall.rs | 1 + 43 files changed, 271 insertions(+), 41 deletions(-) create mode 100644 mk/cfg/x86_64-unknown-netbsd.mk create mode 100644 src/librustc_back/target/netbsd_base.rs create mode 100644 src/librustc_back/target/x86_64_unknown_netbsd.rs create mode 100644 src/libstd/os/netbsd/mod.rs create mode 100644 src/libstd/os/netbsd/raw.rs (limited to 'src/libsyntax') diff --git a/configure b/configure index 5d4a017b6fb..1d3611f88f0 100755 --- a/configure +++ b/configure @@ -405,6 +405,10 @@ case $CFG_OSTYPE in CFG_OSTYPE=unknown-openbsd ;; + NetBSD) + CFG_OSTYPE=unknown-netbsd + ;; + Darwin) CFG_OSTYPE=apple-darwin ;; diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk new file mode 100644 index 00000000000..401b0fb7ab0 --- /dev/null +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -0,0 +1,22 @@ +# x86_64-unknown-netbsd configuration +CC_x86_64-unknown-netbsd=$(CC) +CXX_x86_64-unknown-netbsd=$(CXX) +CPP_x86_64-unknown-netbsd=$(CPP) +AR_x86_64-unknown-netbsd=$(AR) +CFG_LIB_NAME_x86_64-unknown-netbsd=lib$(1).so +CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a +CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt +CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_x86_64-unknown-netbsd := +CFG_INSTALL_NAME_x86_64-unknown-netbsd = +CFG_EXE_SUFFIX_x86_64-unknown-netbsd := +CFG_WINDOWSY_x86_64-unknown-netbsd := +CFG_UNIXY_x86_64-unknown-netbsd := 1 +CFG_LDPATH_x86_64-unknown-netbsd := +CFG_RUN_x86_64-unknown-netbsd=$(2) +CFG_RUN_TARG_x86_64-unknown-netbsd=$(call CFG_RUN_x86_64-unknown-netbsd,,$(2)) +CFG_GNU_TRIPLE_x86_64-unknown-netbsd := x86_64-unknown-netbsd diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 184d62db451..13d6c029ff5 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -21,6 +21,7 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("ios", "ios"), ("linux", "linux"), ("mingw32", "windows"), + ("netbsd", "netbsd"), ("openbsd", "openbsd"), ("win32", "windows"), ("windows", "windows"), diff --git a/src/doc/reference.md b/src/doc/reference.md index 7e28651c6aa..650e1d5541e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2023,7 +2023,7 @@ The following configurations must be defined by the implementation: as a configuration itself, like `unix` or `windows`. * `target_os = "..."`. Operating system of the target, examples include `"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`, - `"bitrig"` or `"openbsd"`. + `"bitrig"` , `"openbsd"` or `"netbsd"`. * `target_pointer_width = "..."`. Target pointer width in bits. This is set to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit pointers. diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index 0349ccf9b66..6d62a45c703 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -41,13 +41,14 @@ download_dir_base = "dl" download_unpack_base = os.path.join(download_dir_base, "unpack") snapshot_files = { + "bitrig": ["bin/rustc"], + "dragonfly": ["bin/rustc"], + "freebsd": ["bin/rustc"], "linux": ["bin/rustc"], "macos": ["bin/rustc"], - "winnt": ["bin/rustc.exe"], - "freebsd": ["bin/rustc"], - "dragonfly": ["bin/rustc"], - "bitrig": ["bin/rustc"], + "netbsd": ["bin/rustc"], "openbsd": ["bin/rustc"], + "winnt": ["bin/rustc.exe"], } winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"] @@ -103,6 +104,8 @@ def get_kernel(triple): return "dragonfly" if os_name == "bitrig": return "bitrig" + if os_name == "netbsd": + return "netbsd" if os_name == "openbsd": return "openbsd" return "linux" diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 6e01796ad82..f66811e561a 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -1322,7 +1322,7 @@ pub mod types { } } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os ="openbsd"))] pub mod os { pub mod common { pub mod posix01 { @@ -1351,7 +1351,7 @@ pub mod types { pub __unused7: *mut c_void, } - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "netbsd", target_os="openbsd"))] #[repr(C)] #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: c_int, @@ -4323,7 +4323,7 @@ pub mod consts { } } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub mod os { pub mod c95 { use types::os::arch::c95::{c_int, c_uint}; @@ -5568,6 +5568,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "nacl"))] pub mod posix88 { @@ -5584,6 +5585,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -5602,6 +5604,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -5889,6 +5892,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "nacl"))] pub mod posix01 { @@ -5901,6 +5905,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "ios", @@ -6019,16 +6024,17 @@ pub mod funcs { } - #[cfg(any(target_os = "windows", - target_os = "linux", - target_os = "android", - target_os = "macos", + #[cfg(any(target_os = "android", + target_os = "bitrig", + target_os = "dragonfly", target_os = "ios", target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", + target_os = "linux", + target_os = "macos", + target_os = "nacl", + target_os = "netbsd", target_os = "openbsd", - target_os = "nacl"))] + target_os = "windows"))] pub mod posix08 { pub mod unistd { } @@ -6115,6 +6121,7 @@ pub mod funcs { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub mod bsd44 { use types::common::c95::{c_void}; @@ -6192,6 +6199,7 @@ pub mod funcs { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub mod extra { } diff --git a/src/librustc_back/arm.rs b/src/librustc_back/arm.rs index 7325e4e7a2e..9e288f6ddb2 100644 --- a/src/librustc_back/arm.rs +++ b/src/librustc_back/arm.rs @@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/mips.rs b/src/librustc_back/mips.rs index b46150f75d0..e1edff817d6 100644 --- a/src/librustc_back/mips.rs +++ b/src/librustc_back/mips.rs @@ -56,7 +56,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsBitrig | abi::OsDragonfly | abi::OsFreebsd | abi::OsNetbsd | abi::OsOpenbsd => { "E-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/mipsel.rs b/src/librustc_back/mipsel.rs index c7fa7aa879a..ca52a9e56ff 100644 --- a/src/librustc_back/mipsel.rs +++ b/src/librustc_back/mipsel.rs @@ -56,7 +56,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -a:0:64-n32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32:32\ -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index a42f861d190..bc5f306cd35 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -58,6 +58,7 @@ mod dragonfly_base; mod freebsd_base; mod linux_base; mod openbsd_base; +mod netbsd_base; mod windows_base; mod windows_msvc_base; @@ -368,6 +369,7 @@ impl Target { x86_64_unknown_bitrig, x86_64_unknown_openbsd, + x86_64_unknown_netbsd, x86_64_apple_darwin, i686_apple_darwin, diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs new file mode 100644 index 00000000000..0f2ab32be24 --- /dev/null +++ b/src/librustc_back/target/netbsd_base.rs @@ -0,0 +1,32 @@ +// Copyright 2014-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 target::TargetOptions; +use std::default::Default; + +pub fn opts() -> TargetOptions { + TargetOptions { + linker: "cc".to_string(), + dynamic_linking: true, + executables: true, + morestack: false, + linker_is_gnu: true, + has_rpath: true, + pre_link_args: vec!( + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + ), + position_independent_executables: true, + .. Default::default() + } +} diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs new file mode 100644 index 00000000000..3f5bd39949a --- /dev/null +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -0,0 +1,29 @@ +// Copyright 2014-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 target::Target; + +pub fn target() -> Target { + let mut base = super::netbsd_base::opts(); + base.pre_link_args.push("-m64".to_string()); + + Target { + data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ + s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), + llvm_target: "x86_64-unknown-netbsd".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + arch: "x86_64".to_string(), + target_os: "netbsd".to_string(), + target_env: "".to_string(), + options: base, + } +} diff --git a/src/librustc_back/x86.rs b/src/librustc_back/x86.rs index 1c6eacc3559..46e0a83ac03 100644 --- a/src/librustc_back/x86.rs +++ b/src/librustc_back/x86.rs @@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd | abi::OsNetbsd => { "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string() } diff --git a/src/librustc_back/x86_64.rs b/src/librustc_back/x86_64.rs index d016bd12c69..abdcd564442 100644 --- a/src/librustc_back/x86_64.rs +++ b/src/librustc_back/x86_64.rs @@ -47,7 +47,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } - abi::OsFreebsd | abi::OsDragonfly | abi::OsBitrig | abi::OsOpenbsd => { + abi::OsBitrig | abi::OsDragonfly | abi::OsFreebsd | abi::OsNetbsd | abi::OsOpenbsd => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 760fa329fd9..847e28d2bc5 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -68,6 +68,7 @@ mod imp { #[cfg(any(target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index a17d121e60a..3621d18daed 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -160,6 +160,7 @@ mod tests { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] fn test_errors_do_not_crash() { // Open /dev/null as a library to get an error, and make sure @@ -179,6 +180,7 @@ mod tests { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod dl { use prelude::v1::*; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 2e00e126e23..7c2cd615303 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -633,6 +633,7 @@ pub mod consts { /// - freebsd /// - dragonfly /// - bitrig + /// - netbsd /// - openbsd /// - android /// - windows @@ -759,6 +760,17 @@ mod os { pub const EXE_EXTENSION: &'static str = ""; } +#[cfg(target_os = "netbsd")] +mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "netbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + #[cfg(target_os = "openbsd")] mod os { pub const FAMILY: &'static str = "unix"; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 222059e4c0e..085ba286dc3 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -904,7 +904,7 @@ mod tests { // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index c3cf9895205..0545175d9ae 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -360,9 +360,9 @@ mod tests { assert_eq!(format!("{:?}", udpsock), compare); } - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index cc4b1c944e7..859cb900460 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -24,6 +24,7 @@ #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "nacl")] pub mod nacl; +#[cfg(target_os = "netbsd")] pub mod netbsd; #[cfg(target_os = "openbsd")] pub mod openbsd; pub mod raw; diff --git a/src/libstd/os/netbsd/mod.rs b/src/libstd/os/netbsd/mod.rs new file mode 100644 index 00000000000..bdb003b877b --- /dev/null +++ b/src/libstd/os/netbsd/mod.rs @@ -0,0 +1,20 @@ +// 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. + +//! OpenBSD-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; + +pub mod fs { + #![stable(feature = "raw_ext", since = "1.1.0")] + pub use sys::fs::MetadataExt; +} diff --git a/src/libstd/os/netbsd/raw.rs b/src/libstd/os/netbsd/raw.rs new file mode 100644 index 00000000000..f9898dfbdb5 --- /dev/null +++ b/src/libstd/os/netbsd/raw.rs @@ -0,0 +1,71 @@ +// 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. + +//! NetBSD/OpenBSD-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t}; + +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + +#[repr(C)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: blkcnt_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: blksize_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_flags: fflags_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gen: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime_nsec: c_long, +} diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index d23a124a6ec..52697f00264 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -44,6 +44,7 @@ pub fn clone() -> Option>> { imp::clone() } target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { use prelude::v1::*; diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs index 8f75ae5ef5c..d99b31c9f2b 100644 --- a/src/libstd/rt/libunwind.rs +++ b/src/libstd/rt/libunwind.rs @@ -106,7 +106,7 @@ extern {} #[link(name = "unwind", kind = "static")] extern {} -#[cfg(any(target_os = "android", target_os = "openbsd"))] +#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] #[link(name = "gcc")] extern {} diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index be674c83e22..a395dbf8995 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -39,6 +39,7 @@ extern {} #[cfg(any(target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[link(name = "pthread")] extern {} diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index 11982ebc572..002e3b20c35 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -202,6 +202,7 @@ pub unsafe fn record_sp_limit(limit: usize) { target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] unsafe fn target_record_sp_limit(_: usize) { } @@ -299,6 +300,7 @@ pub unsafe fn get_sp_limit() -> usize { target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[inline(always)] unsafe fn target_get_sp_limit() -> usize { diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index b23a3eee1a1..a5d1595cfeb 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -363,6 +363,7 @@ fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, let selfname = if cfg!(target_os = "freebsd") || cfg!(target_os = "dragonfly") || cfg!(target_os = "bitrig") || + cfg!(target_os = "netbsd") || cfg!(target_os = "openbsd") { env::current_exe().ok() } else { diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index 99a6731c57d..eeecf7f50f7 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -34,6 +34,7 @@ use libc; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const FIOCLEX: libc::c_ulong = 0x20006601; @@ -60,6 +61,7 @@ pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 70; target_os = "dragonfly"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71; #[cfg(any(target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 101; #[cfg(target_os = "android")] @@ -82,6 +84,7 @@ pub struct passwd { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub struct passwd { pub pw_name: *mut libc::c_char, @@ -321,6 +324,7 @@ mod signal_os { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod signal_os { use libc; @@ -348,7 +352,7 @@ mod signal_os { pub struct sigset_t { bits: [u32; 4], } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub type sigset_t = libc::c_uint; // This structure has more fields, but we're not all that interested in @@ -365,7 +369,7 @@ mod signal_os { pub _status: libc::c_int, pub si_addr: *mut libc::c_void } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct siginfo { pub si_signo: libc::c_int, @@ -375,7 +379,7 @@ mod signal_os { } #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "bitrig", target_os = "openbsd"))] + target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct sigaction { pub sa_sigaction: sighandler_t, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c1a4e8cee9e..6fd20b940bb 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -26,6 +26,7 @@ use ops::Neg; #[cfg(target_os = "linux")] pub use os::linux as platform; #[cfg(target_os = "macos")] pub use os::macos as platform; #[cfg(target_os = "nacl")] pub use os::nacl as platform; +#[cfg(target_os = "netbsd")] pub use os::netbsd as platform; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; pub mod backtrace; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5178d7b8fb1..334dd6b5f18 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -51,23 +51,13 @@ pub fn errno() -> i32 { __error() } - #[cfg(target_os = "bitrig")] - fn errno_location() -> *const c_int { - extern { - fn __errno() -> *const c_int; - } - unsafe { - __errno() - } - } - #[cfg(target_os = "dragonfly")] unsafe fn errno_location() -> *const c_int { extern { fn __dfly_error() -> *const c_int; } __dfly_error() } - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] unsafe fn errno_location() -> *const c_int { extern { fn __errno() -> *const c_int; } __errno() @@ -214,7 +204,7 @@ pub fn current_exe() -> io::Result { ::fs::read_link("/proc/curproc/file") } -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] +#[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub fn current_exe() -> io::Result { use sync::StaticMutex; static LOCK: StaticMutex = StaticMutex::new(); @@ -356,6 +346,7 @@ pub fn args() -> Args { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn args() -> Args { use rt; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 695d0ddfaaf..cc78dd4e5ef 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -423,6 +423,7 @@ fn translate_status(status: c_int) -> ExitStatus { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 52494a17b9d..62689c39255 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -35,6 +35,7 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { use sys_common::stack; @@ -149,6 +150,7 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] mod imp { use libc; diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 41e1e206a42..9c8a1f4ca40 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -55,6 +55,7 @@ extern { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index bb0e12e8df8..17804c8d81f 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -105,6 +105,7 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn set_name(name: &str) { extern { @@ -162,6 +163,7 @@ impl Drop for Thread { #[cfg(all(not(target_os = "linux"), not(target_os = "macos"), not(target_os = "bitrig"), + not(target_os = "netbsd"), not(target_os = "openbsd")))] pub mod guard { pub unsafe fn current() -> usize { 0 } @@ -173,6 +175,7 @@ pub mod guard { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { @@ -193,6 +196,7 @@ pub mod guard { #[cfg(any(target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] unsafe fn get_stack_start() -> *mut libc::c_void { current() as *mut libc::c_void @@ -258,7 +262,7 @@ pub mod guard { pthread_get_stacksize_np(pthread_self())) as usize } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] pub unsafe fn current() -> usize { #[repr(C)] struct stack_t { diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs index 3afe84b2580..7238adfcc56 100644 --- a/src/libstd/sys/unix/thread_local.rs +++ b/src/libstd/sys/unix/thread_local.rs @@ -46,6 +46,7 @@ type pthread_key_t = ::libc::c_ulong; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] type pthread_key_t = ::libc::c_int; @@ -54,6 +55,7 @@ type pthread_key_t = ::libc::c_int; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] type pthread_key_t = ::libc::c_uint; diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 6b84baeca7d..db0d0f15061 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -80,6 +80,7 @@ mod inner { // OpenBSD provide it via libc #[cfg(not(any(target_os = "android", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_env = "musl")))] #[link(name = "rt")] diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index 679902ec7ab..c2fad0aa89c 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -104,6 +104,7 @@ macro_rules! __scoped_thread_local_inner { #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64")), thread_local)] @@ -215,6 +216,7 @@ impl ScopedKey { #[cfg(not(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] @@ -238,6 +240,7 @@ mod imp { #[cfg(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64", no_elf_tls))] diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 27e331893e5..50c86a80b4a 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -25,6 +25,7 @@ pub enum Os { OsiOS, OsDragonfly, OsBitrig, + OsNetbsd, OsOpenbsd, } @@ -138,6 +139,7 @@ impl fmt::Display for Os { OsFreebsd => "freebsd".fmt(f), OsDragonfly => "dragonfly".fmt(f), OsBitrig => "bitrig".fmt(f), + OsNetbsd => "netbsd".fmt(f), OsOpenbsd => "openbsd".fmt(f), } } diff --git a/src/test/parse-fail/issue-5806.rs b/src/test/parse-fail/issue-5806.rs index f5442313904..f6606a58eca 100644 --- a/src/test/parse-fail/issue-5806.rs +++ b/src/test/parse-fail/issue-5806.rs @@ -11,6 +11,7 @@ // ignore-windows // ignore-freebsd // ignore-openbsd +// ignore-netbsd // ignore-bitrig // compile-flags: -Z parse-only diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index fa97ef8fcd3..ef69946d7aa 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -22,6 +22,7 @@ mod rusti { target_os = "macos", target_os = "freebsd", target_os = "dragonfly", + target_os = "netbsd", target_os = "openbsd"))] mod m { #[main] diff --git a/src/test/run-pass/rec-align-u64.rs b/src/test/run-pass/rec-align-u64.rs index bae95bcb50f..fc032aa3ff0 100644 --- a/src/test/run-pass/rec-align-u64.rs +++ b/src/test/run-pass/rec-align-u64.rs @@ -40,6 +40,7 @@ struct Outer { target_os = "macos", target_os = "freebsd", target_os = "dragonfly", + target_os = "netbsd", target_os = "openbsd"))] mod m { #[cfg(target_arch = "x86")] diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index c47b95bec2b..dca65f03f69 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -9,8 +9,9 @@ // except according to those terms. // ignore-android needs extra network permissions -// ignore-openbsd system ulimit (Too many open files) // ignore-bitrig system ulimit (Too many open files) +// ignore-netbsd system ulimit (Too many open files) +// ignore-openbsd system ulimit (Too many open files) use std::io::prelude::*; use std::net::{TcpListener, TcpStream}; diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs index b0bfb5c29c1..62cbb76c309 100644 --- a/src/test/run-pass/x86stdcall.rs +++ b/src/test/run-pass/x86stdcall.rs @@ -35,6 +35,7 @@ pub fn main() { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_os = "android"))] pub fn main() { } -- cgit 1.4.1-3-g733a5 From f3ba950a34885b366b79750237aca6ca3901cbc2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 3 Jul 2015 12:50:18 +1200 Subject: Refactor how the parser looks for sub-modules This makes the functionality usable from outside the parser --- src/libsyntax/parse/parser.rs | 176 ++++++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 68 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 03c788aee58..d19364f5f44 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,7 +60,7 @@ use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast; use ast_util::{self, AS_PREC, ident_to_path, operator_prec}; -use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp}; +use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap}; use diagnostic; use ext::tt::macro_parser; use parse; @@ -297,6 +297,24 @@ fn is_plain_ident_or_underscore(t: &token::Token) -> bool { t.is_plain_ident() || *t == token::Underscore } +/// Information about the path to a module. +pub struct ModulePath { + pub name: String, + pub path_exists: bool, + pub result: Result, +} + +pub struct ModulePathSuccess { + pub path: ::std::path::PathBuf, + pub owns_directory: bool, +} + +pub struct ModulePathError { + pub err_msg: String, + pub help_msg: String, +} + + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig, @@ -4861,82 +4879,104 @@ impl<'a> Parser<'a> { self.mod_path_stack.pop().unwrap(); } - /// Read a module from a source file. - fn eval_src_mod(&mut self, - id: ast::Ident, - outer_attrs: &[ast::Attribute], - id_sp: Span) - -> PResult<(ast::Item_, Vec )> { + pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option { + ::attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d)) + } + + /// Returns either a path to a module, or . + pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath + { + let mod_string = token::get_ident(id); + let mod_name = mod_string.to_string(); + let default_path_str = format!("{}.rs", mod_name); + let secondary_path_str = format!("{}/mod.rs", mod_name); + let default_path = dir_path.join(&default_path_str); + let secondary_path = dir_path.join(&secondary_path_str); + let default_exists = codemap.file_exists(&default_path); + let secondary_exists = codemap.file_exists(&secondary_path); + + let result = match (default_exists, secondary_exists) { + (true, false) => Ok(ModulePathSuccess { path: default_path, owns_directory: false }), + (false, true) => Ok(ModulePathSuccess { path: secondary_path, owns_directory: true }), + (false, false) => Err(ModulePathError { + err_msg: format!("file not found for module `{}`", mod_name), + help_msg: format!("name the file either {} or {} inside the directory {:?}", + default_path_str, + secondary_path_str, + dir_path.display()), + }), + (true, true) => Err(ModulePathError { + err_msg: format!("file for module `{}` found at both {} and {}", + mod_name, + default_path_str, + secondary_path_str), + help_msg: "delete or rename one of them to remove the ambiguity".to_owned(), + }), + }; + + ModulePath { + name: mod_name, + path_exists: default_exists || secondary_exists, + result: result, + } + } + + fn submod_path(&mut self, + id: ast::Ident, + outer_attrs: &[ast::Attribute], + id_sp: Span) -> PResult { let mut prefix = PathBuf::from(&self.sess.codemap().span_to_filename(self.span)); prefix.pop(); let mut dir_path = prefix; for part in &self.mod_path_stack { dir_path.push(&**part); } - let mod_string = token::get_ident(id); - let (file_path, owns_directory) = match ::attr::first_attr_value_str_by_name( - outer_attrs, "path") { - Some(d) => (dir_path.join(&*d), true), - None => { - let mod_name = mod_string.to_string(); - let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); - let default_path = dir_path.join(&default_path_str[..]); - let secondary_path = dir_path.join(&secondary_path_str[..]); - let default_exists = self.sess.codemap().file_exists(&default_path); - let secondary_exists = self.sess.codemap().file_exists(&secondary_path); - - if !self.owns_directory { - self.span_err(id_sp, - "cannot declare a new module at this location"); - let this_module = match self.mod_path_stack.last() { - Some(name) => name.to_string(), - None => self.root_module_name.as_ref().unwrap().clone(), - }; - self.span_note(id_sp, - &format!("maybe move this module `{0}` \ - to its own directory via \ - `{0}/mod.rs`", - this_module)); - if default_exists || secondary_exists { - self.span_note(id_sp, - &format!("... or maybe `use` the module \ - `{}` instead of possibly \ - redeclaring it", - mod_name)); - } - self.abort_if_errors(); - } - match (default_exists, secondary_exists) { - (true, false) => (default_path, false), - (false, true) => (secondary_path, true), - (false, false) => { - return Err(self.span_fatal_help(id_sp, - &format!("file not found for module `{}`", - mod_name), - &format!("name the file either {} or {} inside \ - the directory {:?}", - default_path_str, - secondary_path_str, - dir_path.display()))); - } - (true, true) => { - return Err(self.span_fatal_help( - id_sp, - &format!("file for module `{}` found at both {} \ - and {}", - mod_name, - default_path_str, - secondary_path_str), - "delete or rename one of them to remove the ambiguity")); - } - } + if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &dir_path) { + return Ok(ModulePathSuccess { path: p, owns_directory: true }); + } + + let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap()); + + if !self.owns_directory { + self.span_err(id_sp, "cannot declare a new module at this location"); + let this_module = match self.mod_path_stack.last() { + Some(name) => name.to_string(), + None => self.root_module_name.as_ref().unwrap().clone(), + }; + self.span_note(id_sp, + &format!("maybe move this module `{0}` to its own directory \ + via `{0}/mod.rs`", + this_module)); + if paths.path_exists { + self.span_note(id_sp, + &format!("... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name)); } - }; + self.abort_if_errors(); + } + + match paths.result { + Ok(succ) => Ok(succ), + Err(err) => Err(self.span_fatal_help(id_sp, &err.err_msg, &err.help_msg)), + } + } - self.eval_src_mod_from_path(file_path, owns_directory, - mod_string.to_string(), id_sp) + /// Read a module from a source file. + fn eval_src_mod(&mut self, + id: ast::Ident, + outer_attrs: &[ast::Attribute], + id_sp: Span) + -> PResult<(ast::Item_, Vec )> { + let ModulePathSuccess { path, owns_directory } = try!(self.submod_path(id, + outer_attrs, + id_sp)); + + self.eval_src_mod_from_path(path, + owns_directory, + token::get_ident(id).to_string(), + id_sp) } fn eval_src_mod_from_path(&mut self, -- cgit 1.4.1-3-g733a5 From 6a3b385cbd6b9044b4447da96aad066e8b257ddf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 1 Jul 2015 06:05:17 +0300 Subject: Feature-gate #[prelude_import]. --- src/librustc_driver/driver.rs | 2 +- src/libsyntax/feature_gate.rs | 6 ++- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax/std_inject.rs | 48 +++++++++++++++------- .../compile-fail/feature-gate-prelude_import.rs | 14 +++++++ src/test/pretty/issue-4264.pp | 2 +- 6 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-prelude_import.rs (limited to 'src/libsyntax') diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 80c4fc28703..ae6136a049a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -547,7 +547,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, sess.diagnostic())); krate = time(time_passes, "prelude injection", krate, |krate| - syntax::std_inject::maybe_inject_prelude(krate)); + syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate)); time(time_passes, "checking that all macro invocations are gone", &krate, |krate| syntax::ext::expand::check_for_macros(&sess.parse_sess, krate)); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3d0cf9236c2..ab8cf9ae6b6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -155,6 +155,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows the definition of `const fn` functions. ("const_fn", "1.2.0", Active), + + // Allows using #[prelude_import] on glob `use` items. + ("prelude_import", "1.2.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -265,7 +268,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ and may be removed in the future")), // used in resolve - ("prelude_import", Whitelisted), + ("prelude_import", Gated("prelude_import", + "`#[prelude_import]` is for use by rustc only")), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3adb73cfa5d..6693eed6ace 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -120,11 +120,13 @@ pub fn print_crate<'a>(cm: &'a CodeMap, // of the feature gate, so we fake them up here. let no_std_meta = attr::mk_word_item(InternedString::new("no_std")); + let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import")); // #![feature(no_std)] let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), attr::mk_list_item(InternedString::new("feature"), - vec![no_std_meta.clone()])); + vec![no_std_meta.clone(), + prelude_import_meta])); try!(s.print_attribute(&fake_attr)); // #![no_std] diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 021ec4738ed..36550586531 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,16 +10,35 @@ use ast; use attr; -use codemap::DUMMY_SP; +use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute}; use codemap; use fold::Folder; use fold; use parse::token::InternedString; use parse::token::special_idents; -use parse::token; +use parse::{token, ParseSess}; use ptr::P; use util::small_vector::SmallVector; +/// Craft a span that will be ignored by the stability lint's +/// call to codemap's is_internal check. +/// The expanded code uses the unstable `#[prelude_import]` attribute. +fn ignored_span(sess: &ParseSess, sp: Span) -> Span { + let info = ExpnInfo { + call_site: DUMMY_SP, + callee: NameAndSpan { + name: "std_inject".to_string(), + format: MacroAttribute, + span: None, + allow_internal_unstable: true, + } + }; + let expn_id = sess.codemap().record_expansion(info); + let mut sp = sp; + sp.expn_id = expn_id; + return sp; +} + pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option) -> ast::Crate { if use_std(&krate) { @@ -29,9 +48,12 @@ pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option) } } -pub fn maybe_inject_prelude(krate: ast::Crate) -> ast::Crate { +pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate { if use_std(&krate) { - inject_prelude(krate) + let mut fold = PreludeInjector { + span: ignored_span(sess, DUMMY_SP) + }; + fold.fold_crate(krate) } else { krate } @@ -80,8 +102,9 @@ fn inject_crates_ref(krate: ast::Crate, alt_std_name: Option) -> ast::Cr fold.fold_crate(krate) } -struct PreludeInjector; - +struct PreludeInjector { + span: Span +} impl fold::Folder for PreludeInjector { fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -107,7 +130,7 @@ impl fold::Folder for PreludeInjector { fn fold_mod(&mut self, mut mod_: ast::Mod) -> ast::Mod { let prelude_path = ast::Path { - span: DUMMY_SP, + span: self.span, global: false, segments: vec![ ast::PathSegment { @@ -131,12 +154,12 @@ impl fold::Folder for PreludeInjector { ident: special_idents::invalid, node: ast::ItemUse(vp), attrs: vec![ast::Attribute { - span: DUMMY_SP, + span: self.span, node: ast::Attribute_ { id: attr::mk_attr_id(), style: ast::AttrOuter, value: P(ast::MetaItem { - span: DUMMY_SP, + span: self.span, node: ast::MetaWord(token::get_name( special_idents::prelude_import.name)), }), @@ -144,14 +167,9 @@ impl fold::Folder for PreludeInjector { }, }], vis: ast::Inherited, - span: DUMMY_SP, + span: self.span, })); fold::noop_fold_mod(mod_, self) } } - -fn inject_prelude(krate: ast::Crate) -> ast::Crate { - let mut fold = PreludeInjector; - fold.fold_crate(krate) -} diff --git a/src/test/compile-fail/feature-gate-prelude_import.rs b/src/test/compile-fail/feature-gate-prelude_import.rs new file mode 100644 index 00000000000..8bc3df247ec --- /dev/null +++ b/src/test/compile-fail/feature-gate-prelude_import.rs @@ -0,0 +1,14 @@ +// 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. + +#[prelude_import] //~ ERROR `#[prelude_import]` is for use by rustc only +use std::prelude::v1::*; + +fn main() {} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index c2ed10ce6a1..5f7ce68348a 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -1,4 +1,4 @@ -#![feature(no_std)] +#![feature(no_std, prelude_import)] #![no_std] #[prelude_import] use std::prelude::v1::*; -- cgit 1.4.1-3-g733a5 From 69d340a40d0ca37e91731026bd5d7041a145aa34 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 2 Jul 2015 21:00:59 -0700 Subject: rustc: implement `unstable(issue = "nnn")`. This takes an issue number and points people to it in the printed error message. This commit does not make it an error to have no `issue` field. --- src/librustc/middle/stability.rs | 8 ++- src/libsyntax/attr.rs | 68 ++++++++++++++-------- src/test/auxiliary/stability_attribute_issue.rs | 20 +++++++ src/test/compile-fail/stability-attribute-issue.rs | 21 +++++++ 4 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 src/test/auxiliary/stability_attribute_issue.rs create mode 100644 src/test/compile-fail/stability-attribute-issue.rs (limited to 'src/libsyntax') diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e6bbae6405b..6d8f5ca42b0 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -289,15 +289,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { if !cross_crate { return } match *stab { - Some(&Stability { level: attr::Unstable, ref feature, ref reason, .. }) => { + Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => { self.used_features.insert(feature.clone(), attr::Unstable); if !self.active_features.contains(feature) { - let msg = match *reason { + let mut msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", &feature, &r), None => format!("use of unstable library feature '{}'", &feature) }; + if let Some(n) = issue { + use std::fmt::Write; + write!(&mut msg, " (see issue #{})", n).unwrap(); + } emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic, &feature, span, &msg); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 3ee8ffe3636..84fea8415ee 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -375,6 +375,8 @@ pub struct Stability { // The reason for the current stability level. If deprecated, the // reason for deprecation. pub reason: Option, + // The relevant rust-lang issue + pub issue: Option } /// The available stability levels. @@ -409,41 +411,54 @@ fn find_stability_generic<'a, used_attrs.push(attr); - let (feature, since, reason) = match attr.meta_item_list() { + let (feature, since, reason, issue) = match attr.meta_item_list() { Some(metas) => { let mut feature = None; let mut since = None; let mut reason = None; + let mut issue = None; for meta in metas { - if meta.name() == "feature" { - match meta.value_str() { - Some(v) => feature = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + match &*meta.name() { + "feature" => { + match meta.value_str() { + Some(v) => feature = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } - } - if &meta.name()[..] == "since" { - match meta.value_str() { - Some(v) => since = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + "since" => { + match meta.value_str() { + Some(v) => since = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } - } - if &meta.name()[..] == "reason" { - match meta.value_str() { - Some(v) => reason = Some(v), - None => { - diagnostic.span_err(meta.span, "incorrect meta item"); - continue 'outer; + "reason" => { + match meta.value_str() { + Some(v) => reason = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } + } + } + "issue" => { + match meta.value_str().and_then(|s| s.parse().ok()) { + Some(v) => issue = Some(v), + None => { + diagnostic.span_err(meta.span, "incorrect meta item"); + continue 'outer; + } } } + _ => {} } } - (feature, since, reason) + (feature, since, reason, issue) } None => { diagnostic.span_err(attr.span(), "incorrect stability attribute type"); @@ -477,7 +492,8 @@ fn find_stability_generic<'a, feature: feature.unwrap_or(intern_and_get_ident("bogus")), since: since, deprecated_since: None, - reason: reason + reason: reason, + issue: issue, }); } else { // "deprecated" if deprecated.is_some() { @@ -501,6 +517,12 @@ fn find_stability_generic<'a, either stable or unstable attribute"); } } + } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) { + // non-deprecated unstable items need to point to issues. + // FIXME: uncomment this error + // diagnostic.span_err(item_sp, + // "non-deprecated unstable items need to point \ + // to an issue with `issue = \"NNN\"`"); } (stab, used_attrs) diff --git a/src/test/auxiliary/stability_attribute_issue.rs b/src/test/auxiliary/stability_attribute_issue.rs new file mode 100644 index 00000000000..69560d15b5f --- /dev/null +++ b/src/test/auxiliary/stability_attribute_issue.rs @@ -0,0 +1,20 @@ +// 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. + +#![feature(staged_api)] +#![staged_api] +#![stable(feature = "foo", since = "1.2.0")] + + +#[unstable(feature = "foo", issue = "1")] +pub fn unstable() {} + +#[unstable(feature = "foo", reason = "message", issue = "2")] +pub fn unstable_msg() {} diff --git a/src/test/compile-fail/stability-attribute-issue.rs b/src/test/compile-fail/stability-attribute-issue.rs new file mode 100644 index 00000000000..c473bdd23b5 --- /dev/null +++ b/src/test/compile-fail/stability-attribute-issue.rs @@ -0,0 +1,21 @@ +// Copyright 2013-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. + +// aux-build:stability_attribute_issue.rs + +#![deny(deprecated)] + +extern crate stability_attribute_issue; +use stability_attribute_issue::*; + +fn main() { + unstable(); //~ ERROR use of unstable library feature 'foo' (see issue #1) + unstable_msg(); //~ ERROR use of unstable library feature 'foo': message (see issue #2) +} -- cgit 1.4.1-3-g733a5 From e08c5f751578520c013d4838f0e288af937caf0d Mon Sep 17 00:00:00 2001 From: P1start Date: Tue, 7 Jul 2015 11:11:20 +1200 Subject: Change some free functions into methods in libsyntax/diagnostic.rs --- src/libsyntax/diagnostic.rs | 788 ++++++++++++++++++++++---------------------- 1 file changed, 392 insertions(+), 396 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index ec93d2c5536..fbf015169f8 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -308,63 +308,6 @@ impl Level { } } -fn print_maybe_styled(w: &mut EmitterWriter, - msg: &str, - color: term::attr::Attr) -> io::Result<()> { - match w.dst { - Terminal(ref mut t) => { - try!(t.attr(color)); - // If `msg` ends in a newline, we need to reset the color before - // the newline. We're making the assumption that we end up writing - // to a `LineBufferedWriter`, which means that emitting the reset - // after the newline ends up buffering the reset until we print - // another line or exit. Buffering the reset is a problem if we're - // sharing the terminal with any other programs (e.g. other rustc - // instances via `make -jN`). - // - // Note that if `msg` contains any internal newlines, this will - // result in the `LineBufferedWriter` flushing twice instead of - // once, which still leaves the opportunity for interleaved output - // to be miscolored. We assume this is rare enough that we don't - // have to worry about it. - if msg.ends_with("\n") { - try!(t.write_all(msg[..msg.len()-1].as_bytes())); - try!(t.reset()); - try!(t.write_all(b"\n")); - } else { - try!(t.write_all(msg.as_bytes())); - try!(t.reset()); - } - Ok(()) - } - Raw(ref mut w) => w.write_all(msg.as_bytes()), - } -} - -fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, - msg: &str, code: Option<&str>) -> io::Result<()> { - if !topic.is_empty() { - try!(write!(&mut dst.dst, "{} ", topic)); - } - - try!(print_maybe_styled(dst, - &format!("{}: ", lvl.to_string()), - term::attr::ForegroundColor(lvl.color()))); - try!(print_maybe_styled(dst, - &format!("{}", msg), - term::attr::Bold)); - - match code { - Some(code) => { - let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); - try!(print_maybe_styled(dst, &format!(" [{}]", code.clone()), style)); - } - None => () - } - try!(write!(&mut dst.dst, "\n")); - Ok(()) -} - pub struct EmitterWriter { dst: Destination, registry: Option @@ -401,6 +344,392 @@ impl EmitterWriter { registry: Option) -> EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry } } + + fn print_maybe_styled(&mut self, + msg: &str, + color: term::attr::Attr) -> io::Result<()> { + match self.dst { + Terminal(ref mut t) => { + try!(t.attr(color)); + // If `msg` ends in a newline, we need to reset the color before + // the newline. We're making the assumption that we end up writing + // to a `LineBufferedWriter`, which means that emitting the reset + // after the newline ends up buffering the reset until we print + // another line or exit. Buffering the reset is a problem if we're + // sharing the terminal with any other programs (e.g. other rustc + // instances via `make -jN`). + // + // Note that if `msg` contains any internal newlines, this will + // result in the `LineBufferedWriter` flushing twice instead of + // once, which still leaves the opportunity for interleaved output + // to be miscolored. We assume this is rare enough that we don't + // have to worry about it. + if msg.ends_with("\n") { + try!(t.write_all(msg[..msg.len()-1].as_bytes())); + try!(t.reset()); + try!(t.write_all(b"\n")); + } else { + try!(t.write_all(msg.as_bytes())); + try!(t.reset()); + } + Ok(()) + } + Raw(ref mut w) => w.write_all(msg.as_bytes()), + } + } + + fn print_diagnostic(&mut self, topic: &str, lvl: Level, + msg: &str, code: Option<&str>) -> io::Result<()> { + if !topic.is_empty() { + try!(write!(&mut self.dst, "{} ", topic)); + } + + try!(self.print_maybe_styled(&format!("{}: ", lvl.to_string()), + term::attr::ForegroundColor(lvl.color()))); + try!(self.print_maybe_styled(&format!("{}", msg), + term::attr::Bold)); + + match code { + Some(code) => { + let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(self.print_maybe_styled(&format!(" [{}]", code.clone()), style)); + } + None => () + } + try!(write!(&mut self.dst, "\n")); + Ok(()) + } + + fn emit_(&mut self, cm: &codemap::CodeMap, rsp: RenderSpan, + msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { + let sp = rsp.span(); + + // We cannot check equality directly with COMMAND_LINE_SP + // since PartialEq is manually implemented to ignore the ExpnId + let ss = if sp.expn_id == COMMAND_LINE_EXPN { + "".to_string() + } else if let EndSpan(_) = rsp { + let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; + cm.span_to_string(span_end) + } else { + cm.span_to_string(sp) + }; + + try!(self.print_diagnostic(&ss[..], lvl, msg, code)); + + match rsp { + FullSpan(_) => { + try!(self.highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); + try!(self.print_macro_backtrace(cm, sp)); + } + EndSpan(_) => { + try!(self.end_highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); + try!(self.print_macro_backtrace(cm, sp)); + } + Suggestion(_, ref suggestion) => { + try!(self.highlight_suggestion(cm, sp, suggestion)); + try!(self.print_macro_backtrace(cm, sp)); + } + FileLine(..) => { + // no source text in this case! + } + } + + match code { + Some(code) => + match self.registry.as_ref().and_then(|registry| registry.find_description(code)) { + Some(_) => { + try!(self.print_diagnostic(&ss[..], Help, + &format!("run `rustc --explain {}` to see a \ + detailed explanation", code), None)); + } + None => () + }, + None => (), + } + Ok(()) + } + + fn highlight_suggestion(&mut self, + cm: &codemap::CodeMap, + sp: Span, + suggestion: &str) + -> io::Result<()> + { + let lines = cm.span_to_lines(sp).unwrap(); + assert!(!lines.lines.is_empty()); + + // To build up the result, we want to take the snippet from the first + // line that precedes the span, prepend that with the suggestion, and + // then append the snippet from the last line that trails the span. + let fm = &lines.file; + + let first_line = &lines.lines[0]; + let prefix = fm.get_line(first_line.line_index) + .map(|l| &l[..first_line.start_col.0]) + .unwrap_or(""); + + let last_line = lines.lines.last().unwrap(); + let suffix = fm.get_line(last_line.line_index) + .map(|l| &l[last_line.end_col.0..]) + .unwrap_or(""); + + let complete = format!("{}{}{}", prefix, suggestion, suffix); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let fm = &*lines.file; + let mut lines = complete.lines(); + for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { + let elided_line_num = format!("{}", line_index+1); + try!(write!(&mut self.dst, "{0}:{1:2$} {3}\n", + fm.name, "", elided_line_num.len(), line)); + } + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); + try!(write!(&mut self.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), elided_line_num.len())); + } + + Ok(()) + } + + fn highlight_lines(&mut self, + cm: &codemap::CodeMap, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> + { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let line_strings: Option> = + lines.lines.iter() + .map(|info| fm.get_line(info.line_index)) + .collect(); + + let line_strings = match line_strings { + None => { return Ok(()); } + Some(line_strings) => line_strings + }; + + // Display only the first MAX_LINES lines. + let all_lines = lines.lines.len(); + let display_lines = cmp::min(all_lines, MAX_LINES); + let display_line_infos = &lines.lines[..display_lines]; + let display_line_strings = &line_strings[..display_lines]; + + // Calculate the widest number to format evenly and fix #11715 + assert!(display_line_infos.len() > 0); + let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; + let mut digits = 0; + while max_line_num > 0 { + max_line_num /= 10; + digits += 1; + } + + // Print the offending lines + for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { + try!(write!(&mut self.dst, "{}:{:>width$} {}\n", + fm.name, + line_info.line_index + 1, + line, + width=digits)); + } + + // If we elided something, put an ellipsis. + if display_lines < all_lines { + let last_line_index = display_line_infos.last().unwrap().line_index; + let s = format!("{}:{} ", fm.name, last_line_index + 1); + try!(write!(&mut self.dst, "{0:1$}...\n", "", s.len())); + } + + // FIXME (#3260) + // If there's one line at fault we can easily point to the problem + if lines.lines.len() == 1 { + let lo = cm.lookup_char_pos(sp.lo); + let mut digits = 0; + let mut num = (lines.lines[0].line_index + 1) / 10; + + // how many digits must be indent past? + while num > 0 { num /= 10; digits += 1; } + + let mut s = String::new(); + // Skip is the number of characters we need to skip because they are + // part of the 'filename:line ' part of the previous line. + let skip = fm.name.chars().count() + digits + 3; + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines.lines[0].line_index) { + let mut col = skip; + let mut lastc = ' '; + let mut iter = orig.chars().enumerate(); + for (pos, ch) in iter.by_ref() { + lastc = ch; + if pos >= lo.col.to_usize() { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => { + col += 8 - col%8; + s.push('\t'); + }, + _ => { + col += 1; + s.push(' '); + }, + } + } + + try!(write!(&mut self.dst, "{}", s)); + let mut s = String::from("^"); + let count = match lastc { + // Most terminals have a tab stop every eight columns by default + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + + let hi = cm.lookup_char_pos(sp.hi); + if hi.col != lo.col { + for (pos, ch) in iter { + if pos >= hi.col.to_usize() { break; } + let count = match ch { + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + } + } + + if s.len() > 1 { + // One extra squiggly is replaced by a "^" + s.pop(); + } + + try!(self.print_maybe_styled(&format!("{}\n", s), + term::attr::ForegroundColor(lvl.color()))); + } + } + Ok(()) + } + + /// Here are the differences between this and the normal `highlight_lines`: + /// `end_highlight_lines` will always put arrow on the last byte of the + /// span (instead of the first byte). Also, when the span is too long (more + /// than 6 lines), `end_highlight_lines` will print the first line, then + /// dot dot dot, then last line, whereas `highlight_lines` prints the first + /// six lines. + #[allow(deprecated)] + fn end_highlight_lines(&mut self, + cm: &codemap::CodeMap, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let lines = &lines.lines[..]; + if lines.len() > MAX_LINES { + if let Some(line) = fm.get_line(lines[0].line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + lines[0].line_index + 1, line)); + } + try!(write!(&mut self.dst, "...\n")); + let last_line_index = lines[lines.len() - 1].line_index; + if let Some(last_line) = fm.get_line(last_line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + last_line_index + 1, last_line)); + } + } else { + for line_info in lines { + if let Some(line) = fm.get_line(line_info.line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + line_info.line_index + 1, line)); + } + } + } + let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); + let hi = cm.lookup_char_pos(sp.hi); + let skip = last_line_start.chars().count(); + let mut s = String::new(); + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines[0].line_index) { + let iter = orig.chars().enumerate(); + for (pos, ch) in iter { + // Span seems to use half-opened interval, so subtract 1 + if pos >= hi.col.to_usize() - 1 { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => s.push('\t'), + _ => s.push(' '), + } + } + } + s.push('^'); + s.push('\n'); + self.print_maybe_styled(&s[..], + term::attr::ForegroundColor(lvl.color())) + } + + fn print_macro_backtrace(&mut self, + cm: &codemap::CodeMap, + sp: Span) + -> io::Result<()> { + let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> { + match expn_info { + Some(ei) => { + let ss = ei.callee.span.map_or(String::new(), + |span| cm.span_to_string(span)); + let (pre, post) = match ei.callee.format { + codemap::MacroAttribute => ("#[", "]"), + codemap::MacroBang => ("", "!"), + codemap::CompilerExpansion => ("", ""), + }; + try!(self.print_diagnostic(&ss, Note, + &format!("in expansion of {}{}{}", + pre, + ei.callee.name, + post), + None)); + let ss = cm.span_to_string(ei.call_site); + try!(self.print_diagnostic(&ss, Note, "expansion site", None)); + Ok(Some(ei.call_site)) + } + None => Ok(None) + } + })); + cs.map_or(Ok(()), |call_site| self.print_macro_backtrace(cm, call_site)) + } } #[cfg(unix)] @@ -442,11 +771,11 @@ impl Emitter for EmitterWriter { cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, code: Option<&str>, lvl: Level) { let error = match cmsp { - Some((cm, COMMAND_LINE_SP)) => emit(self, cm, + Some((cm, COMMAND_LINE_SP)) => self.emit_(cm, FileLine(COMMAND_LINE_SP), msg, code, lvl), - Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl), - None => print_diagnostic(self, "", lvl, msg, code), + Some((cm, sp)) => self.emit_(cm, FullSpan(sp), msg, code, lvl), + None => self.print_diagnostic("", lvl, msg, code), }; match error { @@ -457,346 +786,13 @@ impl Emitter for EmitterWriter { fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { - match emit(self, cm, sp, msg, None, lvl) { + match self.emit_(cm, sp, msg, None, lvl) { Ok(()) => {} Err(e) => panic!("failed to print diagnostics: {:?}", e), } } } -fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { - let sp = rsp.span(); - - // We cannot check equality directly with COMMAND_LINE_SP - // since PartialEq is manually implemented to ignore the ExpnId - let ss = if sp.expn_id == COMMAND_LINE_EXPN { - "".to_string() - } else if let EndSpan(_) = rsp { - let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; - cm.span_to_string(span_end) - } else { - cm.span_to_string(sp) - }; - - try!(print_diagnostic(dst, &ss[..], lvl, msg, code)); - - match rsp { - FullSpan(_) => { - try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); - try!(print_macro_backtrace(dst, cm, sp)); - } - EndSpan(_) => { - try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); - try!(print_macro_backtrace(dst, cm, sp)); - } - Suggestion(_, ref suggestion) => { - try!(highlight_suggestion(dst, cm, sp, suggestion)); - try!(print_macro_backtrace(dst, cm, sp)); - } - FileLine(..) => { - // no source text in this case! - } - } - - match code { - Some(code) => - match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { - Some(_) => { - try!(print_diagnostic(dst, &ss[..], Help, - &format!("run `rustc --explain {}` to see a detailed \ - explanation", code), None)); - } - None => () - }, - None => (), - } - Ok(()) -} - -fn highlight_suggestion(err: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - suggestion: &str) - -> io::Result<()> -{ - let lines = cm.span_to_lines(sp).unwrap(); - assert!(!lines.lines.is_empty()); - - // To build up the result, we want to take the snippet from the first - // line that precedes the span, prepend that with the suggestion, and - // then append the snippet from the last line that trails the span. - let fm = &lines.file; - - let first_line = &lines.lines[0]; - let prefix = fm.get_line(first_line.line_index) - .map(|l| &l[..first_line.start_col.0]) - .unwrap_or(""); - - let last_line = lines.lines.last().unwrap(); - let suffix = fm.get_line(last_line.line_index) - .map(|l| &l[last_line.end_col.0..]) - .unwrap_or(""); - - let complete = format!("{}{}{}", prefix, suggestion, suffix); - - // print the suggestion without any line numbers, but leave - // space for them. This helps with lining up with previous - // snippets from the actual error being reported. - let fm = &*lines.file; - let mut lines = complete.lines(); - for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { - let elided_line_num = format!("{}", line_index+1); - try!(write!(&mut err.dst, "{0}:{1:2$} {3}\n", - fm.name, "", elided_line_num.len(), line)); - } - - // if we elided some lines, add an ellipsis - if lines.next().is_some() { - let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); - try!(write!(&mut err.dst, "{0:1$} {0:2$} ...\n", - "", fm.name.len(), elided_line_num.len())); - } - - Ok(()) -} - -fn highlight_lines(err: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - lvl: Level, - lines: codemap::FileLinesResult) - -> io::Result<()> -{ - let lines = match lines { - Ok(lines) => lines, - Err(_) => { - try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n")); - return Ok(()); - } - }; - - let fm = &*lines.file; - - let line_strings: Option> = - lines.lines.iter() - .map(|info| fm.get_line(info.line_index)) - .collect(); - - let line_strings = match line_strings { - None => { return Ok(()); } - Some(line_strings) => line_strings - }; - - // Display only the first MAX_LINES lines. - let all_lines = lines.lines.len(); - let display_lines = cmp::min(all_lines, MAX_LINES); - let display_line_infos = &lines.lines[..display_lines]; - let display_line_strings = &line_strings[..display_lines]; - - // Calculate the widest number to format evenly and fix #11715 - assert!(display_line_infos.len() > 0); - let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; - let mut digits = 0; - while max_line_num > 0 { - max_line_num /= 10; - digits += 1; - } - - // Print the offending lines - for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { - try!(write!(&mut err.dst, "{}:{:>width$} {}\n", - fm.name, - line_info.line_index + 1, - line, - width=digits)); - } - - // If we elided something, put an ellipsis. - if display_lines < all_lines { - let last_line_index = display_line_infos.last().unwrap().line_index; - let s = format!("{}:{} ", fm.name, last_line_index + 1); - try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len())); - } - - // FIXME (#3260) - // If there's one line at fault we can easily point to the problem - if lines.lines.len() == 1 { - let lo = cm.lookup_char_pos(sp.lo); - let mut digits = 0; - let mut num = (lines.lines[0].line_index + 1) / 10; - - // how many digits must be indent past? - while num > 0 { num /= 10; digits += 1; } - - let mut s = String::new(); - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the previous line. - let skip = fm.name.chars().count() + digits + 3; - for _ in 0..skip { - s.push(' '); - } - if let Some(orig) = fm.get_line(lines.lines[0].line_index) { - let mut col = skip; - let mut lastc = ' '; - let mut iter = orig.chars().enumerate(); - for (pos, ch) in iter.by_ref() { - lastc = ch; - if pos >= lo.col.to_usize() { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => { - col += 8 - col%8; - s.push('\t'); - }, - _ => { - col += 1; - s.push(' '); - }, - } - } - - try!(write!(&mut err.dst, "{}", s)); - let mut s = String::from("^"); - let count = match lastc { - // Most terminals have a tab stop every eight columns by default - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - let hi = cm.lookup_char_pos(sp.hi); - if hi.col != lo.col { - for (pos, ch) in iter { - if pos >= hi.col.to_usize() { break; } - let count = match ch { - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - } - } - - if s.len() > 1 { - // One extra squiggly is replaced by a "^" - s.pop(); - } - - try!(print_maybe_styled(err, - &format!("{}\n", s), - term::attr::ForegroundColor(lvl.color()))); - } - } - Ok(()) -} - -/// Here are the differences between this and the normal `highlight_lines`: -/// `end_highlight_lines` will always put arrow on the last byte of the -/// span (instead of the first byte). Also, when the span is too long (more -/// than 6 lines), `end_highlight_lines` will print the first line, then -/// dot dot dot, then last line, whereas `highlight_lines` prints the first -/// six lines. -#[allow(deprecated)] -fn end_highlight_lines(w: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - lvl: Level, - lines: codemap::FileLinesResult) - -> io::Result<()> { - let lines = match lines { - Ok(lines) => lines, - Err(_) => { - try!(write!(&mut w.dst, "(internal compiler error: unprintable span)\n")); - return Ok(()); - } - }; - - let fm = &*lines.file; - - let lines = &lines.lines[..]; - if lines.len() > MAX_LINES { - if let Some(line) = fm.get_line(lines[0].line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - lines[0].line_index + 1, line)); - } - try!(write!(&mut w.dst, "...\n")); - let last_line_index = lines[lines.len() - 1].line_index; - if let Some(last_line) = fm.get_line(last_line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - last_line_index + 1, last_line)); - } - } else { - for line_info in lines { - if let Some(line) = fm.get_line(line_info.line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - line_info.line_index + 1, line)); - } - } - } - let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); - let hi = cm.lookup_char_pos(sp.hi); - let skip = last_line_start.chars().count(); - let mut s = String::new(); - for _ in 0..skip { - s.push(' '); - } - if let Some(orig) = fm.get_line(lines[0].line_index) { - let iter = orig.chars().enumerate(); - for (pos, ch) in iter { - // Span seems to use half-opened interval, so subtract 1 - if pos >= hi.col.to_usize() - 1 { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => s.push('\t'), - _ => s.push(' '), - } - } - } - s.push('^'); - s.push('\n'); - print_maybe_styled(w, - &s[..], - term::attr::ForegroundColor(lvl.color())) -} - -fn print_macro_backtrace(w: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span) - -> io::Result<()> { - let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> { - match expn_info { - Some(ei) => { - let ss = ei.callee.span.map_or(String::new(), - |span| cm.span_to_string(span)); - let (pre, post) = match ei.callee.format { - codemap::MacroAttribute => ("#[", "]"), - codemap::MacroBang => ("", "!"), - codemap::CompilerExpansion => ("", ""), - }; - try!(print_diagnostic(w, &ss, Note, - &format!("in expansion of {}{}{}", - pre, - ei.callee.name, - post), - None)); - let ss = cm.span_to_string(ei.call_site); - try!(print_diagnostic(w, &ss, Note, "expansion site", None)); - Ok(Some(ei.call_site)) - } - None => Ok(None) - } - })); - cs.map_or(Ok(()), |call_site| print_macro_backtrace(w, cm, call_site)) -} - pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where M: FnOnce() -> String, { @@ -808,7 +804,7 @@ pub fn expect(diag: &SpanHandler, opt: Option, msg: M) -> T where #[cfg(test)] mod test { - use super::{EmitterWriter, highlight_lines, Level}; + use super::{EmitterWriter, Level}; use codemap::{mk_sp, CodeMap, BytePos}; use std::sync::{Arc, Mutex}; use std::io::{self, Write}; @@ -854,7 +850,7 @@ mod test { println!("span_to_lines"); let lines = cm.span_to_lines(sp); println!("highlight_lines"); - highlight_lines(&mut ew, &cm, sp, lvl, lines).unwrap(); + ew.highlight_lines(&cm, sp, lvl, lines).unwrap(); println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; -- cgit 1.4.1-3-g733a5 From 84cb4ad96994dd8a0dd0d8827834526b0184ca82 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Jul 2015 14:29:43 +1200 Subject: Fix a bug where macros in expression position don't have expansion inidices in their spans --- src/libsyntax/ext/expand.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4aa313f3e66..a4855ddcb25 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -60,14 +60,14 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }; // Keep going, outside-in. - // let fully_expanded = fld.fold_expr(expanded_expr); + let span = fld.new_span(span); fld.cx.bt_pop(); fully_expanded.map(|e| ast::Expr { id: ast::DUMMY_NODE_ID, node: e.node, - span: fld.new_span(span), + span: span, }) } @@ -367,7 +367,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { /// of expansion and the mark which must be applied to the result. /// Our current interface doesn't allow us to apply the mark to the /// result until after calling make_expr, make_items, etc. -fn expand_mac_invoc(mac: ast::Mac, span: codemap::Span, +fn expand_mac_invoc(mac: ast::Mac, + span: codemap::Span, parse_thunk: F, mark_thunk: G, fld: &mut MacroExpander) -- cgit 1.4.1-3-g733a5 From 374af4aea7878127ca52cbc271fb1237b4afe223 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Jul 2015 14:30:18 +1200 Subject: save-analysis: API-ify paths --- src/librustc_trans/save/dump_csv.rs | 127 +++++++++++++----------------------- src/librustc_trans/save/mod.rs | 104 ++++++++++++++++++++++++++++- src/libsyntax/ext/expand.rs | 2 +- 3 files changed, 147 insertions(+), 86 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index cf033ff0806..23bab3fe5b7 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -28,7 +28,7 @@ //! DumpCsvVisitor walks the AST and processes it. -use super::{escape, generated_code, recorder, SaveContext, PathCollector}; +use super::{escape, generated_code, recorder, SaveContext, PathCollector, Data}; use session::Session; @@ -738,90 +738,51 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_path(&mut self, id: NodeId, - span: Span, path: &ast::Path, ref_kind: Option) { - if generated_code(span) { - return + if generated_code(path.span) { + return; } - let def_map = self.tcx.def_map.borrow(); - if !def_map.contains_key(&id) { - self.sess.span_bug(span, - &format!("def_map has no key for {} in visit_expr", id)); - } - let def = def_map.get(&id).unwrap().full_def(); - let sub_span = self.span.span_for_last_ident(span); - match def { - def::DefUpvar(..) | - def::DefLocal(..) | - def::DefStatic(..) | - def::DefConst(..) | - def::DefAssociatedConst(..) | - def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), - span, - sub_span, - def.def_id(), - self.cur_scope), - def::DefStruct(def_id) => self.fmt.ref_str(recorder::TypeRef, - span, - sub_span, - def_id, - self.cur_scope), - def::DefTy(def_id, _) => self.fmt.ref_str(recorder::TypeRef, - span, - sub_span, - def_id, - self.cur_scope), - def::DefMethod(declid, provenence) => { - let sub_span = self.span.sub_span_for_meth_name(span); - let defid = if declid.krate == ast::LOCAL_CRATE { - let ti = self.tcx.impl_or_trait_item(declid); - match provenence { - def::FromTrait(def_id) => { - Some(self.tcx.trait_items(def_id) - .iter() - .find(|mr| { - mr.name() == ti.name() - }) - .unwrap() - .def_id()) - } - def::FromImpl(def_id) => { - let impl_items = self.tcx.impl_items.borrow(); - Some(impl_items.get(&def_id) - .unwrap() - .iter() - .find(|mr| { - self.tcx.impl_or_trait_item(mr.def_id()).name() - == ti.name() - }) - .unwrap() - .def_id()) - } - } - } else { - None - }; - self.fmt.meth_call_str(span, - sub_span, - defid, - Some(declid), - self.cur_scope); - }, - def::DefFn(def_id, _) => { - self.fmt.fn_call_str(span, - sub_span, - def_id, - self.cur_scope) + let path_data = self.save_ctxt.get_path_data(id, path); + match path_data { + Data::VariableRefData(ref vrd) => { + self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), + path.span, + Some(vrd.span), + vrd.ref_id, + vrd.scope); + + } + Data::TypeRefData(ref trd) => { + self.fmt.ref_str(recorder::TypeRef, + path.span, + Some(trd.span), + trd.ref_id, + trd.scope); + } + Data::MethodCallData(ref mcd) => { + self.fmt.meth_call_str(path.span, + Some(mcd.span), + mcd.ref_id, + mcd.decl_id, + mcd.scope); + } + Data::FunctionCallData(fcd) => { + self.fmt.fn_call_str(path.span, + Some(fcd.span), + fcd.ref_id, + fcd.scope); + } + _ => { + self.sess.span_bug(path.span, + &format!("Unexpected data: {:?}", path_data)); } - _ => self.sess.span_bug(span, - &format!("Unexpected def kind while looking \ - up path in `{}`: `{:?}`", - self.span.snippet(span), - def)), } - // modules or types in the path prefix + + // Modules or types in the path prefix. + let def_map = self.tcx.def_map.borrow(); + let def = def_map.get(&id).unwrap().full_def(); match def { def::DefMethod(did, _) => { let ti = self.tcx.impl_or_trait_item(did); @@ -1187,7 +1148,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { visit::walk_expr(self, ex); } ast::ExprPath(_, ref path) => { - self.process_path(ex.id, path.span, path, None); + self.process_path(ex.id, path, None); visit::walk_expr(self, ex); } ast::ExprStruct(ref path, ref fields, ref base) => @@ -1283,6 +1244,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { // This is to get around borrow checking, because we need mut self to call process_path. let mut paths_to_process = vec![]; + // process collected paths for &(id, ref p, immut, ref_kind) in &collector.collected_paths { let def_map = self.tcx.def_map.borrow(); @@ -1319,11 +1281,12 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { def) } } + for &(id, ref path, ref_kind) in &paths_to_process { - self.process_path(id, path.span, path, ref_kind); + self.process_path(id, path, ref_kind); } visit::walk_expr_opt(self, &arm.guard); - self.visit_expr(&*arm.body); + self.visit_expr(&arm.body); } fn visit_stmt(&mut self, s: &ast::Stmt) { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 5d080924e50..239e5966a71 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -61,6 +61,8 @@ pub enum Data { VariableRefData(VariableRefData), /// Data for a reference to a type or trait. TypeRefData(TypeRefData), + /// Data about a function call. + FunctionCallData(FunctionCallData), /// Data about a method call. MethodCallData(MethodCallData), } @@ -122,7 +124,7 @@ pub struct ImplData { } /// Data for the use of some item (e.g., the use of a local variable, which -/// will refere to that variables declaration (by ref_id)). +/// will refer to that variables declaration (by ref_id)). #[derive(Debug)] pub struct VariableRefData { pub name: String, @@ -139,6 +141,14 @@ pub struct TypeRefData { pub ref_id: DefId, } +/// Data about a function call. +#[derive(Debug)] +pub struct FunctionCallData { + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + /// Data about a method call. #[derive(Debug)] pub struct MethodCallData { @@ -392,13 +402,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ty::TraitContainer(_) => (None, Some(method_id)) }; let sub_span = self.span_utils.sub_span_for_meth_name(expr.span); + let parent = self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0); Some(Data::MethodCallData(MethodCallData { span: sub_span.unwrap(), - scope: self.tcx.map.get_enclosing_scope(expr.id).unwrap_or(0), + scope: parent, ref_id: def_id, - decl_id: decl_id, + decl_id: decl_id, })) } + ast::ExprPath(_, ref path) => { + Some(self.get_path_data(expr.id, path)) + } _ => { // FIXME unimplemented!(); @@ -406,6 +420,90 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + pub fn get_path_data(&self, + id: NodeId, + path: &ast::Path) + -> Data { + let def_map = self.tcx.def_map.borrow(); + if !def_map.contains_key(&id) { + self.tcx.sess.span_bug(path.span, + &format!("def_map has no key for {} in visit_expr", id)); + } + let def = def_map.get(&id).unwrap().full_def(); + let sub_span = self.span_utils.span_for_last_ident(path.span); + match def { + def::DefUpvar(..) | + def::DefLocal(..) | + def::DefStatic(..) | + def::DefConst(..) | + def::DefAssociatedConst(..) | + def::DefVariant(..) => { + Data::VariableRefData(VariableRefData { + name: self.span_utils.snippet(sub_span.unwrap()), + span: sub_span.unwrap(), + scope: self.tcx.map.get_enclosing_scope(id).unwrap_or(0), + ref_id: def.def_id(), + }) + } + def::DefStruct(def_id) | def::DefTy(def_id, _) => { + Data::TypeRefData(TypeRefData { + span: sub_span.unwrap(), + ref_id: def_id, + scope: self.tcx.map.get_enclosing_scope(id).unwrap_or(0), + }) + } + def::DefMethod(decl_id, provenence) => { + let sub_span = self.span_utils.sub_span_for_meth_name(path.span); + let def_id = if decl_id.krate == ast::LOCAL_CRATE { + let ti = self.tcx.impl_or_trait_item(decl_id); + match provenence { + def::FromTrait(def_id) => { + Some(self.tcx.trait_items(def_id) + .iter() + .find(|mr| { + mr.name() == ti.name() + }) + .unwrap() + .def_id()) + } + def::FromImpl(def_id) => { + let impl_items = self.tcx.impl_items.borrow(); + Some(impl_items.get(&def_id) + .unwrap() + .iter() + .find(|mr| { + self.tcx.impl_or_trait_item(mr.def_id()).name() + == ti.name() + }) + .unwrap() + .def_id()) + } + } + } else { + None + }; + Data::MethodCallData(MethodCallData { + span: sub_span.unwrap(), + scope: self.tcx.map.get_enclosing_scope(id).unwrap_or(0), + ref_id: def_id, + decl_id: Some(decl_id), + }) + }, + def::DefFn(def_id, _) => { + Data::FunctionCallData(FunctionCallData { + ref_id: def_id, + span: sub_span.unwrap(), + scope: self.tcx.map.get_enclosing_scope(id).unwrap_or(0), + }) + } + _ => self.tcx.sess.span_bug(path.span, + &format!("Unexpected def kind while looking \ + up path in `{}`: `{:?}`", + self.span_utils.snippet(path.span), + def)), + } + } + pub fn get_field_ref_data(&self, field_ref: &ast::Field, struct_id: DefId, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a4855ddcb25..53befc092da 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -61,7 +61,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // Keep going, outside-in. let fully_expanded = fld.fold_expr(expanded_expr); - let span = fld.new_span(span); + let span = fld.new_span(span); fld.cx.bt_pop(); fully_expanded.map(|e| ast::Expr { -- cgit 1.4.1-3-g733a5 From f28f79b79615fc77e65ec42c4e2a3960659150c9 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Jul 2015 17:47:27 +1200 Subject: Fix a span bug for qualified paths --- src/libsyntax/parse/parser.rs | 6 ++---- src/test/run-make/save-analysis/foo.rs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 03c788aee58..81ae607fea2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1566,12 +1566,13 @@ impl<'a> Parser<'a> { // Assumes that the leading `<` has been parsed already. pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { + let span = self.last_span; let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { try!(self.parse_path(LifetimeAndTypesWithoutColons)) } else { ast::Path { - span: self.span, + span: span, global: false, segments: vec![] } @@ -1598,9 +1599,6 @@ impl<'a> Parser<'a> { }; path.segments.extend(segments); - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } path.span.hi = self.last_span.hi; Ok((qself, path)) diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 07b99dff4e0..4981ea475d3 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -364,3 +364,18 @@ impl<'a> Pattern<'a> for CharEqPattern { } struct CharSearcher<'a>(>::Searcher); + +pub trait Error { +} + +impl Error + 'static { + pub fn is(&self) -> bool { + panic!() + } +} + +impl Error + 'static + Send { + pub fn is(&self) -> bool { + ::is::(self) + } +} -- cgit 1.4.1-3-g733a5 From 836f32e7697195a482b88883cbbe4a2dd986d8cb Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 8 Jul 2015 22:52:55 +0200 Subject: Use vec![elt; n] where possible The common pattern `iter::repeat(elt).take(n).collect::>()` is exactly equivalent to `vec![elt; n]`, do this replacement in the whole tree. (Actually, vec![] is smart enough to only call clone n - 1 times, while the former solution would call clone n times, and this fact is virtually irrelevant in practice.) --- src/libcollections/bit.rs | 2 +- src/libcollectionstest/slice.rs | 8 ++++---- src/libcoretest/ptr.rs | 5 ++--- src/libgraphviz/lib.rs | 3 +-- src/librand/reseeding.rs | 2 +- src/librustc/middle/check_match.rs | 8 ++++---- src/librustc/middle/dataflow.rs | 13 ++++++------- src/librustc/middle/infer/region_inference/mod.rs | 3 +-- src/librustc/middle/liveness.rs | 5 ++--- src/librustc_back/sha2.rs | 6 ++---- src/librustc_data_structures/bitvec.rs | 4 +--- src/librustc_trans/trans/cabi_x86_64.rs | 3 +-- src/librustc_trans/trans/consts.rs | 3 +-- src/librustc_trans/trans/expr.rs | 3 +-- src/librustc_trans/trans/type_.rs | 5 ++--- src/librustc_typeck/astconv.rs | 3 +-- src/librustc_typeck/check/method/confirm.rs | 3 +-- src/librustc_typeck/check/mod.rs | 15 +++++++-------- src/librustc_typeck/rscope.rs | 3 +-- src/librustdoc/html/render.rs | 2 +- src/libstd/collections/hash/map.rs | 6 +++--- src/libstd/sys/windows/stdio.rs | 3 +-- src/libsyntax/ext/format.rs | 3 +-- src/libsyntax/print/pp.rs | 7 +++---- src/test/bench/core-std.rs | 9 ++++----- src/test/bench/shootout-fasta-redux.rs | 3 +-- src/test/bench/shootout-meteor.rs | 3 +-- src/test/bench/shootout-spectralnorm.rs | 3 +-- src/test/bench/sudoku.rs | 4 +--- src/test/run-pass/issue-3563-3.rs | 9 +++------ src/test/run-pass/realloc-16687.rs | 3 +-- 31 files changed, 61 insertions(+), 91 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index a8d638028be..3a4cfbba65f 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -283,7 +283,7 @@ impl BitVec { pub fn from_elem(nbits: usize, bit: bool) -> BitVec { let nblocks = blocks_for_bits(nbits); let mut bit_vec = BitVec { - storage: repeat(if bit { !0 } else { 0 }).take(nblocks).collect(), + storage: vec![if bit { !0 } else { 0 }; nblocks], nbits: nbits }; bit_vec.fix_last_block(); diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index e1c4e05e192..d88d8b8e4a0 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -1318,7 +1318,7 @@ mod bench { #[bench] fn mut_iterator(b: &mut Bencher) { - let mut v: Vec<_> = repeat(0).take(100).collect(); + let mut v = vec![0; 100]; b.iter(|| { let mut i = 0; @@ -1419,7 +1419,7 @@ mod bench { #[bench] fn zero_1kb_from_elem(b: &mut Bencher) { b.iter(|| { - repeat(0u8).take(1024).collect::>() + vec![0u8; 1024] }); } @@ -1467,7 +1467,7 @@ mod bench { fn random_inserts(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v: Vec<_> = repeat((0, 0)).take(30).collect(); + let mut v = vec![(0, 0); 30]; for _ in 0..100 { let l = v.len(); v.insert(rng.gen::() % (l + 1), @@ -1479,7 +1479,7 @@ mod bench { fn random_removes(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v: Vec<_> = repeat((0, 0)).take(130).collect(); + let mut v = vec![(0, 0); 130]; for _ in 0..100 { let l = v.len(); v.remove(rng.gen::() % l); diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 8f1017c50a3..865b049aae5 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -10,7 +10,6 @@ use core::ptr::*; use core::mem; -use std::iter::repeat; #[test] fn test() { @@ -110,7 +109,7 @@ fn test_as_mut() { #[test] fn test_ptr_addition() { unsafe { - let xs = repeat(5).take(16).collect::>(); + let xs = vec![5; 16]; let mut ptr = xs.as_ptr(); let end = ptr.offset(16); @@ -128,7 +127,7 @@ fn test_ptr_addition() { m_ptr = m_ptr.offset(1); } - assert!(xs_mut == repeat(10).take(16).collect::>()); + assert!(xs_mut == vec![10; 16]); } } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index f8d80035d97..cd9e677d87f 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -599,7 +599,6 @@ mod tests { use std::io; use std::io::prelude::*; use std::borrow::IntoCow; - use std::iter::repeat; /// each node is an index in a vector in the graph. type Node = usize; @@ -647,7 +646,7 @@ mod tests { fn to_opt_strs(self) -> Vec> { match self { UnlabelledNodes(len) - => repeat(None).take(len).collect(), + => vec![None; len], AllNodesLabelled(lbls) => lbls.into_iter().map( |l|Some(l)).collect(), diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index bb0b13c4375..73ff51da290 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -186,7 +186,7 @@ mod tests { const FILL_BYTES_V_LEN: usize = 13579; #[test] fn test_rng_fill_bytes() { - let mut v = repeat(0).take(FILL_BYTES_V_LEN).collect::>(); + let mut v = vec![0; FILL_BYTES_V_LEN]; ::test::rng().fill_bytes(&mut v); // Sanity test: if we've gotten here, `fill_bytes` has not infinitely diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index a303c49bf8d..444192b7913 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -704,7 +704,7 @@ fn is_useful(cx: &MatchCheckCtxt, match is_useful(cx, &matrix, v.tail(), witness) { UsefulWithWitness(pats) => { let arity = constructor_arity(cx, &constructor, left_ty); - let wild_pats: Vec<_> = repeat(DUMMY_WILD_PAT).take(arity).collect(); + let wild_pats = vec![DUMMY_WILD_PAT; arity]; let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty); let mut new_pats = vec![enum_pat]; new_pats.extend(pats); @@ -862,7 +862,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } = raw_pat(r[col]); let head: Option> = match *node { ast::PatWild(_) => - Some(repeat(DUMMY_WILD_PAT).take(arity).collect()), + Some(vec![DUMMY_WILD_PAT; arity]), ast::PatIdent(_, _, _) => { let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def()); @@ -875,7 +875,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } else { None }, - _ => Some(repeat(DUMMY_WILD_PAT).take(arity).collect()) + _ => Some(vec![DUMMY_WILD_PAT; arity]) } } @@ -889,7 +889,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], DefVariant(..) | DefStruct(..) => { Some(match args { &Some(ref args) => args.iter().map(|p| &**p).collect(), - &None => repeat(DUMMY_WILD_PAT).take(arity).collect(), + &None => vec![DUMMY_WILD_PAT; arity], }) } _ => None diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index b69a0862573..dea769197aa 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -21,7 +21,6 @@ use middle::cfg::CFGIndex; use middle::ty; use std::io; use std::usize; -use std::iter::repeat; use syntax::ast; use syntax::ast_util::IdRange; use syntax::visit; @@ -239,11 +238,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let entry = if oper.initial_value() { usize::MAX } else {0}; - let zeroes: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); - let gens: Vec<_> = zeroes.clone(); - let kills1: Vec<_> = zeroes.clone(); - let kills2: Vec<_> = zeroes; - let on_entry: Vec<_> = repeat(entry).take(num_nodes * words_per_id).collect(); + let zeroes = vec![0; num_nodes * words_per_id]; + let gens = zeroes.clone(); + let kills1 = zeroes.clone(); + let kills2 = zeroes; + let on_entry = vec![entry; num_nodes * words_per_id]; let nodeid_to_index = build_nodeid_to_index(decl, cfg); @@ -511,7 +510,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { changed: true }; - let mut temp: Vec<_> = repeat(0).take(words_per_id).collect(); + let mut temp = vec![0; words_per_id]; while propcx.changed { propcx.changed = false; propcx.reset(&mut temp); diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 891a39e723a..ba5814167a6 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -34,7 +34,6 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cell::{Cell, RefCell}; use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::fmt; -use std::iter::repeat; use std::u32; use syntax::ast; @@ -1304,7 +1303,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // idea is to report errors that derive from independent // regions of the graph, but not those that derive from // overlapping locations. - let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect(); + let mut dup_vec = vec![u32::MAX; self.num_vars() as usize]; for idx in 0..self.num_vars() as usize { match var_data[idx].value { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 37460531dbd..4345649de0c 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -119,7 +119,6 @@ use util::nodemap::NodeMap; use std::{fmt, usize}; use std::io::prelude::*; use std::io; -use std::iter::repeat; use std::rc::Rc; use syntax::ast::{self, NodeId, Expr}; use syntax::codemap::{BytePos, original_sp, Span}; @@ -566,8 +565,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Liveness { ir: ir, s: specials, - successors: repeat(invalid_node()).take(num_live_nodes).collect(), - users: repeat(invalid_users()).take(num_live_nodes * num_vars).collect(), + successors: vec![invalid_node(); num_live_nodes], + users: vec![invalid_users(); num_live_nodes * num_vars], loop_scope: Vec::new(), break_ln: NodeMap(), cont_ln: NodeMap(), diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index efbd4c3ef5e..4f904c20a51 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -12,7 +12,6 @@ //! use. This implementation is not intended for external use or for any use where security is //! important. -use std::iter::repeat; use std::slice::bytes::{MutableByteVector, copy_memory}; use serialize::hex::ToHex; @@ -255,7 +254,7 @@ pub trait Digest { /// Convenience function that retrieves the result of a digest as a /// newly allocated vec of bytes. fn result_bytes(&mut self) -> Vec { - let mut buf: Vec = repeat(0).take((self.output_bits()+7)/8).collect(); + let mut buf = vec![0; (self.output_bits()+7)/8]; self.result(&mut buf); buf } @@ -534,7 +533,6 @@ mod tests { use self::rand::Rng; use self::rand::isaac::IsaacRng; use serialize::hex::FromHex; - use std::iter::repeat; use std::u64; use super::{Digest, Sha256, FixedBuffer}; @@ -613,7 +611,7 @@ mod tests { /// correct. fn test_digest_1million_random(digest: &mut D, blocksize: usize, expected: &str) { let total_size = 1000000; - let buffer: Vec = repeat('a' as u8).take(blocksize * 2).collect(); + let buffer = vec![b'a'; blocksize * 2]; let mut rng = IsaacRng::new_unseeded(); let mut count = 0; diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 983601771a0..f2f4a69d882 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::iter; - /// A very simple BitVector type. pub struct BitVector { data: Vec @@ -18,7 +16,7 @@ pub struct BitVector { impl BitVector { pub fn new(num_bits: usize) -> BitVector { let num_words = (num_bits + 63) / 64; - BitVector { data: iter::repeat(0).take(num_words).collect() } + BitVector { data: vec![0; num_words] } } fn word_mask(&self, bit: usize) -> (usize, u64) { diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index b64e24591fd..fa3824866cc 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -21,7 +21,6 @@ use trans::context::CrateContext; use trans::type_::Type; use std::cmp; -use std::iter::repeat; #[derive(Clone, Copy, PartialEq)] enum RegClass { @@ -319,7 +318,7 @@ fn classify_ty(ty: Type) -> Vec { } let words = (ty_size(ty) + 7) / 8; - let mut cls: Vec<_> = repeat(NoClass).take(words).collect(); + let mut cls = vec![NoClass; words]; if words > 4 { all_mem(&mut cls); return cls; diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index ece52b3ad4d..5b6d939d9e6 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -35,7 +35,6 @@ use middle::subst::Substs; use middle::ty::{self, Ty}; use util::nodemap::NodeMap; -use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; use syntax::parse::token; @@ -780,7 +779,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let llunitty = type_of::type_of(cx, unit_ty); let n = cx.tcx().eval_repeat_count(count); let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0; - let vs: Vec<_> = repeat(unit_val).take(n).collect(); + let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { C_struct(cx, &vs[..], false) } else { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7722cb322c9..efd86c5741a 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -83,7 +83,6 @@ use syntax::{ast, ast_util, codemap}; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::parse::token; -use std::iter::repeat; use std::mem; // Destinations @@ -1401,7 +1400,7 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| { - let mut need_base: Vec = repeat(true).take(field_tys.len()).collect(); + let mut need_base = vec![true; field_tys.len()]; let numbered_fields = fields.iter().map(|field| { let opt_pos = diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index b80b2b8266a..ac39d10a23d 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -23,7 +23,6 @@ use std::ffi::CString; use std::mem; use std::ptr; use std::cell::RefCell; -use std::iter::repeat; use libc::c_uint; @@ -253,7 +252,7 @@ impl Type { if n_elts == 0 { return Vec::new(); } - let mut elts: Vec<_> = repeat(Type { rf: ptr::null_mut() }).take(n_elts).collect(); + let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts]; llvm::LLVMGetStructElementTypes(self.to_ref(), elts.as_mut_ptr() as *mut TypeRef); elts @@ -267,7 +266,7 @@ impl Type { pub fn func_params(&self) -> Vec { unsafe { let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize; - let mut args: Vec<_> = repeat(Type { rf: ptr::null_mut() }).take(n_args).collect(); + let mut args = vec![Type { rf: ptr::null_mut() }; n_args]; llvm::LLVMGetParamTypes(self.to_ref(), args.as_mut_ptr() as *mut TypeRef); args diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 046e83bf3fc..ef3c858bed5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -64,7 +64,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::FnvHashSet; -use std::iter::repeat; use std::slice; use syntax::{abi, ast, ast_util}; use syntax::codemap::{Span, Pos}; @@ -588,7 +587,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, 0, ®ion_substs, a_t)) .collect::>>(); - let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); + let input_params = vec![String::new(); inputs.len()]; let implied_output_region = find_implied_output_region(this.tcx(), &inputs, input_params); let input_ty = this.tcx().mk_tup(inputs); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8db5b5e7c50..b9c986a512e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -20,7 +20,6 @@ use middle::infer; use middle::infer::InferCtxt; use syntax::ast; use syntax::codemap::Span; -use std::iter::repeat; struct ConfirmContext<'a, 'tcx:'a> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -322,7 +321,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } else if num_supplied_types != num_method_types { span_err!(self.tcx().sess, self.span, E0036, "incorrect number of type parameters given for this method"); - repeat(self.tcx().types.err).take(num_method_types).collect() + vec![self.tcx().types.err; num_method_types] } else { supplied_method_types } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9704bef6487..638cc868527 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -108,7 +108,6 @@ use util::lev_distance::lev_distance; use std::cell::{Cell, Ref, RefCell}; use std::mem::replace; -use std::iter::repeat; use std::slice; use syntax::{self, abi, attr}; use syntax::attr::AttrMetaMethods; @@ -4340,7 +4339,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefTyParam(..) => { // Everything but the final segment should have no // parameters at all. - segment_spaces = repeat(None).take(segments.len() - 1).collect(); + segment_spaces = vec![None; segments.len() - 1]; segment_spaces.push(Some(subst::TypeSpace)); } @@ -4348,7 +4347,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefFn(..) | def::DefConst(..) | def::DefStatic(..) => { - segment_spaces = repeat(None).take(segments.len() - 1).collect(); + segment_spaces = vec![None; segments.len() - 1]; segment_spaces.push(Some(subst::FnSpace)); } @@ -4362,7 +4361,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } if segments.len() >= 2 { - segment_spaces = repeat(None).take(segments.len() - 2).collect(); + segment_spaces = vec![None; segments.len() - 2]; segment_spaces.push(Some(subst::TypeSpace)); segment_spaces.push(Some(subst::FnSpace)); } else { @@ -4382,7 +4381,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } if segments.len() >= 2 { - segment_spaces = repeat(None).take(segments.len() - 2).collect(); + segment_spaces = vec![None; segments.len() - 2]; segment_spaces.push(Some(subst::TypeSpace)); segment_spaces.push(None); } else { @@ -4400,7 +4399,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefRegion(..) | def::DefLabel(..) | def::DefUpvar(..) => { - segment_spaces = repeat(None).take(segments.len()).collect(); + segment_spaces = vec![None; segments.len()]; } } assert_eq!(segment_spaces.len(), segments.len()); @@ -4681,7 +4680,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if required_len == 1 {""} else {"s"}, provided_len, if provided_len == 1 {""} else {"s"}); - substs.types.replace(space, repeat(fcx.tcx().types.err).take(desired.len()).collect()); + substs.types.replace(space, vec![fcx.tcx().types.err; desired.len()]); return; } @@ -4813,7 +4812,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // make a vector of booleans initially false, set to true when used if tps.is_empty() { return; } - let mut tps_used: Vec<_> = repeat(false).take(tps.len()).collect(); + let mut tps_used = vec![false; tps.len()]; for leaf_ty in ty.walk() { if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty { diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index d2c982b3099..1b33f588e92 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -13,7 +13,6 @@ use middle::ty; use middle::ty_fold; use std::cell::Cell; -use std::iter::repeat; use syntax::codemap::Span; #[derive(Clone)] @@ -147,7 +146,7 @@ impl RegionScope for ElidableRscope { count: usize) -> Result, Option>> { - Ok(repeat(self.default).take(count).collect()) + Ok(vec![self.default; count]) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5b0109290e6..5ecf0fe8ecf 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1920,7 +1920,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, r#""#, - root_path = repeat("..").take(cx.current.len()).collect::>().connect("/"), + root_path = vec![".."; cx.current.len()].connect("/"), path = if ast_util::is_local(it.def_id) { cx.current.connect("/") } else { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1dca3b77f38..06a30670e8b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1638,7 +1638,7 @@ mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; - use iter::{range_inclusive, repeat}; + use iter::range_inclusive; use cell::RefCell; use rand::{thread_rng, Rng}; @@ -1698,7 +1698,7 @@ mod test_map { #[test] fn test_drops() { DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = repeat(0).take(200).collect(); + *slot.borrow_mut() = vec![0; 200]; }); { @@ -1757,7 +1757,7 @@ mod test_map { #[test] fn test_move_iter_drops() { DROP_VECTOR.with(|v| { - *v.borrow_mut() = repeat(0).take(200).collect(); + *v.borrow_mut() = vec![0; 200]; }); let hm = { diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 9961fef714a..356787d5bf0 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -12,7 +12,6 @@ use prelude::v1::*; use io::prelude::*; use io::{self, Cursor}; -use iter::repeat; use libc; use ptr; use str; @@ -94,7 +93,7 @@ impl Stdin { let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty if utf8.position() as usize == utf8.get_ref().len() { - let mut utf16: Vec = repeat(0u16).take(0x1000).collect(); + let mut utf16 = vec![0u16; 0x1000]; let mut num = 0; try!(cvt(unsafe { c::ReadConsoleW(handle, diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 86e72d4ef03..5b972b464c9 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -23,7 +23,6 @@ use parse::token; use ptr::P; use std::collections::HashMap; -use std::iter::repeat; #[derive(PartialEq)] enum ArgumentType { @@ -469,7 +468,7 @@ impl<'a, 'b> Context<'a, 'b> { /// to fn into_expr(mut self) -> P { let mut locals = Vec::new(); - let mut names: Vec<_> = repeat(None).take(self.name_positions.len()).collect(); + let mut names = vec![None; self.name_positions.len()]; let mut pats = Vec::new(); let mut heads = Vec::new(); diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index ed9937c53f4..7c5a46465f5 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,7 +61,6 @@ use std::io; use std::string; -use std::iter::repeat; #[derive(Clone, Copy, PartialEq)] pub enum Breaks { @@ -166,9 +165,9 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { // fall behind. let n: usize = 3 * linewidth; debug!("mk_printer {}", linewidth); - let token: Vec = repeat(Token::Eof).take(n).collect(); - let size: Vec = repeat(0).take(n).collect(); - let scan_stack: Vec = repeat(0).take(n).collect(); + let token = vec![Token::Eof; n]; + let size = vec![0_isize; n]; + let scan_stack = vec![0_usize; n]; Printer { out: out, buf_len: n, diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 3cc03f5218c..e7d64dfe2c5 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -12,7 +12,6 @@ #![feature(rand, vec_push_all, duration, duration_span)] -use std::iter::repeat; use std::mem::swap; use std::env; use std::__rand::{thread_rng, Rng}; @@ -56,7 +55,7 @@ fn maybe_run_test(argv: &[String], name: String, test: F) where F: FnOnce() { } fn shift_push() { - let mut v1 = repeat(1).take(30000).collect::>(); + let mut v1 = vec![1; 30000]; let mut v2 = Vec::new(); while !v1.is_empty() { @@ -70,7 +69,7 @@ fn vec_plus() { let mut v = Vec::new(); let mut i = 0; while i < 1500 { - let rv = repeat(i).take(r.gen_range(0, i + 1)).collect::>(); + let rv = vec![i; r.gen_range(0, i + 1)]; if r.gen() { v.extend(rv); } else { @@ -88,7 +87,7 @@ fn vec_append() { let mut v = Vec::new(); let mut i = 0; while i < 1500 { - let rv = repeat(i).take(r.gen_range(0, i + 1)).collect::>(); + let rv = vec![i; r.gen_range(0, i + 1)]; if r.gen() { let mut t = v.clone(); t.push_all(&rv); @@ -108,7 +107,7 @@ fn vec_push_all() { let mut v = Vec::new(); for i in 0..1500 { - let mut rv = repeat(i).take(r.gen_range(0, i + 1)).collect::>(); + let mut rv = vec![i; r.gen_range(0, i + 1)]; if r.gen() { v.push_all(&rv); } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index f69e155ad38..3f3c9e52220 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -42,7 +42,6 @@ use std::cmp::min; use std::env; use std::io; use std::io::prelude::*; -use std::iter::repeat; const LINE_LEN: usize = 60; const LOOKUP_SIZE: usize = 4 * 1024; @@ -121,7 +120,7 @@ impl<'a, W: Write> RepeatFasta<'a, W> { fn make(&mut self, n: usize) -> io::Result<()> { let alu_len = self.alu.len(); - let mut buf = repeat(0).take(alu_len + LINE_LEN).collect::>(); + let mut buf = vec![0; alu_len + LINE_LEN]; let alu: &[u8] = self.alu.as_bytes(); for (slot, val) in buf.iter_mut().zip(alu) { diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs index aa40f6f868c..331d83b535a 100644 --- a/src/test/bench/shootout-meteor.rs +++ b/src/test/bench/shootout-meteor.rs @@ -42,7 +42,6 @@ #![feature(iter_cmp)] -use std::iter::repeat; use std::sync::Arc; use std::sync::mpsc::channel; use std::thread; @@ -221,7 +220,7 @@ fn get_id(m: u64) -> u8 { // Converts a list of mask to a Vec. fn to_vec(raw_sol: &List) -> Vec { - let mut sol = repeat('.' as u8).take(50).collect::>(); + let mut sol = vec![b'.'; 50]; for &m in raw_sol.iter() { let id = '0' as u8 + get_id(m); for i in 0..50 { diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index 1598b209223..7f3f6a3c85f 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -43,7 +43,6 @@ #![allow(non_snake_case)] #![feature(unboxed_closures, iter_arith, core_simd, scoped)] -use std::iter::repeat; use std::thread; use std::env; use std::simd::f64x2; @@ -62,7 +61,7 @@ fn main() { fn spectralnorm(n: usize) -> f64 { assert!(n % 2 == 0, "only even lengths are accepted"); - let mut u = repeat(1.0).take(n).collect::>(); + let mut u = vec![1.0; n]; let mut v = u.clone(); let mut tmp = v.clone(); for _ in 0..10 { diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 16742f0a6e1..bcadfd74493 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -15,7 +15,6 @@ use std::io::prelude::*; use std::io; -use std::iter::repeat; use std::env; // Computes a single solution to a given 9x9 sudoku @@ -59,8 +58,7 @@ impl Sudoku { reader.read_line(&mut s).unwrap(); assert_eq!(s, "9,9\n"); - let mut g = repeat(vec![0, 0, 0, 0, 0, 0, 0, 0, 0]) - .take(10).collect::>(); + let mut g = vec![vec![0, 0, 0, 0, 0, 0, 0, 0, 0]; 10]; for line in reader.lines() { let line = line.unwrap(); let comps: Vec<&str> = line diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index cfdc54a3622..5cd58c0ecfb 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -68,12 +68,9 @@ impl Drop for AsciiArt { // If there is a canonical constructor it is typically named the same as the type. // Other constructor sort of functions are typically named from_foo, from_bar, etc. fn AsciiArt(width: usize, height: usize, fill: char) -> AsciiArt { - // Use an anonymous function to build a vector of vectors containing - // blank characters for each position in our canvas. - let mut lines = Vec::new(); - for _ in 0..height { - lines.push(repeat('.').take(width).collect::>()); - } + // Build a vector of vectors containing blank characters for each position in + // our canvas. + let lines = vec![vec!['.'; width]; height]; // Rust code often returns values by omitting the trailing semi-colon // instead of using an explicit return statement. diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index a9bd967ca76..b32d42df6b1 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -19,7 +19,6 @@ extern crate alloc; use alloc::heap; use std::ptr; -use std::iter::repeat; fn main() { unsafe { @@ -29,7 +28,7 @@ fn main() { unsafe fn test_triangle() -> bool { static COUNT : usize = 16; - let mut ascend = repeat(ptr::null_mut()).take(COUNT).collect::>(); + let mut ascend = vec![ptr::null_mut(); COUNT]; let ascend = &mut *ascend; static ALIGN : usize = 1; -- cgit 1.4.1-3-g733a5 From 5c60d1d902da615a770ef211217a46d92b3aaae7 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Thu, 2 Jul 2015 03:55:18 +0900 Subject: Preserve escape sequences in documentation comments on macro expansion Escape sequences in documentation comments must not be parsed as a normal string when expanding a macro, otherwise some innocent but invalid-escape-sequence-looking comments will trigger an ICE. Although this commit replaces normal string literals with raw string literals in macro expansion, this shouldn't be much a problem considering documentation comments are converted into attributes before being passed to a macro anyways. Fixes #25929. Fixes #25943. --- src/libsyntax/ast.rs | 2 +- src/test/run-pass/macro-doc-escapes.rs | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/macro-doc-escapes.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e844b206cc0..a944acad84d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1104,7 +1104,7 @@ impl TokenTree { tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::Str_(name), None))], + TtToken(sp, token::Literal(token::StrRaw(name, 0), None))], close_span: sp, })) } diff --git a/src/test/run-pass/macro-doc-escapes.rs b/src/test/run-pass/macro-doc-escapes.rs new file mode 100644 index 00000000000..ea92f0ffebe --- /dev/null +++ b/src/test/run-pass/macro-doc-escapes.rs @@ -0,0 +1,25 @@ +// 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. + +// When expanding a macro, documentation attributes (including documentation comments) must be +// passed "as is" without being parsed. Otherwise, some text will be incorrectly interpreted as +// escape sequences, leading to an ICE. +// +// Related issues: #25929, #25943 + +macro_rules! homura { + (#[$x:meta]) => () +} + +homura! { + /// \madoka \x41 +} + +fn main() { } -- cgit 1.4.1-3-g733a5 From 0bd5dd6449c9db734bd2d1700ea4b50e22b220be Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 10 Jul 2015 21:37:21 +0300 Subject: Improve incomplete unicode escape reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This improves diagnostic messages when \u escape is used incorrectly and { is missing. Instead of saying “unknown character escape: u”, it will now report that unicode escape sequence is incomplete and suggest what the correct syntax is. --- src/libsyntax/parse/lexer/mod.rs | 24 +++++++++++++++++----- src/test/parse-fail/issue-23620-invalid-escapes.rs | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 507bd9de2a1..b5085b5c44c 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -172,6 +172,11 @@ impl<'a> StringReader<'a> { self.span_diagnostic.span_err(sp, m) } + /// Suggest some help with a given span. + pub fn help_span(&self, sp: Span, m: &str) { + self.span_diagnostic.span_help(sp, m) + } + /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> ! { self.fatal_span(codemap::mk_sp(from_pos, to_pos), m) @@ -182,6 +187,11 @@ impl<'a> StringReader<'a> { self.err_span(codemap::mk_sp(from_pos, to_pos), m) } + /// Suggest some help spanning [`from_pos`, `to_pos`). + fn help_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { + self.help_span(codemap::mk_sp(from_pos, to_pos), m) + } + /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> ! { @@ -742,6 +752,13 @@ impl<'a> StringReader<'a> { valid } } + 'u' if !ascii_only => { + self.err_span_(escaped_pos, self.last_pos, + "incomplete unicode escape sequence"); + self.help_span_(escaped_pos, self.last_pos, + "format of unicode escape sequences is `\\u{…}`"); + false + } '\n' if delim == '"' => { self.consume_whitespace(); true @@ -757,16 +774,13 @@ impl<'a> StringReader<'a> { if ascii_only { "unknown byte escape" } else { "unknown character escape" }, c); - let sp = codemap::mk_sp(escaped_pos, last_pos); if e == '\r' { - self.span_diagnostic.span_help( - sp, + self.help_span_(escaped_pos, last_pos, "this is an isolated carriage return; consider checking \ your editor and version control settings") } if (e == '{' || e == '}') && !ascii_only { - self.span_diagnostic.span_help( - sp, + self.help_span_(escaped_pos, last_pos, "if used in a formatting string, \ curly braces are escaped with `{{` and `}}`") } diff --git a/src/test/parse-fail/issue-23620-invalid-escapes.rs b/src/test/parse-fail/issue-23620-invalid-escapes.rs index 7930ea75bf5..98db3efe114 100644 --- a/src/test/parse-fail/issue-23620-invalid-escapes.rs +++ b/src/test/parse-fail/issue-23620-invalid-escapes.rs @@ -41,5 +41,5 @@ fn main() { //~^ ERROR illegal unicode character escape //~^^ ERROR illegal character in numeric character escape: //~^^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f] - //~^^^^ ERROR unknown character escape: u + //~^^^^ ERROR incomplete unicode escape sequence } -- cgit 1.4.1-3-g733a5 From d22f189da13f8ffb3c9227a038615608e99a6211 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 10 Jul 2015 21:41:37 +0300 Subject: Improve some of the string escape diagnostic spans --- src/libsyntax/parse/lexer/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b5085b5c44c..edaac3b09ba 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -742,7 +742,7 @@ impl<'a> StringReader<'a> { let valid = self.scan_unicode_escape(delim); if valid && ascii_only { self.err_span_( - escaped_pos, + start, self.last_pos, "unicode escape sequences cannot be used as a byte or in \ a byte string" @@ -753,9 +753,9 @@ impl<'a> StringReader<'a> { } } 'u' if !ascii_only => { - self.err_span_(escaped_pos, self.last_pos, + self.err_span_(start, self.last_pos, "incomplete unicode escape sequence"); - self.help_span_(escaped_pos, self.last_pos, + self.help_span_(start, self.last_pos, "format of unicode escape sequences is `\\u{…}`"); false } @@ -862,14 +862,12 @@ impl<'a> StringReader<'a> { valid = false; } - self.bump(); // past the ending } - if valid && (char::from_u32(accum_int).is_none() || count == 0) { self.err_span_(start_bpos, self.last_pos, "illegal unicode character escape"); valid = false; } - + self.bump(); // past the ending } valid } -- cgit 1.4.1-3-g733a5 From 93ddee6cee6816843035575ddf0bf0309021ebc5 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 10 Jul 2015 08:19:21 -0400 Subject: Change some instances of .connect() to .join() --- src/compiletest/runtest.rs | 8 +++---- src/libcollectionstest/slice.rs | 20 ++++++++--------- src/libcollectionstest/str.rs | 30 +++++++++++++------------- src/libgetopts/lib.rs | 6 +++--- src/librustc/metadata/encoder.rs | 2 +- src/librustc/middle/infer/mod.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/librustc_driver/pretty.rs | 2 +- src/librustc_driver/test.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_trans/trans/_match.rs | 4 ++-- src/librustc_trans/trans/asm.rs | 2 +- src/librustc_trans/trans/build.rs | 2 +- src/librustc_trans/trans/builder.rs | 4 ++-- src/librustc_trans/trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans/llrepr.rs | 2 +- src/librustc_trans/trans/type_.rs | 2 +- src/librustc_trans/trans/type_of.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 6 +++--- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/mod.rs | 6 +++--- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/markdown.rs | 10 ++++----- src/librustdoc/html/render.rs | 22 +++++++++---------- src/librustdoc/passes.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libstd/net/ip.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/lexer/comments.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/libtest/lib.rs | 2 +- src/test/auxiliary/plugin_args.rs | 2 +- src/test/run-pass/issue-3563-3.rs | 2 +- src/test/run-pass/trait-to-str.rs | 2 +- 39 files changed, 87 insertions(+), 87 deletions(-) (limited to 'src/libsyntax') diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 93054f39790..5b62f29b824 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -344,7 +344,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { check_lines, breakpoint_lines } = parse_debugger_commands(testfile, "gdb"); - let mut cmds = commands.connect("\n"); + let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) let compiler_run_result = compile_test(config, props, testfile); @@ -799,7 +799,7 @@ fn cleanup_debug_info_options(options: &Option) -> Option { split_maybe_args(options).into_iter() .filter(|x| !options_to_remove.contains(x)) .collect::>() - .connect(" "); + .join(" "); Some(new_options) } @@ -1412,7 +1412,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { // Linux and mac don't require adjusting the library search path if cfg!(unix) { - format!("{} {}", prog, args.connect(" ")) + format!("{} {}", prog, args.join(" ")) } else { // Build the LD_LIBRARY_PATH variable as it would be seen on the command line // for diagnostic purposes @@ -1420,7 +1420,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path)) } - format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" ")) + format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" ")) } } diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index d88d8b8e4a0..436e71fd4a0 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -606,22 +606,22 @@ fn test_concat() { assert_eq!(d, [1, 2, 3]); let v: &[&[_]] = &[&[1], &[2, 3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 3]); let v: &[&[_]] = &[&[1], &[2], &[3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); } #[test] -fn test_connect() { +fn test_join() { let v: [Vec; 0] = []; - assert_eq!(v.connect(&0), []); - assert_eq!([vec![1], vec![2, 3]].connect(&0), [1, 0, 2, 3]); - assert_eq!([vec![1], vec![2], vec![3]].connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), []); + assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]); + assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]); let v: [&[_]; 2] = [&[1], &[2, 3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 3]); let v: [&[_]; 3] = [&[1], &[2], &[3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); } #[test] @@ -1339,11 +1339,11 @@ mod bench { } #[bench] - fn connect(b: &mut Bencher) { + fn join(b: &mut Bencher) { let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); b.iter(|| { - xss.connect(&0) + xss.join(&0) }); } diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 87a018ced19..e92af585c15 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -158,32 +158,32 @@ fn test_concat_for_different_lengths() { test_concat!("abc", ["", "a", "bc"]); } -macro_rules! test_connect { +macro_rules! test_join { ($expected: expr, $string: expr, $delim: expr) => { { - let s = $string.connect($delim); + let s = $string.join($delim); assert_eq!($expected, s); } } } #[test] -fn test_connect_for_different_types() { - test_connect!("a-b", ["a", "b"], "-"); +fn test_join_for_different_types() { + test_join!("a-b", ["a", "b"], "-"); let hyphen = "-".to_string(); - test_connect!("a-b", [s("a"), s("b")], &*hyphen); - test_connect!("a-b", vec!["a", "b"], &*hyphen); - test_connect!("a-b", &*vec!["a", "b"], "-"); - test_connect!("a-b", vec![s("a"), s("b")], "-"); + test_join!("a-b", [s("a"), s("b")], &*hyphen); + test_join!("a-b", vec!["a", "b"], &*hyphen); + test_join!("a-b", &*vec!["a", "b"], "-"); + test_join!("a-b", vec![s("a"), s("b")], "-"); } #[test] -fn test_connect_for_different_lengths() { +fn test_join_for_different_lengths() { let empty: &[&str] = &[]; - test_connect!("", empty, "-"); - test_connect!("a", ["a"], "-"); - test_connect!("a-b", ["a", "b"], "-"); - test_connect!("-a-bc", ["", "a", "bc"], "-"); + test_join!("", empty, "-"); + test_join!("a", ["a"], "-"); + test_join!("a-b", ["a", "b"], "-"); + test_join!("-a-bc", ["", "a", "bc"], "-"); } #[test] @@ -2081,12 +2081,12 @@ mod bench { } #[bench] - fn bench_connect(b: &mut Bencher) { + fn bench_join(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; let sep = "→"; let v = vec![s, s, s, s, s, s, s, s, s, s]; b.iter(|| { - assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9); + assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9); }) } diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 0d15f584d64..65e85b92e0b 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -784,13 +784,13 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> String { // FIXME: #5516 should be graphemes not codepoints // wrapped description - row.push_str(&desc_rows.connect(&desc_sep[..])); + row.push_str(&desc_rows.join(&desc_sep[..])); row }); format!("{}\n\nOptions:\n{}\n", brief, - rows.collect::>().connect("\n")) + rows.collect::>().join("\n")) } fn format_option(opt: &OptGroup) -> String { @@ -836,7 +836,7 @@ pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { line.push_str(&opts.iter() .map(format_option) .collect::>() - .connect(" ")[..]); + .join(" ")[..]); line } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a9e9f17bdce..f38369e3f4c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -2028,7 +2028,7 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { cstore::RequireStatic => "s", })).to_string()) }).collect::>(); - rbml_w.wr_tagged_str(tag, &s.connect(",")); + rbml_w.wr_tagged_str(tag, &s.join(",")); } None => { rbml_w.wr_tagged_str(tag, ""); diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 63f31921ec2..e24fadba6a5 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1098,7 +1098,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { let tstrs: Vec = ts.iter().map(|t| self.ty_to_string(*t)).collect(); - format!("({})", tstrs.connect(", ")) + format!("({})", tstrs.join(", ")) } pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9541076df82..67301a09e52 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -843,7 +843,7 @@ fn write_out_deps(sess: &Session, let mut file = try!(fs::File::create(&deps_filename)); for path in &out_filenames { try!(write!(&mut file, - "{}: {}\n\n", path.display(), files.connect(" "))); + "{}: {}\n\n", path.display(), files.join(" "))); } Ok(()) })(); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7ccada1079f..2906fd35a0a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -606,7 +606,7 @@ Available lint options: for (name, to) in lints { let name = name.to_lowercase().replace("_", "-"); let desc = to.into_iter().map(|x| x.as_str().replace("_", "-")) - .collect::>().connect(", "); + .collect::>().join(", "); println!(" {} {}", padded(&name[..]), desc); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 610f3f3a75e..0e735cbb7ff 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -378,7 +378,7 @@ impl UserIdentifiedItem { fn reconstructed_input(&self) -> String { match *self { ItemViaNode(node_id) => node_id.to_string(), - ItemViaPath(ref parts) => parts.connect("::"), + ItemViaPath(ref parts) => parts.join("::"), } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 128b0b7baab..a9efd13a998 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) { Some(id) => id, None => { - panic!("no item found: `{}`", names.connect("::")); + panic!("no item found: `{}`", names.join("::")); } }; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 186361626ff..1574080b313 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -923,7 +923,7 @@ impl NonSnakeCase { } words.push(buf); } - words.connect("_") + words.join("_") } fn check_snake_case(&self, cx: &Context, sort: &str, name: &str, span: Option) { diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 936b0070dfc..3aa98ab031d 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -936,7 +936,7 @@ fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.to_str(), guard_expr, m, - vals.iter().map(|v| bcx.val_to_string(*v)).collect::>().connect(", ")); + vals.iter().map(|v| bcx.val_to_string(*v)).collect::>().join(", ")); let _indenter = indenter(); let mut bcx = insert_lllocals(bcx, &data.bindings_map, None); @@ -981,7 +981,7 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("compile_submatch(bcx={}, m={:?}, vals=[{}])", bcx.to_str(), m, - vals.iter().map(|v| bcx.val_to_string(*v)).collect::>().connect(", ")); + vals.iter().map(|v| bcx.val_to_string(*v)).collect::>().join(", ")); let _indenter = indenter(); let _icx = push_ctxt("match::compile_submatch"); let mut bcx = bcx; diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index b25d6f2daac..67e7aa5baf6 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -92,7 +92,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) .chain(arch_clobbers.iter() .map(|s| s.to_string())) .collect::>() - .connect(","); + .join(","); debug!("Asm Constraints: {}", &all_constraints[..]); diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs index 05d0a967e64..7d682504044 100644 --- a/src/librustc_trans/trans/build.rs +++ b/src/librustc_trans/trans/build.rs @@ -148,7 +148,7 @@ pub fn Invoke(cx: Block, terminate(cx, "Invoke"); debug!("Invoke({} with arguments ({}))", cx.val_to_string(fn_), - args.iter().map(|a| cx.val_to_string(*a)).collect::>().connect(", ")); + args.iter().map(|a| cx.val_to_string(*a)).collect::>().join(", ")); debug_loc.apply(cx.fcx); B(cx).invoke(fn_, args, then, catch, attributes) } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index e100defc248..32d9ee7a508 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -167,7 +167,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args.iter() .map(|&v| self.ccx.tn().val_to_string(v)) .collect::>() - .connect(", ")); + .join(", ")); unsafe { let v = llvm::LLVMBuildInvoke(self.llbuilder, @@ -809,7 +809,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { args.iter() .map(|&v| self.ccx.tn().val_to_string(v)) .collect::>() - .connect(", ")); + .join(", ")); unsafe { let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(), diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 45349969a0b..45d8fa67db6 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1443,7 +1443,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { let discrfield = discrfield.iter() .skip(1) .map(|x| x.to_string()) - .collect::>().connect("$"); + .collect::>().join("$"); let union_member_name = format!("RUST$ENCODED$ENUM${}${}", discrfield, null_variant_name); diff --git a/src/librustc_trans/trans/llrepr.rs b/src/librustc_trans/trans/llrepr.rs index 6dd56679797..6b785e7edfd 100644 --- a/src/librustc_trans/trans/llrepr.rs +++ b/src/librustc_trans/trans/llrepr.rs @@ -19,7 +19,7 @@ pub trait LlvmRepr { impl LlvmRepr for [T] { fn llrepr(&self, ccx: &CrateContext) -> String { let reprs: Vec = self.iter().map(|t| t.llrepr(ccx)).collect(); - format!("[{}]", reprs.connect(",")) + format!("[{}]", reprs.join(",")) } } diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index ac39d10a23d..c88509dac4c 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -322,7 +322,7 @@ impl TypeNames { pub fn types_to_str(&self, tys: &[Type]) -> String { let strs: Vec = tys.iter().map(|t| self.type_to_string(*t)).collect(); - format!("[{}]", strs.connect(",")) + format!("[{}]", strs.join(",")) } pub fn val_to_string(&self, val: ValueRef) -> String { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 4359a8d270d..36905ffe93b 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -457,7 +457,7 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let tstr = if strings.is_empty() { base } else { - format!("{}<{}>", base, strings.connect(", ")) + format!("{}<{}>", base, strings.join(", ")) }; if did.krate == 0 { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 4d86a4f7c70..f14886606c2 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -134,7 +134,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, p.self_ty(), p)) .collect::>() - .connect(", "); + .join(", "); cx.sess.fileline_note( span, &format!("the method `{}` exists but the \ diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 638cc868527..0f9ebf3713c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1002,7 +1002,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, "not all trait items implemented, missing: `{}`", missing_items.iter() .map(::as_str) - .collect::>().connect("`, `")) + .collect::>().join("`, `")) } if !invalidated_items.is_empty() { @@ -1013,7 +1013,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, invalidator.ident.as_str(), invalidated_items.iter() .map(::as_str) - .collect::>().connect("`, `")) + .collect::>().join("`, `")) } } @@ -2868,7 +2868,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, span_err!(tcx.sess, span, E0063, "missing field{}: {}", if missing_fields.len() == 1 {""} else {"s"}, - missing_fields.connect(", ")); + missing_fields.join(", ")); } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 20407e927f7..cd904425d63 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } else { name.to_string() }, a, b) - }).collect::>().connect(", ")); + }).collect::>().join(", ")); return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e170808ad07..5d2e3533efc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1536,7 +1536,7 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, d => format!("{:?}", d), }) .collect::>() - .connect(","); + .join(","); tcx.sess.span_err(it.span, &object_lifetime_default_reprs); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c25267520cc..daa4e1af338 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2536,12 +2536,12 @@ fn name_from_pat(p: &ast::Pat) -> String { format!("{} {{ {}{} }}", path_to_string(name), fields.iter().map(|&Spanned { node: ref fp, .. }| format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat))) - .collect::>().connect(", "), + .collect::>().join(", "), if etc { ", ..." } else { "" } ) }, PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) - .collect::>().connect(", ")), + .collect::>().join(", ")), PatBox(ref p) => name_from_pat(&**p), PatRegion(ref p, _) => name_from_pat(&**p), PatLit(..) => { @@ -2555,7 +2555,7 @@ fn name_from_pat(p: &ast::Pat) -> String { let begin = begin.iter().map(|p| name_from_pat(&**p)); let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); let end = end.iter().map(|p| name_from_pat(&**p)); - format!("[{}]", begin.chain(mid).chain(end).collect::>().connect(", ")) + format!("[{}]", begin.chain(mid).chain(end).collect::>().join(", ")) }, PatMac(..) => { warn!("can't document the name of a function argument \ diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9439fc3c5f4..fc06dc347b5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -360,7 +360,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, path: &clean::Path, match href(did) { Some((url, shortty, fqp)) => { try!(write!(w, "{}", - shortty, url, fqp.connect("::"), last.name)); + shortty, url, fqp.join("::"), last.name)); } _ => try!(write!(w, "{}", last.name)), } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4982215d02f..4ec4ffb0c31 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -199,7 +199,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { fn collapse_whitespace(s: &str) -> String { s.split(|c: char| c.is_whitespace()).filter(|s| { !s.is_empty() - }).collect::>().connect(" ") + }).collect::>().join(" ") } thread_local!(static USED_HEADER_MAP: RefCell> = { @@ -238,14 +238,14 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); - let text = lines.collect::>().connect("\n"); + let text = lines.collect::>().join("\n"); if rendered { return } PLAYGROUND_KRATE.with(|krate| { let mut s = String::new(); krate.borrow().as_ref().map(|krate| { let test = origtext.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) - }).collect::>().connect("\n"); + }).collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let test = test::maketest(&test, krate, false, &Default::default()); @@ -275,7 +275,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { // Transform the contents of the header into a hyphenated string let id = s.split_whitespace().map(|s| s.to_ascii_lowercase()) - .collect::>().connect("-"); + .collect::>().join("-"); // This is a terrible hack working around how hoedown gives us rendered // html for text rather than the raw text. @@ -387,7 +387,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { let lines = text.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) }); - let text = lines.collect::>().connect("\n"); + let text = lines.collect::>().join("\n"); tests.add_test(text.to_string(), block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5ecf0fe8ecf..07e3ae975d6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -285,7 +285,7 @@ impl fmt::Display for IndexItemFunctionType { let inputs: Vec = self.inputs.iter().map(|ref t| { format!("{}", t) }).collect(); - try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.connect(","))); + try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.join(","))); match self.output { Some(ref t) => try!(write!(f, "{}", t)), @@ -461,7 +461,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result { search_index.push(IndexItem { ty: shortty(item), name: item.name.clone().unwrap(), - path: fqp[..fqp.len() - 1].connect("::"), + path: fqp[..fqp.len() - 1].join("::"), desc: shorter(item.doc_value()), parent: Some(did), search_type: get_index_search_type(&item, parent_basename), @@ -957,7 +957,7 @@ impl DocFolder for Cache { self.search_index.push(IndexItem { ty: shortty(&item), name: s.to_string(), - path: path.connect("::").to_string(), + path: path.join("::").to_string(), desc: shorter(item.doc_value()), parent: parent, search_type: get_index_search_type(&item, parent_basename), @@ -1187,7 +1187,7 @@ impl Context { *slot.borrow_mut() = cx.current.clone(); }); - let mut title = cx.current.connect("::"); + let mut title = cx.current.join("::"); if pushname { if !title.is_empty() { title.push_str("::"); @@ -1393,7 +1393,7 @@ impl<'a> Item<'a> { Some(format!("{root}src/{krate}/{path}.html#{href}", root = self.cx.root_path, krate = self.cx.layout.krate, - path = path.connect("/"), + path = path.join("/"), href = href)) // If this item is not part of the local crate, then things get a little @@ -1417,7 +1417,7 @@ impl<'a> Item<'a> { }; Some(format!("{root}{path}/{file}?gotosrc={goto}", root = root, - path = path[..path.len() - 1].connect("/"), + path = path[..path.len() - 1].join("/"), file = item_path(self.item), goto = self.item.def_id.node)) } @@ -1523,7 +1523,7 @@ fn item_path(item: &clean::Item) -> String { } fn full_path(cx: &Context, item: &clean::Item) -> String { - let mut s = cx.current.connect("::"); + let mut s = cx.current.join("::"); s.push_str("::"); s.push_str(item.name.as_ref().unwrap()); return s @@ -1535,7 +1535,7 @@ fn shorter<'a>(s: Option<&'a str>) -> String { (*line).chars().any(|chr|{ !chr.is_whitespace() }) - }).collect::>().connect("\n"), + }).collect::>().join("\n"), None => "".to_string() } } @@ -1920,12 +1920,12 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, r#""#, - root_path = vec![".."; cx.current.len()].connect("/"), + root_path = vec![".."; cx.current.len()].join("/"), path = if ast_util::is_local(it.def_id) { - cx.current.connect("/") + cx.current.join("/") } else { let path = &cache.external_paths[&it.def_id]; - path[..path.len() - 1].connect("/") + path[..path.len() - 1].join("/") }, ty = shortty(it).to_static_str(), name = *it.name.as_ref().unwrap())); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 74c16127f41..6e1c8beb3ad 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -361,7 +361,7 @@ pub fn unindent(s: &str) -> String { line[min_indent..].to_string() } }).collect::>()); - unindented.connect("\n") + unindented.join("\n") } else { s.to_string() } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1ac95177860..3ce2922c4c9 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -360,7 +360,7 @@ impl Collector { let s = self.current_header.as_ref().map(|s| &**s).unwrap_or(""); format!("{}_{}", s, self.cnt) } else { - format!("{}_{}", self.names.connect("::"), self.cnt) + format!("{}_{}", self.names.join("::"), self.cnt) }; self.cnt += 1; let libs = self.libs.clone(); diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index bc13d966a10..3fe44d4809e 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -442,7 +442,7 @@ impl fmt::Display for Ipv6Addr { .iter() .map(|&seg| format!("{:x}", seg)) .collect::>() - .connect(":") + .join(":") } write!(fmt, "{}::{}", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 7d7ea371ba5..6b38762316c 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -27,7 +27,7 @@ pub fn path_name_i(idents: &[Ident]) -> String { // FIXME: Bad copies (#2543 -- same for everything else that says "bad") idents.iter().map(|i| { token::get_ident(*i).to_string() - }).collect::>().connect("::") + }).collect::>().join("::") } pub fn local_def(id: NodeId) -> DefId { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 3866f5534c2..5418b1f43e4 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -78,7 +78,7 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) .iter() .map(|x| token::get_ident(*x).to_string()) .collect::>() - .connect("::"); + .join("::"); base::MacEager::expr(cx.expr_str( sp, token::intern_and_get_ident(&string[..]))) diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 5521c68e75c..5b3887e76b4 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -465,7 +465,7 @@ pub fn parse(sess: &ParseSess, token::get_ident(bind))).to_string() } _ => panic!() - } }).collect::>().connect(" or "); + } }).collect::>().join(" or "); return Error(sp, format!( "local ambiguity: multiple parsing options: \ built-in NTs {} or {} other options.", diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 1577b50ad76..467345624c2 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -139,7 +139,7 @@ pub fn strip_doc_comment_decoration(comment: &str) -> String { let lines = vertical_trim(lines); let lines = horizontal_trim(lines); - return lines.connect("\n"); + return lines.join("\n"); } panic!("not a doc-comment: {}", comment); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 81ae607fea2..d77b529a3bf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5215,7 +5215,7 @@ impl<'a> Parser<'a> { last_span, &format!("illegal ABI: expected one of [{}], \ found `{}`", - abi::all_names().connect(", "), + abi::all_names().join(", "), the_string)); Ok(None) } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 724c0b2a892..629e3920e10 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1080,7 +1080,7 @@ impl MetricMap { .map(|(k,v)| format!("{}: {} (+/- {})", *k, v.value, v.noise)) .collect(); - v.connect(", ") + v.join(", ") } } diff --git a/src/test/auxiliary/plugin_args.rs b/src/test/auxiliary/plugin_args.rs index 5a615502a95..1920185d4e5 100644 --- a/src/test/auxiliary/plugin_args.rs +++ b/src/test/auxiliary/plugin_args.rs @@ -36,7 +36,7 @@ impl TTMacroExpander for Expander { sp: Span, _: &[ast::TokenTree]) -> Box { let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i)) - .collect::>().connect(", "); + .collect::>().join(", "); let interned = token::intern_and_get_ident(&args[..]); MacEager::expr(ecx.expr_str(sp, interned)) } diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 5cd58c0ecfb..ecee2fd0faa 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -108,7 +108,7 @@ impl fmt::Display for AsciiArt { .collect::>(); // Concatenate the lines together using a new-line. - write!(f, "{}", lines.connect("\n")) + write!(f, "{}", lines.join("\n")) } } diff --git a/src/test/run-pass/trait-to-str.rs b/src/test/run-pass/trait-to-str.rs index 8fa628def79..f5af05d872b 100644 --- a/src/test/run-pass/trait-to-str.rs +++ b/src/test/run-pass/trait-to-str.rs @@ -24,7 +24,7 @@ impl to_str for Vec { self.iter() .map(|e| e.to_string_()) .collect::>() - .connect(", ")) + .join(", ")) } } -- cgit 1.4.1-3-g733a5 From af556238ebe72d58adbcf339bd2fa0aef4e3caf9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 12 Jul 2015 15:53:04 -0700 Subject: syntax: Allow semi tokens after macro ty/path This commit expands the follow set of the `ty` and `path` macro fragments to include the semicolon token as well. A semicolon is already allowed after these tokens, so it's currently a little too restrictive to not have a semicolon allowed. For example: extern { fn foo() -> i32; // semicolon after type } fn main() { struct Foo; Foo; // semicolon after path } --- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/test/run-pass/semi-after-macro-ty.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/semi-after-macro-ty.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 03d4e21a941..634572d4694 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -501,7 +501,7 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { }, "path" | "ty" => { match *tok { - Comma | FatArrow | Colon | Eq | Gt => Ok(true), + Comma | FatArrow | Colon | Eq | Gt | Semi => Ok(true), Ident(i, _) if i.as_str() == "as" => Ok(true), _ => Ok(false) } diff --git a/src/test/run-pass/semi-after-macro-ty.rs b/src/test/run-pass/semi-after-macro-ty.rs new file mode 100644 index 00000000000..2b4304252a1 --- /dev/null +++ b/src/test/run-pass/semi-after-macro-ty.rs @@ -0,0 +1,17 @@ +// 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. + +macro_rules! foo { + ($t:ty; $p:path;) => {} +} + +fn main() { + foo!(i32; i32;); +} -- cgit 1.4.1-3-g733a5 From 4d65ef45491b62fbecdb9a24822c216aa96bb34e Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 10 Jul 2015 22:31:44 +0300 Subject: Tell unicode escapes can’t be used as bytes earlier/more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libsyntax/parse/lexer/mod.rs | 30 ++++++++++------------ src/test/parse-fail/issue-23620-invalid-escapes.rs | 8 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index edaac3b09ba..b6a3788dacc 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -738,26 +738,24 @@ impl<'a> StringReader<'a> { return match e { 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, 'x' => self.scan_byte_escape(delim, !ascii_only), - 'u' if self.curr_is('{') => { - let valid = self.scan_unicode_escape(delim); - if valid && ascii_only { - self.err_span_( - start, - self.last_pos, + 'u' => { + let valid = if self.curr_is('{') { + self.scan_unicode_escape(delim) && !ascii_only + } else { + self.err_span_(start, self.last_pos, + "incorrect unicode escape sequence"); + self.help_span_(start, self.last_pos, + "format of unicode escape sequences is `\\u{…}`"); + false + }; + if ascii_only { + self.err_span_(start, self.last_pos, "unicode escape sequences cannot be used as a byte or in \ a byte string" ); - false - } else { - valid } - } - 'u' if !ascii_only => { - self.err_span_(start, self.last_pos, - "incomplete unicode escape sequence"); - self.help_span_(start, self.last_pos, - "format of unicode escape sequences is `\\u{…}`"); - false + valid + } '\n' if delim == '"' => { self.consume_whitespace(); diff --git a/src/test/parse-fail/issue-23620-invalid-escapes.rs b/src/test/parse-fail/issue-23620-invalid-escapes.rs index 98db3efe114..1790b9164b7 100644 --- a/src/test/parse-fail/issue-23620-invalid-escapes.rs +++ b/src/test/parse-fail/issue-23620-invalid-escapes.rs @@ -16,7 +16,8 @@ fn main() { //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = b'\u'; - //~^ ERROR unknown byte escape: u + //~^ ERROR incorrect unicode escape sequence + //~^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = b'\x5'; //~^ ERROR numeric character escape is too short @@ -35,11 +36,12 @@ fn main() { let _ = b"\u{a4a4} \xf \u"; //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string //~^^ ERROR illegal character in numeric character escape: - //~^^^ ERROR unknown byte escape: u + //~^^^ ERROR incorrect unicode escape sequence + //~^^^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = "\u{ffffff} \xf \u"; //~^ ERROR illegal unicode character escape //~^^ ERROR illegal character in numeric character escape: //~^^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f] - //~^^^^ ERROR incomplete unicode escape sequence + //~^^^^ ERROR incorrect unicode escape sequence } -- cgit 1.4.1-3-g733a5 From a5d8c43687b55a561511f8eec40ff899ad9f20b7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Jul 2015 13:16:59 +0200 Subject: Improve register_diagnostics macro --- src/libsyntax/diagnostics/macros.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 055ade46a3f..8c2d2a251aa 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -63,6 +63,9 @@ macro_rules! fileline_help { macro_rules! register_diagnostics { ($($code:tt),*) => ( $(register_diagnostic! { $code })* + ); + ($($code:tt),*,) => ( + $(register_diagnostic! { $code })* ) } -- cgit 1.4.1-3-g733a5 From 6e58043e75a750a22bbc62586ec5b8f91c7d00e1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 11:21:05 +0200 Subject: Improve register_long_diagnostics macro --- src/libsyntax/diagnostics/macros.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 8c2d2a251aa..669b930ecc9 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -73,5 +73,8 @@ macro_rules! register_diagnostics { macro_rules! register_long_diagnostics { ($($code:tt: $description:tt),*) => ( $(register_diagnostic! { $code, $description })* + ); + ($($code:tt: $description:tt),*,) => ( + $(register_diagnostic! { $code, $description })* ) } -- cgit 1.4.1-3-g733a5 From 12963606d015c5f68c6e8bc51267cd2b9c8d0cfe Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Thu, 16 Jul 2015 09:22:57 +0200 Subject: Include label in the span of loops --- src/libsyntax/parse/parser.rs | 42 ++++++++++++++++++++---------------- src/test/compile-fail/issue-27042.rs | 26 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 src/test/compile-fail/issue-27042.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6e6d3c8105d..28802d323c6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2099,28 +2099,32 @@ impl<'a> Parser<'a> { return self.parse_if_expr(); } if try!(self.eat_keyword(keywords::For) ){ - return self.parse_for_expr(None); + let lo = self.last_span.lo; + return self.parse_for_expr(None, lo); } if try!(self.eat_keyword(keywords::While) ){ - return self.parse_while_expr(None); + let lo = self.last_span.lo; + return self.parse_while_expr(None, lo); } if self.token.is_lifetime() { let lifetime = self.get_lifetime(); + let lo = self.span.lo; try!(self.bump()); try!(self.expect(&token::Colon)); if try!(self.eat_keyword(keywords::While) ){ - return self.parse_while_expr(Some(lifetime)) + return self.parse_while_expr(Some(lifetime), lo) } if try!(self.eat_keyword(keywords::For) ){ - return self.parse_for_expr(Some(lifetime)) + return self.parse_for_expr(Some(lifetime), lo) } if try!(self.eat_keyword(keywords::Loop) ){ - return self.parse_loop_expr(Some(lifetime)) + return self.parse_loop_expr(Some(lifetime), lo) } return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if try!(self.eat_keyword(keywords::Loop) ){ - return self.parse_loop_expr(None); + let lo = self.last_span.lo; + return self.parse_loop_expr(None, lo); } if try!(self.eat_keyword(keywords::Continue) ){ let lo = self.span.lo; @@ -2892,48 +2896,48 @@ impl<'a> Parser<'a> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - pub fn parse_for_expr(&mut self, opt_ident: Option) -> PResult> { + pub fn parse_for_expr(&mut self, opt_ident: Option, + span_lo: BytePos) -> PResult> { // Parse: `for in ` - let lo = self.last_span.lo; let pat = try!(self.parse_pat_nopanic()); try!(self.expect_keyword(keywords::In)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let loop_block = try!(self.parse_block()); let hi = self.last_span.hi; - Ok(self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))) + Ok(self.mk_expr(span_lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) - pub fn parse_while_expr(&mut self, opt_ident: Option) -> PResult> { + pub fn parse_while_expr(&mut self, opt_ident: Option, + span_lo: BytePos) -> PResult> { if self.token.is_keyword(keywords::Let) { - return self.parse_while_let_expr(opt_ident); + return self.parse_while_let_expr(opt_ident, span_lo); } - let lo = self.last_span.lo; let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let body = try!(self.parse_block()); let hi = body.span.hi; - return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident))); + return Ok(self.mk_expr(span_lo, hi, ExprWhile(cond, body, opt_ident))); } /// Parse a 'while let' expression ('while' token already eaten) - pub fn parse_while_let_expr(&mut self, opt_ident: Option) -> PResult> { - let lo = self.last_span.lo; + pub fn parse_while_let_expr(&mut self, opt_ident: Option, + span_lo: BytePos) -> PResult> { try!(self.expect_keyword(keywords::Let)); let pat = try!(self.parse_pat_nopanic()); try!(self.expect(&token::Eq)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let body = try!(self.parse_block()); let hi = body.span.hi; - return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident))); + return Ok(self.mk_expr(span_lo, hi, ExprWhileLet(pat, expr, body, opt_ident))); } - pub fn parse_loop_expr(&mut self, opt_ident: Option) -> PResult> { - let lo = self.last_span.lo; + pub fn parse_loop_expr(&mut self, opt_ident: Option, + span_lo: BytePos) -> PResult> { let body = try!(self.parse_block()); let hi = body.span.hi; - Ok(self.mk_expr(lo, hi, ExprLoop(body, opt_ident))) + Ok(self.mk_expr(span_lo, hi, ExprLoop(body, opt_ident))) } fn parse_match_expr(&mut self) -> PResult> { diff --git a/src/test/compile-fail/issue-27042.rs b/src/test/compile-fail/issue-27042.rs new file mode 100644 index 00000000000..f31389f1337 --- /dev/null +++ b/src/test/compile-fail/issue-27042.rs @@ -0,0 +1,26 @@ +// Copyright 2012-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. + +// Regression test for #27042. Test that a loop's label is included in its span. + +fn main() { + let _: i32 = + 'a: //~ ERROR mismatched types + loop { break }; + let _: i32 = + 'b: //~ ERROR mismatched types + while true { break }; + let _: i32 = + 'c: //~ ERROR mismatched types + for _ in None { break }; + let _: i32 = + 'd: //~ ERROR mismatched types + while let Some(_) = None { break }; +} -- cgit 1.4.1-3-g733a5 From a219917e3f762af49f5ccf7a0975122e04f9d764 Mon Sep 17 00:00:00 2001 From: Lee Jeffery Date: Wed, 15 Jul 2015 19:57:47 +0100 Subject: Fix doc comment parsing in macros. --- src/libcore/str/mod.rs | 20 ++++++------- src/libsyntax/ast.rs | 18 +++++++++-- src/test/parse-fail/macro-doc-comments-1.rs | 19 ++++++++++++ src/test/parse-fail/macro-doc-comments-2.rs | 19 ++++++++++++ src/test/run-pass/macro-doc-comments.rs | 33 +++++++++++++++++++++ src/test/rustdoc/issue-23812.rs | 46 +++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 src/test/parse-fail/macro-doc-comments-1.rs create mode 100644 src/test/parse-fail/macro-doc-comments-2.rs create mode 100644 src/test/run-pass/macro-doc-comments.rs create mode 100644 src/test/rustdoc/issue-23812.rs (limited to 'src/libsyntax') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e4c2ba3be8..8683689bbbe 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -636,10 +636,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split()`."] + /// Created with the method `.split()`. struct Split; reverse: - #[doc="Created with the method `.rsplit()`."] + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -650,10 +650,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split_terminator()`."] + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - #[doc="Created with the method `.rsplit_terminator()`."] + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -696,10 +696,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.splitn()`."] + /// Created with the method `.splitn()`. struct SplitN; reverse: - #[doc="Created with the method `.rsplitn()`."] + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -730,10 +730,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.match_indices()`."] + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - #[doc="Created with the method `.rmatch_indices()`."] + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "str_match_indices", @@ -771,10 +771,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.matches()`."] + /// Created with the method `.matches()`. struct Matches; reverse: - #[doc="Created with the method `.rmatches()`."] + /// Created with the method `.rmatches()`. struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a944acad84d..a0059d33bed 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -63,6 +63,7 @@ use owned_slice::OwnedSlice; use parse::token::{InternedString, str_to_ident}; use parse::token; use parse::lexer; +use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use print::pprust; use ptr::P; @@ -1079,7 +1080,12 @@ pub enum TokenTree { impl TokenTree { pub fn len(&self) -> usize { match *self { - TtToken(_, token::DocComment(_)) => 2, + TtToken(_, token::DocComment(name)) => { + match doc_comment_style(name.as_str()) { + AttrOuter => 2, + AttrInner => 3 + } + } TtToken(_, token::SpecialVarNt(..)) => 2, TtToken(_, token::MatchNt(..)) => 3, TtDelimited(_, ref delimed) => { @@ -1097,14 +1103,20 @@ impl TokenTree { (&TtToken(sp, token::DocComment(_)), 0) => { TtToken(sp, token::Pound) } - (&TtToken(sp, token::DocComment(name)), 1) => { + (&TtToken(sp, token::DocComment(name)), 1) + if doc_comment_style(name.as_str()) == AttrInner => { + TtToken(sp, token::Not) + } + (&TtToken(sp, token::DocComment(name)), _) => { + let stripped = strip_doc_comment_decoration(name.as_str()); TtDelimited(sp, Rc::new(Delimited { delim: token::Bracket, open_span: sp, tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::StrRaw(name, 0), None))], + TtToken(sp, token::Literal( + token::StrRaw(token::intern(&stripped), 0), None))], close_span: sp, })) } diff --git a/src/test/parse-fail/macro-doc-comments-1.rs b/src/test/parse-fail/macro-doc-comments-1.rs new file mode 100644 index 00000000000..03bcef4fa5e --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-1.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! outer { + (#[$outer:meta]) => () +} + +outer! { + //! Inner +} //~^ ERROR no rules expected the token `!` + +fn main() { } diff --git a/src/test/parse-fail/macro-doc-comments-2.rs b/src/test/parse-fail/macro-doc-comments-2.rs new file mode 100644 index 00000000000..a1b112c29b6 --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-2.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! inner { + (#![$inner:meta]) => () +} + +inner! { + /// Outer +} //~^ ERROR no rules expected the token `[` + +fn main() { } diff --git a/src/test/run-pass/macro-doc-comments.rs b/src/test/run-pass/macro-doc-comments.rs new file mode 100644 index 00000000000..506813df5b3 --- /dev/null +++ b/src/test/run-pass/macro-doc-comments.rs @@ -0,0 +1,33 @@ +// 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. + +macro_rules! doc { + ( + $(#[$outer:meta])* + mod $i:ident { + $(#![$inner:meta])* + } + ) => + ( + $(#[$outer])* + pub mod $i { + $(#![$inner])* + } + ) +} + +doc! { + /// Outer doc + mod Foo { + //! Inner doc + } +} + +fn main() { } diff --git a/src/test/rustdoc/issue-23812.rs b/src/test/rustdoc/issue-23812.rs new file mode 100644 index 00000000000..37f6749694c --- /dev/null +++ b/src/test/rustdoc/issue-23812.rs @@ -0,0 +1,46 @@ +// 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. + +macro_rules! doc { + (#[$outer:meta] mod $i:ident { #![$inner:meta] }) => + ( + #[$outer] + pub mod $i { + #![$inner] + } + ) +} + +doc! { + /// Outer comment + mod Foo { + //! Inner comment + } +} + +// @has issue_23812/Foo/index.html +// @has - 'Outer comment' +// @!has - '/// Outer comment' +// @has - 'Inner comment' +// @!has - '//! Inner comment' + + +doc! { + /** Outer block comment */ + mod Bar { + /*! Inner block comment */ + } +} + +// @has issue_23812/Bar/index.html +// @has - 'Outer block comment' +// @!has - '/** Outer block comment */' +// @has - 'Inner block comment' +// @!has - '/*! Inner block comment */' -- cgit 1.4.1-3-g733a5 From 013d47b19b25b94e9740f725425bc836bac6efde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Jul 2015 09:23:31 -0700 Subject: syntax: Suppress panic message on `fatal` This commit ensures that the rustc thread does not leak a panic message whenever a call to `fatal` happens. This already happens for the main rustc thread as part of the `rustc_driver::monitor` function, but the compiler also spawns threads for other operations like `-C codegen-units`, and sometimes errors are emitted on these threads as well. To ensure that there's a consistent error-handling experience across threads this unifies these two to never print the panic message in the case of a normal and expected fatal error. This should also fix the flaky `asm-src-loc-codegen-units.rs` test as the output is sometimes garbled if diagnostics are printed while the panic message is also being printed. --- src/libsyntax/diagnostic.rs | 4 ++++ src/libsyntax/lib.rs | 1 + 2 files changed, 5 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index fbf015169f8..e95813e44ba 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -208,6 +208,10 @@ impl Handler { } pub fn fatal(&self, msg: &str) -> ! { self.emit.borrow_mut().emit(None, msg, None, Fatal); + + // Suppress the fatal error message from the panic below as we've + // already terminated in our own "legitimate" fashion. + io::set_panic(Box::new(io::sink())); panic!(FatalError); } pub fn err(&self, msg: &str) { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7333265bdd4..d93af5da13c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,6 +32,7 @@ #![feature(libc)] #![feature(ref_slice)] #![feature(rustc_private)] +#![feature(set_stdio)] #![feature(staged_api)] #![feature(str_char)] #![feature(str_escape)] -- cgit 1.4.1-3-g733a5 From 007246c17f1891cabb84c8a82250703f542cd58e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 2 Jul 2015 15:37:52 +1200 Subject: Allow for space between each filemap in the codemap So if a filemap's last byte is at position n in the codemap, then n+1 will not refer to any filemap, and the next filemap will begin an n+2. This is useful for empty files, it means that every file (even empty ones) has a byte in the codemap. Closes #23301, #26504 --- src/libsyntax/codemap.rs | 162 ++++++++++++++++++++++++-------------------- src/libsyntax/diagnostic.rs | 13 ++-- 2 files changed, 97 insertions(+), 78 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5ddcfaef9ea..2f109b589f1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -115,6 +115,10 @@ impl Sub for CharPos { /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back /// to the original source. +/// You must be careful if the span crosses more than one file - you will not be +/// able to use many of the functions on spans in codemap and you cannot assume +/// that the length of the span = hi - lo; there may be space in the BytePos +/// range between files. #[derive(Clone, Copy, Hash)] pub struct Span { pub lo: BytePos, @@ -339,7 +343,7 @@ pub struct MultiByteChar { pub bytes: usize, } -/// A single source in the CodeMap +/// A single source in the CodeMap. pub struct FileMap { /// The name of the file that the source came from, source that doesn't /// originate from files has names between angle brackets by convention, @@ -508,6 +512,9 @@ impl FileMap { lines.get(line_number).map(|&line| { let begin: BytePos = line - self.start_pos; let begin = begin.to_usize(); + // We can't use `lines.get(line_number+1)` because we might + // be parsing when we call this function and thus the current + // line is the last one we have line info for. let slice = &src[begin..]; match slice.find('\n') { Some(e) => &slice[..e], @@ -598,27 +605,27 @@ impl CodeMap { Ok(self.new_filemap(path.to_str().unwrap().to_string(), src)) } + fn next_start_pos(&self) -> usize { + let files = self.files.borrow(); + match files.last() { + None => 0, + // Add one so there is some space between files. This lets us distinguish + // positions in the codemap, even in the presence of zero-length files. + Some(last) => last.end_pos.to_usize() + 1, + } + } + + /// Creates a new filemap without setting its line information. If you don't + /// intend to set the line information yourself, you should use new_filemap_and_lines. pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; // Remove utf-8 BOM if any. if src.starts_with("\u{feff}") { src.drain(..3); } - // Append '\n' in case it's not already there. - // This is a workaround to prevent CodeMap.lookup_filemap_idx from - // accidentally overflowing into the next filemap in case the last byte - // of span is also the last byte of filemap, which leads to incorrect - // results from CodeMap.span_to_*. - if !src.is_empty() && !src.ends_with("\n") { - src.push('\n'); - } - let end_pos = start_pos + src.len(); let filemap = Rc::new(FileMap { @@ -645,11 +652,8 @@ impl CodeMap { mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; let end_pos = Pos::from_usize(start_pos + source_len); let start_pos = Pos::from_usize(start_pos); @@ -686,39 +690,61 @@ impl CodeMap { /// Lookup source information about a BytePos pub fn lookup_char_pos(&self, pos: BytePos) -> Loc { - let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); - let line = a + 1; // Line numbers start at 1 let chpos = self.bytepos_to_file_charpos(pos); - let linebpos = (*f.lines.borrow())[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - debug!("byte pos {:?} is on the line at byte pos {:?}", - pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", - chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - Loc { - file: f, - line: line, - col: chpos - linechpos + match self.lookup_line(pos) { + Ok(FileMapAndLine { fm: f, line: a }) => { + let line = a + 1; // Line numbers start at 1 + let linebpos = (*f.lines.borrow())[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + debug!("byte pos {:?} is on the line at byte pos {:?}", + pos, linebpos); + debug!("char pos {:?} is on the line at char pos {:?}", + chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + Loc { + file: f, + line: line, + col: chpos - linechpos, + } + } + Err(f) => { + Loc { + file: f, + line: 0, + col: chpos, + } + } } } - fn lookup_line(&self, pos: BytePos) -> FileMapAndLine { + // If the relevant filemap is empty, we don't return a line number. + fn lookup_line(&self, pos: BytePos) -> Result> { let idx = self.lookup_filemap_idx(pos); let files = self.files.borrow(); let f = (*files)[idx].clone(); + + let len = f.lines.borrow().len(); + if len == 0 { + return Err(f); + } + let mut a = 0; { let lines = f.lines.borrow(); let mut b = lines.len(); while b - a > 1 { let m = (a + b) / 2; - if (*lines)[m] > pos { b = m; } else { a = m; } + if (*lines)[m] > pos { + b = m; + } else { + a = m; + } } + assert!(a <= lines.len()); } - FileMapAndLine {fm: f, line: a} + Ok(FileMapAndLine { fm: f, line: a }) } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -880,12 +906,15 @@ impl CodeMap { CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes) } + // Return the index of the filemap (in self.files) which contains pos. fn lookup_filemap_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &*files; - let len = files.len(); + let count = files.len(); + + // Binary search for the filemap. let mut a = 0; - let mut b = len; + let mut b = count; while b - a > 1 { let m = (a + b) / 2; if files[m].start_pos > pos { @@ -894,26 +923,8 @@ impl CodeMap { a = m; } } - // There can be filemaps with length 0. These have the same start_pos as - // the previous filemap, but are not the filemaps we want (because they - // are length 0, they cannot contain what we are looking for). So, - // rewind until we find a useful filemap. - loop { - let lines = files[a].lines.borrow(); - let lines = lines; - if !lines.is_empty() { - break; - } - if a == 0 { - panic!("position {} does not resolve to a source location", - pos.to_usize()); - } - a -= 1; - } - if a >= len { - panic!("position {} does not resolve to a source location", - pos.to_usize()) - } + + assert!(a < count, "position {} does not resolve to a source location", pos.to_usize()); return a; } @@ -1027,10 +1038,13 @@ mod tests { let fm = cm.new_filemap("blork.rs".to_string(), "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); + // Test we can get lines with partial line info. assert_eq!(fm.get_line(0), Some("first line.")); - // TESTING BROKEN BEHAVIOR: + // TESTING BROKEN BEHAVIOR: line break declared before actual line break. fm.next_line(BytePos(10)); assert_eq!(fm.get_line(1), Some(".")); + fm.next_line(BytePos(12)); + assert_eq!(fm.get_line(2), Some("second line")); } #[test] @@ -1056,9 +1070,9 @@ mod tests { fm1.next_line(BytePos(0)); fm1.next_line(BytePos(12)); - fm2.next_line(BytePos(24)); - fm3.next_line(BytePos(24)); - fm3.next_line(BytePos(34)); + fm2.next_line(fm2.start_pos); + fm3.next_line(fm3.start_pos); + fm3.next_line(fm3.start_pos + BytePos(12)); cm } @@ -1068,11 +1082,15 @@ mod tests { // Test lookup_byte_offset let cm = init_code_map(); - let fmabp1 = cm.lookup_byte_offset(BytePos(22)); + let fmabp1 = cm.lookup_byte_offset(BytePos(23)); assert_eq!(fmabp1.fm.name, "blork.rs"); - assert_eq!(fmabp1.pos, BytePos(22)); + assert_eq!(fmabp1.pos, BytePos(23)); + + let fmabp1 = cm.lookup_byte_offset(BytePos(24)); + assert_eq!(fmabp1.fm.name, "empty.rs"); + assert_eq!(fmabp1.pos, BytePos(0)); - let fmabp2 = cm.lookup_byte_offset(BytePos(24)); + let fmabp2 = cm.lookup_byte_offset(BytePos(25)); assert_eq!(fmabp2.fm.name, "blork2.rs"); assert_eq!(fmabp2.pos, BytePos(0)); } @@ -1085,7 +1103,7 @@ mod tests { let cp1 = cm.bytepos_to_file_charpos(BytePos(22)); assert_eq!(cp1, CharPos(22)); - let cp2 = cm.bytepos_to_file_charpos(BytePos(24)); + let cp2 = cm.bytepos_to_file_charpos(BytePos(25)); assert_eq!(cp2, CharPos(0)); } @@ -1099,7 +1117,7 @@ mod tests { assert_eq!(loc1.line, 2); assert_eq!(loc1.col, CharPos(10)); - let loc2 = cm.lookup_char_pos(BytePos(24)); + let loc2 = cm.lookup_char_pos(BytePos(25)); assert_eq!(loc2.file.name, "blork2.rs"); assert_eq!(loc2.line, 1); assert_eq!(loc2.col, CharPos(0)); @@ -1115,18 +1133,18 @@ mod tests { "first line€€.\n€ second line".to_string()); fm1.next_line(BytePos(0)); - fm1.next_line(BytePos(22)); - fm2.next_line(BytePos(40)); - fm2.next_line(BytePos(58)); + fm1.next_line(BytePos(28)); + fm2.next_line(fm2.start_pos); + fm2.next_line(fm2.start_pos + BytePos(20)); fm1.record_multibyte_char(BytePos(3), 3); fm1.record_multibyte_char(BytePos(9), 3); fm1.record_multibyte_char(BytePos(12), 3); fm1.record_multibyte_char(BytePos(15), 3); fm1.record_multibyte_char(BytePos(18), 3); - fm2.record_multibyte_char(BytePos(50), 3); - fm2.record_multibyte_char(BytePos(53), 3); - fm2.record_multibyte_char(BytePos(58), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(10), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(13), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(18), 3); cm } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index fbf015169f8..60f713b5289 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -854,11 +854,12 @@ mod test { println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; - println!("{}", from_utf8(vec).unwrap()); - assert_eq!(vec, "dummy.txt: 8 \n\ - dummy.txt: 9 \n\ - dummy.txt:10 \n\ - dummy.txt:11 \n\ - dummy.txt:12 \n".as_bytes()); + let str = from_utf8(vec).unwrap(); + println!("{}", str); + assert_eq!(str, "dummy.txt: 8 line8\n\ + dummy.txt: 9 line9\n\ + dummy.txt:10 line10\n\ + dummy.txt:11 e-lä-vän\n\ + dummy.txt:12 tolv\n"); } } -- cgit 1.4.1-3-g733a5 From 0e907fa542d7bfa08ca1f55512ffa4a5ff70ed15 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 2 Jul 2015 17:14:14 +1200 Subject: Provide a filemap ctor with line info --- src/libsyntax/codemap.rs | 30 ++++++++++++++++-------------- src/libsyntax/diagnostic.rs | 7 +------ src/libsyntax/ext/source_util.rs | 4 ++-- 3 files changed, 19 insertions(+), 22 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2f109b589f1..3e5c10702b6 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -642,6 +642,21 @@ impl CodeMap { filemap } + /// Creates a new filemap and sets its line information. + pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { + let fm = self.new_filemap(filename.to_string(), src.to_owned()); + let mut byte_pos: u32 = 0; + for line in src.lines() { + // register the start of this line + fm.next_line(BytePos(byte_pos)); + + // update byte_pos to include this line and the \n at the end + byte_pos += line.len() as u32 + 1; + } + fm + } + + /// Allocates a new FileMap representing a source file from an external /// crate. The source code of such an "imported filemap" is not available, /// but we still know enough to generate accurate debuginfo location @@ -1190,19 +1205,6 @@ mod tests { Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } - fn new_filemap_and_lines(cm: &CodeMap, filename: &str, input: &str) -> Rc { - let fm = cm.new_filemap(filename.to_string(), input.to_string()); - let mut byte_pos: u32 = 0; - for line in input.lines() { - // register the start of this line - fm.next_line(BytePos(byte_pos)); - - // update byte_pos to include this line and the \n at the end - byte_pos += line.len() as u32 + 1; - } - fm - } - /// Test span_to_snippet and span_to_lines for a span coverting 3 /// lines in the middle of a file. #[test] @@ -1210,7 +1212,7 @@ mod tests { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ^~\n~~~\n~~~~~ \n \n"; - new_filemap_and_lines(&cm, "blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", inputtext); let span = span_from_selection(inputtext, selection); // check that we are extracting the text we thought we were extracting diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 60f713b5289..22aea1ce079 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -837,12 +837,7 @@ mod test { tolv dreizehn "; - let file = cm.new_filemap("dummy.txt".to_string(), content.to_string()); - for (i, b) in content.bytes().enumerate() { - if b == b'\n' { - file.next_line(BytePos(i as u32)); - } - } + let file = cm.new_filemap_and_lines("dummy.txt", content); let start = file.lines.borrow()[7]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 5418b1f43e4..22517dc5f1b 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -156,7 +156,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // dependency information let filename = format!("{}", file.display()); let interned = token::intern_and_get_ident(&src[..]); - cx.codemap().new_filemap(filename, src); + cx.codemap().new_filemap_and_lines(&filename, &src); base::MacEager::expr(cx.expr_str(sp, interned)) } @@ -187,7 +187,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // Add this input file to the code map to make it available as // dependency information, but don't enter it's contents let filename = format!("{}", file.display()); - cx.codemap().new_filemap(filename, "".to_string()); + cx.codemap().new_filemap_and_lines(&filename, ""); base::MacEager::expr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } -- cgit 1.4.1-3-g733a5 From f47d20aecdcd7db34d41ad1666fd3eee095cc943 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 6 Jul 2015 14:13:19 +1200 Subject: Use a span from the correct file for the inner span of a module This basically only affects modules which are empty (or only contain comments). Closes #26755 --- src/librustdoc/clean/mod.rs | 4 ++++ src/libsyntax/codemap.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 1 + src/libsyntax/parse/mod.rs | 11 +++++++++-- src/libsyntax/parse/parser.rs | 24 ++++++++++++++---------- 5 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cc24550297..d4eeaa1de10 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1947,6 +1947,10 @@ impl Span { impl Clean for syntax::codemap::Span { fn clean(&self, cx: &DocContext) -> Span { + if *self == DUMMY_SP { + return Span::empty(); + } + let cm = cx.sess().codemap(); let filename = cm.span_to_filename(*self); let lo = cm.lookup_char_pos(self.lo); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3e5c10702b6..e6bc3218897 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -894,7 +894,7 @@ impl CodeMap { FileMapAndBytePos {fm: fm, pos: offset} } - /// Converts an absolute BytePos to a CharPos relative to the filemap and above. + /// Converts an absolute BytePos to a CharPos relative to the filemap. pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_filemap_idx(bpos); let files = self.files.borrow(); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b6a3788dacc..621335ecd97 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -231,6 +231,7 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; + self.peek_span = codemap::mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.last_pos; self.peek_tok = self.next_token_inner(); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index d6c28d41447..34a63fc92fe 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -11,7 +11,7 @@ //! The main parser interface use ast; -use codemap::{Span, CodeMap, FileMap}; +use codemap::{self, Span, CodeMap, FileMap}; use diagnostic::{SpanHandler, Handler, Auto, FatalError}; use parse::attr::ParserAttr; use parse::parser::Parser; @@ -203,7 +203,14 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, cfg: ast::CrateConfig) -> Parser<'a> { - tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg) + let end_pos = filemap.end_pos; + let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg); + + if parser.token == token::Eof && parser.span == codemap::DUMMY_SP { + parser.span = codemap::mk_sp(end_pos, end_pos); + } + + parser } // must preserve old name for now, because quote! from the *existing* diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 28802d323c6..db1b2489f1d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4824,8 +4824,14 @@ impl<'a> Parser<'a> { return Err(self.fatal(&format!("expected item, found `{}`", token_str))); } + let hi = if self.span == codemap::DUMMY_SP { + inner_lo + } else { + self.span.lo + }; + Ok(ast::Mod { - inner: mk_sp(inner_lo, self.span.lo), + inner: mk_sp(inner_lo, hi), items: items }) } @@ -4869,8 +4875,7 @@ impl<'a> Parser<'a> { fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) { let default_path = self.id_to_interned_str(id); - let file_path = match ::attr::first_attr_value_str_by_name(attrs, - "path") { + let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") { Some(d) => d, None => default_path, }; @@ -5003,13 +5008,12 @@ impl<'a> Parser<'a> { included_mod_stack.push(path.clone()); drop(included_mod_stack); - let mut p0 = - new_sub_parser_from_file(self.sess, - self.cfg.clone(), - &path, - owns_directory, - Some(name), - id_sp); + let mut p0 = new_sub_parser_from_file(self.sess, + self.cfg.clone(), + &path, + owns_directory, + Some(name), + id_sp); let mod_inner_lo = p0.span.lo; let mod_attrs = p0.parse_inner_attributes(); let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo)); -- cgit 1.4.1-3-g733a5 From b36d107b83388606ed4ce2b58941f0d905983958 Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Tue, 21 Jul 2015 23:04:23 +0200 Subject: Assign proper span to range expression --- src/libsyntax/parse/parser.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 28802d323c6..be13f9a130e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2738,14 +2738,15 @@ impl<'a> Parser<'a> { // (much lower than other prefix expressions) to be consistent // with the postfix-form 'expr..' let lo = self.span.lo; + let mut hi = self.span.hi; try!(self.bump()); let opt_end = if self.is_at_start_of_range_notation_rhs() { let end = try!(self.parse_binops()); + hi = end.span.hi; Some(end) } else { None }; - let hi = self.span.hi; let ex = self.mk_range(None, opt_end); Ok(self.mk_expr(lo, hi, ex)) } @@ -2787,17 +2788,17 @@ impl<'a> Parser<'a> { } // A range expression, either `expr..expr` or `expr..`. token::DotDot => { + let lo = lhs.span.lo; + let mut hi = self.span.hi; try!(self.bump()); let opt_end = if self.is_at_start_of_range_notation_rhs() { let end = try!(self.parse_binops()); + hi = end.span.hi; Some(end) } else { None }; - - let lo = lhs.span.lo; - let hi = self.span.hi; let range = self.mk_range(Some(lhs), opt_end); return Ok(self.mk_expr(lo, hi, range)); } -- cgit 1.4.1-3-g733a5 From 1829fa5199bae5a192c771807c532badce14be37 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 5 Jun 2015 08:31:27 +0200 Subject: Hack for "unsafety hygiene" -- `push_unsafe!` and `pop_unsafe!`. Even after expansion, the generated expressions still track depth of such pushes (i.e. how often you have "pushed" without a corresponding "pop"), and we add a rule that in a context with a positive `push_unsafe!` depth, it is effectively an `unsafe` block context. (This way, we can inject code that uses `unsafe` features, but still contains within it a sub-expression that should inherit the outer safety checking setting, outside of the injected code.) This is a total hack; it not only needs a feature-gate, but probably should be feature-gated forever (if possible). ignore-pretty in test/run-pass/pushpop-unsafe-okay.rs --- src/librustc/middle/effect.rs | 37 +++++++-- src/librustc_typeck/check/mod.rs | 20 +++-- src/libsyntax/ast.rs | 2 + src/libsyntax/ext/base.rs | 6 ++ src/libsyntax/ext/expand.rs | 1 + src/libsyntax/ext/pushpop_safe.rs | 94 ++++++++++++++++++++++ src/libsyntax/feature_gate.rs | 11 +++ src/libsyntax/lib.rs | 1 + src/libsyntax/print/pprust.rs | 4 +- .../compile-fail/feature-gate-pushpop-unsafe.rs | 14 ++++ src/test/compile-fail/pushpop-unsafe-rejects.rs | 71 ++++++++++++++++ src/test/run-pass/pushpop-unsafe-okay.rs | 56 +++++++++++++ 12 files changed, 301 insertions(+), 16 deletions(-) create mode 100644 src/libsyntax/ext/pushpop_safe.rs create mode 100644 src/test/compile-fail/feature-gate-pushpop-unsafe.rs create mode 100644 src/test/compile-fail/pushpop-unsafe-rejects.rs create mode 100644 src/test/run-pass/pushpop-unsafe-okay.rs (limited to 'src/libsyntax') diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index b2a064bf86c..a2e42245bbe 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -10,7 +10,7 @@ //! Enforces the Rust effect system. Currently there is just one effect, //! `unsafe`. -use self::UnsafeContext::*; +use self::RootUnsafeContext::*; use middle::def; use middle::ty::{self, Ty}; @@ -21,8 +21,20 @@ use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; +#[derive(Copy, Clone)] +struct UnsafeContext { + push_unsafe_count: usize, + root: RootUnsafeContext, +} + +impl UnsafeContext { + fn new(root: RootUnsafeContext) -> UnsafeContext { + UnsafeContext { root: root, push_unsafe_count: 0 } + } +} + #[derive(Copy, Clone, PartialEq)] -enum UnsafeContext { +enum RootUnsafeContext { SafeContext, UnsafeFn, UnsafeBlock(ast::NodeId), @@ -44,7 +56,8 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { fn require_unsafe(&mut self, span: Span, description: &str) { - match self.unsafe_context { + if self.unsafe_context.push_unsafe_count > 0 { return; } + match self.unsafe_context.root { SafeContext => { // Report an error. span_err!(self.tcx.sess, span, E0133, @@ -75,9 +88,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { let old_unsafe_context = self.unsafe_context; if is_unsafe_fn { - self.unsafe_context = UnsafeFn + self.unsafe_context = UnsafeContext::new(UnsafeFn) } else if is_item_fn { - self.unsafe_context = SafeContext + self.unsafe_context = UnsafeContext::new(SafeContext) } visit::walk_fn(self, fn_kind, fn_decl, block, span); @@ -105,10 +118,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { // external blocks (e.g. `unsafe { println("") }`, // expands to `unsafe { ... unsafe { ... } }` where // the inner one is compiler generated). - if self.unsafe_context == SafeContext || source == ast::CompilerGenerated { - self.unsafe_context = UnsafeBlock(block.id) + if self.unsafe_context.root == SafeContext || source == ast::CompilerGenerated { + self.unsafe_context.root = UnsafeBlock(block.id) } } + ast::PushUnsafeBlock(..) => { + self.unsafe_context.push_unsafe_count = + self.unsafe_context.push_unsafe_count.saturating_add(1); + } + ast::PopUnsafeBlock(..) => { + self.unsafe_context.push_unsafe_count = + self.unsafe_context.push_unsafe_count.saturating_sub(1); + } } visit::walk_block(self, block); @@ -162,7 +183,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { pub fn check_crate(tcx: &ty::ctxt) { let mut visitor = EffectCheckVisitor { tcx: tcx, - unsafe_context: SafeContext, + unsafe_context: UnsafeContext::new(SafeContext), }; visit::walk_crate(&mut visitor, tcx.map.krate()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fdeed657e07..d6afd72d3b4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -231,12 +231,13 @@ impl<'tcx> Expectation<'tcx> { pub struct UnsafetyState { pub def: ast::NodeId, pub unsafety: ast::Unsafety, + pub unsafe_push_count: u32, from_fn: bool } impl UnsafetyState { pub fn function(unsafety: ast::Unsafety, def: ast::NodeId) -> UnsafetyState { - UnsafetyState { def: def, unsafety: unsafety, from_fn: true } + UnsafetyState { def: def, unsafety: unsafety, unsafe_push_count: 0, from_fn: true } } pub fn recurse(&mut self, blk: &ast::Block) -> UnsafetyState { @@ -248,13 +249,20 @@ impl UnsafetyState { ast::Unsafety::Unsafe if self.from_fn => *self, unsafety => { - let (unsafety, def) = match blk.rules { - ast::UnsafeBlock(..) => (ast::Unsafety::Unsafe, blk.id), - ast::DefaultBlock => (unsafety, self.def), + let (unsafety, def, count) = match blk.rules { + ast::PushUnsafeBlock(..) => + (unsafety, blk.id, self.unsafe_push_count.saturating_add(1)), + ast::PopUnsafeBlock(..) => + (unsafety, blk.id, self.unsafe_push_count.saturating_sub(1)), + ast::UnsafeBlock(..) => + (ast::Unsafety::Unsafe, blk.id, self.unsafe_push_count), + ast::DefaultBlock => + (unsafety, self.def, self.unsafe_push_count), }; UnsafetyState{ def: def, - unsafety: unsafety, - from_fn: false } + unsafety: unsafety, + unsafe_push_count: count, + from_fn: false } } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a0059d33bed..fba9db401db 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -810,6 +810,8 @@ pub type SpannedIdent = Spanned; pub enum BlockCheckMode { DefaultBlock, UnsafeBlock(UnsafeSource), + PushUnsafeBlock(UnsafeSource), + PopUnsafeBlock(UnsafeSource), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 499562edc0c..409ae86db35 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -591,6 +591,12 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders.insert(intern("cfg"), builtin_normal_expander( ext::cfg::expand_cfg)); + syntax_expanders.insert(intern("push_unsafe"), + builtin_normal_expander( + ext::pushpop_safe::expand_push_unsafe)); + syntax_expanders.insert(intern("pop_unsafe"), + builtin_normal_expander( + ext::pushpop_safe::expand_pop_unsafe)); syntax_expanders.insert(intern("trace_macros"), builtin_normal_expander( ext::trace_macros::expand_trace_macros)); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 53befc092da..b540e0adeea 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1504,6 +1504,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_trace_macros = allow_trace_macros, fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = allow_custom_derive, + fn enable_pushpop_unsafe = allow_pushpop_unsafe, } } diff --git a/src/libsyntax/ext/pushpop_safe.rs b/src/libsyntax/ext/pushpop_safe.rs new file mode 100644 index 00000000000..fee445cd31a --- /dev/null +++ b/src/libsyntax/ext/pushpop_safe.rs @@ -0,0 +1,94 @@ +// 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. + +/* + * The compiler code necessary to support the `push_unsafe!` and + * `pop_unsafe!` macros. + * + * This is a hack to allow a kind of "safety hygiene", where a macro + * can generate code with an interior expression that inherits the + * safety of some outer context. + * + * For example, in: + * + * ```rust + * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } + * ``` + * + * the `EXPR_1` is considered to be in an `unsafe` context, + * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context. + * + * For comparison, in: + * + * ```rust + * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } } + * ``` + * + * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe` + * contexts. + * + */ + +use ast; +use codemap::Span; +use ext::base::*; +use ext::base; +use ext::build::AstBuilder; +use feature_gate; +use ptr::P; + +enum PushPop { Push, Pop } + +pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { + feature_gate::check_for_pushpop_syntax( + cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); + expand_pushpop_unsafe(cx, sp, tts, PushPop::Push) +} + +pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) + -> Box { + feature_gate::check_for_pushpop_syntax( + cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); + expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop) +} + +fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree], + pp: PushPop) -> Box { + let mut exprs = match get_exprs_from_tts(cx, sp, tts) { + Some(exprs) => exprs.into_iter(), + None => return DummyResult::expr(sp), + }; + let expr = match (exprs.next(), exprs.next()) { + (Some(expr), None) => expr, + _ => { + let msg = match pp { + PushPop::Push => "push_unsafe! takes 1 arguments", + PushPop::Pop => "pop_unsafe! takes 1 arguments", + }; + cx.span_err(sp, msg); + return DummyResult::expr(sp); + } + }; + + let source = ast::UnsafeSource::CompilerGenerated; + let check_mode = match pp { + PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source), + PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source), + }; + + MacEager::expr(cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(expr), + id: ast::DUMMY_NODE_ID, + rules: check_mode, + span: sp + }))) +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ab8cf9ae6b6..69d120cff60 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -80,6 +80,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("visible_private_types", "1.0.0", Active), ("slicing_syntax", "1.0.0", Accepted), ("box_syntax", "1.0.0", Active), + ("pushpop_unsafe", "1.2.0", Active), ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), ("allocator", "1.0.0", Active), @@ -325,6 +326,7 @@ pub struct Features { pub allow_trace_macros: bool, pub allow_internal_unstable: bool, pub allow_custom_derive: bool, + pub allow_pushpop_unsafe: bool, pub simd_ffi: bool, pub unmarked_api: bool, pub negate_unsigned: bool, @@ -348,6 +350,7 @@ impl Features { allow_trace_macros: false, allow_internal_unstable: false, allow_custom_derive: false, + allow_pushpop_unsafe: false, simd_ffi: false, unmarked_api: false, negate_unsigned: false, @@ -358,6 +361,13 @@ impl Features { } } +pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f { + return; + } + emit_feature_err(diag, "pushpop_unsafe", span, EXPLAIN_PUSHPOP_UNSAFE); +} + struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, @@ -787,6 +797,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, allow_trace_macros: cx.has_feature("trace_macros"), allow_internal_unstable: cx.has_feature("allow_internal_unstable"), allow_custom_derive: cx.has_feature("custom_derive"), + allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), negate_unsigned: cx.has_feature("negate_unsigned"), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d93af5da13c..5424c0b214a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -120,6 +120,7 @@ pub mod ext { pub mod log_syntax; pub mod mtwt; pub mod quote; + pub mod pushpop_safe; pub mod source_util; pub mod trace_macros; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6693eed6ace..448857389da 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1434,8 +1434,8 @@ impl<'a> State<'a> { attrs: &[ast::Attribute], close_box: bool) -> io::Result<()> { match blk.rules { - ast::UnsafeBlock(..) => try!(self.word_space("unsafe")), - ast::DefaultBlock => () + ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")), + ast::DefaultBlock | ast::PopUnsafeBlock(..) => () } try!(self.maybe_print_comment(blk.span.lo)); try!(self.ann.pre(self, NodeBlock(blk))); diff --git a/src/test/compile-fail/feature-gate-pushpop-unsafe.rs b/src/test/compile-fail/feature-gate-pushpop-unsafe.rs new file mode 100644 index 00000000000..e317b4c7d4d --- /dev/null +++ b/src/test/compile-fail/feature-gate-pushpop-unsafe.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental + let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental +} diff --git a/src/test/compile-fail/pushpop-unsafe-rejects.rs b/src/test/compile-fail/pushpop-unsafe-rejects.rs new file mode 100644 index 00000000000..b009a670da1 --- /dev/null +++ b/src/test/compile-fail/pushpop-unsafe-rejects.rs @@ -0,0 +1,71 @@ +// Copyright 2012 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. + +// Basic sanity check for `push_unsafe!(EXPR)` and +// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a +// positive number of pushes in the stack, or if we are within a +// normal `unsafe` block, but otherwise cannot. + +static mut X: i32 = 0; + +unsafe fn f() { X += 1; return; } +fn g() { unsafe { X += 1_000; } return; } + +fn main() { + push_unsafe!( { + f(); pop_unsafe!({ + f() //~ ERROR: call to unsafe function + }) + } ); + + push_unsafe!({ + f(); + pop_unsafe!({ + g(); + f(); //~ ERROR: call to unsafe function + }) + } ); + + push_unsafe!({ + g(); pop_unsafe!({ + unsafe { + f(); + } + f(); //~ ERROR: call to unsafe function + }) + }); + + + // Note: For implementation simplicity I have chosen to just have + // the stack do "saturated pop", but perhaps we would prefer to + // have cases like these two here be errors: + + pop_unsafe!{ g() }; + + push_unsafe!({ + pop_unsafe!(pop_unsafe!{ g() }) + }); + + + // Okay, back to examples that do error, even in the presence of + // "saturated pop" + + push_unsafe!({ + g(); + pop_unsafe!(pop_unsafe!({ + f() //~ ERROR: call to unsafe function + })) + }); + + pop_unsafe!({ + f(); //~ ERROR: call to unsafe function + }) + +} diff --git a/src/test/run-pass/pushpop-unsafe-okay.rs b/src/test/run-pass/pushpop-unsafe-okay.rs new file mode 100644 index 00000000000..fc402d41368 --- /dev/null +++ b/src/test/run-pass/pushpop-unsafe-okay.rs @@ -0,0 +1,56 @@ +// 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. + +// Basic sanity check for `push_unsafe!(EXPR)` and +// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a +// positive number of pushes in the stack, or if we are within a +// normal `unsafe` block, but otherwise cannot. + +// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros +// are not integrated with the pretty-printer. + +#![feature(pushpop_unsafe)] + +static mut X: i32 = 0; + +unsafe fn f() { X += 1; return; } +fn g() { unsafe { X += 1_000; } return; } + +fn check_reset_x(x: i32) -> bool { + #![allow(unused_parens)] // dont you judge my style choices! + unsafe { + let ret = (x == X); + X = 0; + ret + } +} + +fn main() { + // double-check test infrastructure + assert!(check_reset_x(0)); + unsafe { f(); } + assert!(check_reset_x(1)); + assert!(check_reset_x(0)); + { g(); } + assert!(check_reset_x(1000)); + assert!(check_reset_x(0)); + unsafe { f(); g(); g(); } + assert!(check_reset_x(2001)); + + push_unsafe!( { f(); pop_unsafe!( g() ) } ); + assert!(check_reset_x(1_001)); + push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } ); + assert!(check_reset_x(1_002)); + + unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); } + assert!(check_reset_x(3)); + push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } ); + assert!(check_reset_x(4)); +} -- cgit 1.4.1-3-g733a5 From 866250c6d4ca63fb56b7d58e55f8949337663998 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 27 Jan 2015 01:22:12 +0100 Subject: prototype Placer protocol for unstable overloaded-box and placement-in. --- src/liballoc/boxed.rs | 107 ++++++++++++++++++++++++++++-- src/libcore/ops.rs | 112 +++++++++++++++++++++++++++++++ src/librustc/middle/expr_use_visitor.rs | 5 ++ src/libsyntax/ext/expand.rs | 114 ++++++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 5 deletions(-) (limited to 'src/libsyntax') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d9653cecc73..4b571a43627 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,13 +55,16 @@ use core::prelude::*; +use heap; + use core::any::Any; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; -use core::marker::Unsize; +use core::marker::{self, Unsize}; use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; +use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; use core::ptr::Unique; use core::raw::{TraitObject}; @@ -83,7 +86,12 @@ use core::raw::{TraitObject}; #[lang = "exchange_heap"] #[unstable(feature = "box_heap", reason = "may be renamed; uncertain about custom allocator design")] -pub const HEAP: () = (); +pub const HEAP: ExchangeHeapSingleton = + ExchangeHeapSingleton { _force_singleton: () }; + +/// This the singleton type used solely for `boxed::HEAP`. +#[derive(Copy, Clone)] +pub struct ExchangeHeapSingleton { _force_singleton: () } /// A pointer type for heap allocation. /// @@ -91,7 +99,97 @@ pub const HEAP: () = (); #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] #[fundamental] -pub struct Box(Unique); +pub struct Box(Unique); + +/// `IntermediateBox` represents uninitialized backing storage for `Box`. +/// +/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of +/// introducing a separate `IntermediateBox`; but then you hit +/// issues when you e.g. attempt to destructure an instance of `Box`, +/// since it is a lang item and so it gets special handling by the +/// compiler. Easier just to make this parallel type for now. +/// +/// FIXME (pnkfelix): Currently the `box` protocol only supports +/// creating instances of sized types. This IntermediateBox is +/// designed to be forward-compatible with a future protocol that +/// supports creating instances of unsized types; that is why the type +/// parameter has the `?Sized` generalization marker, and is also why +/// this carries an explicit size. However, it probably does not need +/// to carry the explicit alignment; that is just a work-around for +/// the fact that the `align_of` intrinsic currently requires the +/// input type to be Sized (which I do not think is strictly +/// necessary). +#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")] +pub struct IntermediateBox{ + ptr: *mut u8, + size: usize, + align: usize, + marker: marker::PhantomData<*mut T>, +} + +impl Place for IntermediateBox { + fn pointer(&mut self) -> *mut T { + unsafe { ::core::mem::transmute(self.ptr) } + } +} + +unsafe fn finalize(b: IntermediateBox) -> Box { + let p = b.ptr as *mut T; + mem::forget(b); + mem::transmute(p) +} + +fn make_place() -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + let p = if size == 0 { + heap::EMPTY as *mut u8 + } else { + let p = unsafe { + heap::allocate(size, align) + }; + if p.is_null() { + panic!("Box make_place allocation failure."); + } + p + }; + + IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData } +} + +impl BoxPlace for IntermediateBox { + fn make_place() -> IntermediateBox { make_place() } +} + +impl InPlace for IntermediateBox { + type Owner = Box; + unsafe fn finalize(self) -> Box { finalize(self) } +} + +impl Boxed for Box { + type Data = T; + type Place = IntermediateBox; + unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } +} + +impl Placer for ExchangeHeapSingleton { + type Place = IntermediateBox; + + fn make_place(self) -> IntermediateBox { + make_place() + } +} + +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr, self.size, self.align) + } + } + } +} impl Box { /// Allocates memory on the heap and then moves `x` into it. @@ -199,8 +297,7 @@ impl Clone for Box { /// let y = x.clone(); /// ``` #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } - + fn clone(&self) -> Box { box (HEAP) {(**self).clone()} } /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c2a9b8c8308..18e4e282f22 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1266,3 +1266,115 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + +/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `in (PLACE) EXPR`. +/// +/// `in (PLACE) EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `in (PLACE) EXPR`. +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `in (PLACE) EXPR` + /// + /// Note that when `in (PLACE) EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place; /* should be bounded by BoxPlace */ + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 54fc2daff2b..f27a96545dd 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -555,6 +555,11 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { None => {} } self.consume_expr(&**base); + if place.is_some() { + self.tcx().sess.span_bug( + expr.span, + "box with explicit place remains after expansion"); + } } ast::ExprMac(..) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b540e0adeea..3a72a50b5ca 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -33,6 +33,16 @@ use visit; use visit::Visitor; use std_inject; +// Given suffix ["b","c","d"], returns path `::std::b::c::d` when +// `fld.cx.use_std`, and `::core::b::c::d` otherwise. +fn mk_core_path(fld: &mut MacroExpander, + span: Span, + suffix: &[&'static str]) -> ast::Path { + let mut idents = vec![fld.cx.ident_of_std("core")]; + for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); } + fld.cx.path_global(span, idents) +} + pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) { fld.cx.bt_push(ExpnInfo { @@ -47,6 +57,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { } e.and_then(|ast::Expr {id, node, span}| match node { + // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprMac(mac) => { @@ -71,6 +82,109 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }) } + // Desugar ExprBox: `in (PLACE) EXPR` + ast::ExprBox(Some(placer), value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = InPlace::pointer(&mut place); + // let value = EXPR; + // unsafe { + // std::ptr::write(raw_place, value); + // InPlace::finalize(place) + // } + + let value_span = value_expr.span; + let placer_span = placer.span; + + let placer_expr = fld.fold_expr(placer); + let value_expr = fld.fold_expr(value_expr); + + let placer_ident = token::gensym_ident("placer"); + let agent_ident = token::gensym_ident("place"); + let value_ident = token::gensym_ident("value"); + let p_ptr_ident = token::gensym_ident("p_ptr"); + + let placer = fld.cx.expr_ident(span, placer_ident); + let agent = fld.cx.expr_ident(span, agent_ident); + let value = fld.cx.expr_ident(span, value_ident); + let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let ptr_write = ["ptr", "write"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |fld: &mut MacroExpander, p, args| { + let path = mk_core_path(fld, placer_span, p); + let path = fld.cx.expr_path(path); + fld.cx.expr_call(span, path, args) + }; + + let stmt_let = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, false, bind, expr) + }; + let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, true, bind, expr) + }; + + // let placer = ; + let s1 = stmt_let(fld, placer_ident, placer_expr); + + // let mut place = Placer::make_place(placer); + let s2 = { + let call = make_call(fld, &make_place, vec![placer]); + stmt_let_mut(fld, agent_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())]; + let call = make_call(fld, &place_pointer, args); + stmt_let(fld, p_ptr_ident, call) + }; + + // let value = ; + let s4 = fld.cx.stmt_let(value_span, false, value_ident, value_expr); + + // unsafe { ptr::write(p_ptr, value); InPlace::finalize(place) } + let expr = { + let call_ptr_write = StmtSemi(make_call( + fld, &ptr_write, vec![p_ptr, value]), ast::DUMMY_NODE_ID); + let call_ptr_write = codemap::respan(value_span, call_ptr_write); + + let call = make_call(fld, &inplace_finalize, vec![agent]); + Some(fld.cx.expr_block(P(ast::Block { + stmts: vec![P(call_ptr_write)], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: span, + }))) + }; + + let block = fld.cx.block_all(span, vec![s1, s2, s3, s4], expr); + fld.cx.expr_block(block) + } + + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ast::ExprWhile(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); -- cgit 1.4.1-3-g733a5 From d79bbbc4ef20a11680a004b600a90281e4c5e04a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 5 Jun 2015 14:21:32 +0200 Subject: Revise placement-in expansion to use `push/pop_unsafe` and `move_val_init`. --- src/libsyntax/ext/expand.rs | 61 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 24 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 3a72a50b5ca..208446ed046 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -56,7 +56,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }); } - e.and_then(|ast::Expr {id, node, span}| match node { + return e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. @@ -88,12 +88,11 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // // let p = PLACE; // let mut place = Placer::make_place(p); - // let raw_place = InPlace::pointer(&mut place); - // let value = EXPR; - // unsafe { - // std::ptr::write(raw_place, value); + // let raw_place = Place::pointer(&mut place); + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); // InPlace::finalize(place) - // } + // }) let value_span = value_expr.span; let placer_span = placer.span; @@ -103,17 +102,15 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let placer_ident = token::gensym_ident("placer"); let agent_ident = token::gensym_ident("place"); - let value_ident = token::gensym_ident("value"); let p_ptr_ident = token::gensym_ident("p_ptr"); let placer = fld.cx.expr_ident(span, placer_ident); let agent = fld.cx.expr_ident(span, agent_ident); - let value = fld.cx.expr_ident(span, value_ident); let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); let make_place = ["ops", "Placer", "make_place"]; let place_pointer = ["ops", "Place", "pointer"]; - let ptr_write = ["ptr", "write"]; + let move_val_init = ["intrinsics", "move_val_init"]; let inplace_finalize = ["ops", "InPlace", "finalize"]; let make_call = |fld: &mut MacroExpander, p, args| { @@ -145,26 +142,23 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { stmt_let(fld, p_ptr_ident, call) }; - // let value = ; - let s4 = fld.cx.stmt_let(value_span, false, value_ident, value_expr); + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span); - // unsafe { ptr::write(p_ptr, value); InPlace::finalize(place) } + // push_unsafe!({ + // ptr::write(p_ptr, pop_unsafe!()); + // InPlace::finalize(place) + // }) let expr = { - let call_ptr_write = StmtSemi(make_call( - fld, &ptr_write, vec![p_ptr, value]), ast::DUMMY_NODE_ID); - let call_ptr_write = codemap::respan(value_span, call_ptr_write); + let call_move_val_init = StmtSemi(make_call( + fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID); + let call_move_val_init = codemap::respan(value_span, call_move_val_init); let call = make_call(fld, &inplace_finalize, vec![agent]); - Some(fld.cx.expr_block(P(ast::Block { - stmts: vec![P(call_ptr_write)], - expr: Some(call), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: span, - }))) + Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span)) }; - let block = fld.cx.block_all(span, vec![s1, s2, s3, s4], expr); + let block = fld.cx.block_all(span, vec![s1, s2, s3], expr); fld.cx.expr_block(block) } @@ -474,7 +468,26 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { span: span }, fld)) } - }) + }); + + fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec>, + expr: P, span: Span) + -> P { + let rules = ast::PushUnsafeBlock(ast::CompilerGenerated); + cx.expr_block(P(ast::Block { + rules: rules, span: span, id: ast::DUMMY_NODE_ID, + stmts: stmts, expr: Some(expr), + })) + } + + fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P, span: Span) + -> P { + let rules = ast::PopUnsafeBlock(ast::CompilerGenerated); + cx.expr_block(P(ast::Block { + rules: rules, span: span, id: ast::DUMMY_NODE_ID, + stmts: vec![], expr: Some(expr), + })) + } } /// Expand a (not-ident-style) macro invocation. Returns the result -- cgit 1.4.1-3-g733a5 From b325e4f28e0735bb951bdf9f1db1206bd3ee715b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 12 Feb 2015 11:30:16 +0100 Subject: Add feature-gates for desugaring-based `box` and placement-`in`. update test/compile-fail/feature-gate-box-expr.rs to reflect new feature gates. Part of what lands with Issue 22181. --- src/liballoc/lib.rs | 2 + src/libstd/lib.rs | 1 + src/libsyntax/ext/expand.rs | 7 ++++ src/libsyntax/feature_gate.rs | 57 +++++++++++++++++++++++++- src/test/compile-fail/feature-gate-box-expr.rs | 5 ++- 5 files changed, 70 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ead0b4259a9..d72b52615eb 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -82,8 +82,10 @@ #![feature(no_std)] #![feature(nonzero)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(raw)] #![feature(staged_api)] +#![feature(placement_in_syntax)] #![feature(unboxed_closures)] #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 82bc1314ad5..784f5eecf0b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -234,6 +234,7 @@ #![feature(no_std)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(rand)] #![feature(raw)] #![feature(reflect_marker)] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 208446ed046..93e744287ba 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -56,6 +56,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }); } + let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the @@ -94,6 +95,12 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // InPlace::finalize(place) // }) + // Ensure feature-gate is enabled + feature_gate::check_for_placement_in( + fld.cx.ecfg.features, + &fld.cx.parse_sess.span_diagnostic, + expr_span); + let value_span = value_expr.span; let placer_span = placer.span; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 69d120cff60..8c6855036f6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -80,6 +80,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("visible_private_types", "1.0.0", Active), ("slicing_syntax", "1.0.0", Accepted), ("box_syntax", "1.0.0", Active), + ("placement_in_syntax", "1.0.0", Active), ("pushpop_unsafe", "1.2.0", Active), ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), @@ -326,6 +327,8 @@ pub struct Features { pub allow_trace_macros: bool, pub allow_internal_unstable: bool, pub allow_custom_derive: bool, + pub allow_placement_in: bool, + pub allow_box: bool, pub allow_pushpop_unsafe: bool, pub simd_ffi: bool, pub unmarked_api: bool, @@ -350,6 +353,8 @@ impl Features { allow_trace_macros: false, allow_internal_unstable: false, allow_custom_derive: false, + allow_placement_in: false, + allow_box: false, allow_pushpop_unsafe: false, simd_ffi: false, unmarked_api: false, @@ -361,6 +366,29 @@ impl Features { } } +const EXPLAIN_BOX_SYNTAX: &'static str = + "box expression syntax is experimental; you can call `Box::new` instead."; + +const EXPLAIN_PLACEMENT_IN: &'static str = + "placement-in expression syntax is experimental and subject to change."; + +const EXPLAIN_PUSHPOP_UNSAFE: &'static str = + "push/pop_unsafe macros are experimental and subject to change."; + +pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_box: true, .. }) = f { + return; + } + emit_feature_err(diag, "box_syntax", span, EXPLAIN_BOX_SYNTAX); +} + +pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_placement_in: true, .. }) = f { + return; + } + emit_feature_err(diag, "placement_in_syntax", span, EXPLAIN_PLACEMENT_IN); +} + pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f { return; @@ -376,6 +404,11 @@ struct Context<'a> { } impl<'a> Context<'a> { + fn enable_feature(&mut self, feature: &'static str) { + debug!("enabling feature: {}", feature); + self.features.push(feature); + } + fn gate_feature(&self, feature: &str, span: Span, explain: &str) { let has_feature = self.has_feature(feature); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature); @@ -498,6 +531,26 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.context.check_attribute(attr, true); } + + fn visit_expr(&mut self, e: &ast::Expr) { + // Issue 22181: overloaded-`box` and placement-`in` are + // implemented via a desugaring expansion, so their feature + // gates go into MacroVisitor since that works pre-expansion. + // + // Issue 22234: we also check during expansion as well. + // But we keep these checks as a pre-expansion check to catch + // uses in e.g. conditionalized code. + + if let ast::ExprBox(None, _) = e.node { + self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX); + } + + if let ast::ExprBox(Some(_), _) = e.node { + self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN); + } + + visit::walk_expr(self, e); + } } struct PostExpansionVisitor<'a> { @@ -764,7 +817,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, match KNOWN_FEATURES.iter() .find(|& &(n, _, _)| name == n) { Some(&(name, _, Active)) => { - cx.features.push(name); + cx.enable_feature(name); } Some(&(_, _, Removed)) => { span_handler.span_err(mi.span, "feature has been removed"); @@ -797,6 +850,8 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, allow_trace_macros: cx.has_feature("trace_macros"), allow_internal_unstable: cx.has_feature("allow_internal_unstable"), allow_custom_derive: cx.has_feature("custom_derive"), + allow_placement_in: cx.has_feature("placement_in_syntax"), + allow_box: cx.has_feature("box_syntax"), allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), diff --git a/src/test/compile-fail/feature-gate-box-expr.rs b/src/test/compile-fail/feature-gate-box-expr.rs index 8f8b035f4a9..f5c9a63b79b 100644 --- a/src/test/compile-fail/feature-gate-box-expr.rs +++ b/src/test/compile-fail/feature-gate-box-expr.rs @@ -17,6 +17,9 @@ fn main() { let x = box () 'c'; //~ ERROR box expression syntax is experimental println!("x: {}", x); - let x = box (HEAP) 'c'; //~ ERROR box expression syntax is experimental + let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental + println!("x: {}", x); + + let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental println!("x: {}", x); } -- cgit 1.4.1-3-g733a5 From 07afe91fda3df8e3b7bbb14006a64d136627f33c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 5 Jun 2015 18:51:23 +0200 Subject: Allow unstable code to be injected by placement-`in` expansion. (Over time the stability checking has gotten more finicky; in particular one must attach the (whole) span of the original `in PLACE BLOCK` expression to the injected references to unstable paths, as noted in the comments.) call `push_compiler_expansion` during the placement-`in` expansion. --- src/libsyntax/ext/expand.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 93e744287ba..faa1e5b2f51 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -50,12 +50,23 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { callee: NameAndSpan { name: expansion_desc.to_string(), format: CompilerExpansion, + + // This does *not* mean code generated after + // `push_compiler_expansion` is automatically exempt + // from stability lints; must also tag such code with + // an appropriate span from `fld.cx.backtrace()`. allow_internal_unstable: true, + span: None, }, }); } + // Sets the expn_id so that we can use unstable methods. + fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span { + Span { expn_id: fld.cx.backtrace(), ..span } + } + let expr_span = e.span; return e.and_then(|ast::Expr {id, node, span}| match node { @@ -101,6 +112,8 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { &fld.cx.parse_sess.span_diagnostic, expr_span); + push_compiler_expansion(fld, expr_span, "placement-in expansion"); + let value_span = value_expr.span; let placer_span = placer.span; @@ -121,9 +134,14 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { let inplace_finalize = ["ops", "InPlace", "finalize"]; let make_call = |fld: &mut MacroExpander, p, args| { - let path = mk_core_path(fld, placer_span, p); + // We feed in the `expr_span` because codemap's span_allows_unstable + // allows the call_site span to inherit the `allow_internal_unstable` + // setting. + let span_unstable = allow_unstable(fld, expr_span); + let path = mk_core_path(fld, span_unstable, p); let path = fld.cx.expr_path(path); - fld.cx.expr_call(span, path, args) + let expr_span_unstable = allow_unstable(fld, span); + fld.cx.expr_call(expr_span_unstable, path, args) }; let stmt_let = |fld: &mut MacroExpander, bind, expr| { @@ -166,7 +184,9 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }; let block = fld.cx.block_all(span, vec![s1, s2, s3], expr); - fld.cx.expr_block(block) + let result = fld.cx.expr_block(block); + fld.cx.bt_pop(); + result } // Issue #22181: -- cgit 1.4.1-3-g733a5 From 9ca1c618794b3da0603ffedff488cd42a32c4eb6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 5 Jun 2015 18:53:17 +0200 Subject: Instrumentation in effort to understand treatment of `allow_internal_unstable`. It is all `debug!` instrumentation so it should not impose a cost on non-debug builds. --- src/librustc/middle/stability.rs | 14 ++++++++++++-- src/libsyntax/codemap.rs | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 30553d62719..6d3bc7fb68c 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -543,9 +543,19 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) { - if !is_staged_api(tcx, id) { return } - if is_internal(tcx, span) { return } + if !is_staged_api(tcx, id) { + debug!("maybe_do_stability_check: \ + skipping id={:?} since it is not staged_api", id); + return; + } + if is_internal(tcx, span) { + debug!("maybe_do_stability_check: \ + skipping span={:?} since it is internal", span); + return; + } let ref stability = lookup(tcx, id); + debug!("maybe_do_stability_check: \ + inspecting id={:?} span={:?} of stability={:?}", id, span, stability); cb(id, span, stability); } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index e6bc3218897..17e6b2c2e12 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -980,6 +980,10 @@ impl CodeMap { mac_span.lo <= span.lo && span.hi <= mac_span.hi }); + debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", + (span.lo, span.hi), + (info.call_site.lo, info.call_site.hi), + info.callee.span.map(|x| (x.lo, x.hi))); debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", span_comes_from_this_expansion, info.callee.allow_internal_unstable); -- cgit 1.4.1-3-g733a5 From 9f6f35bef4986e02f811a1fb7c3da212241784a8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 21 Jul 2015 18:31:37 +0200 Subject: Added support for parsing `in PLACE { BLOCK_CONTENT }`. --- src/libsyntax/parse/parser.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db1b2489f1d..6c10d6efa50 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2612,18 +2612,43 @@ impl<'a> Parser<'a> { ex = ExprAddrOf(m, e); } token::Ident(_, _) => { - if !self.check_keyword(keywords::Box) { + if !self.check_keyword(keywords::Box) && !self.check_keyword(keywords::In) { return self.parse_dot_or_call_expr(); } let lo = self.span.lo; - let box_hi = self.span.hi; + let keyword_hi = self.span.hi; + let is_in = self.token.is_keyword(keywords::In); try!(self.bump()); - // Check for a place: `box(PLACE) EXPR`. + if is_in { + let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); + let blk = try!(self.parse_block()); + hi = blk.span.hi; + let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); + ex = ExprBox(Some(place), blk_expr); + return Ok(self.mk_expr(lo, hi, ex)); + } + + // FIXME (#22181) Remove `box (PLACE) EXPR` support + // entirely after next release (enabling `(box (EXPR))`), + // since it will be replaced by `in PLACE { EXPR }`, ... + // + // ... but for now: check for a place: `box(PLACE) EXPR`. + if try!(self.eat(&token::OpenDelim(token::Paren)) ){ - // Support `box() EXPR` as the default. + // SNAP ba0e1cd + // Enable this warning after snapshot ... + // + // let box_span = mk_sp(lo, self.last_span.hi); + // self.span_warn( + // box_span, + // "deprecated syntax; use the `in` keyword now \ + // (e.g. change `box () ` to \ + // `in { }`)"); + + // Continue supporting `box () EXPR` (temporarily) if !try!(self.eat(&token::CloseDelim(token::Paren)) ){ let place = try!(self.parse_expr_nopanic()); try!(self.expect(&token::CloseDelim(token::Paren))); @@ -2634,10 +2659,9 @@ impl<'a> Parser<'a> { self.span_err(span, &format!("expected expression, found `{}`", this_token_to_string)); - let box_span = mk_sp(lo, box_hi); - self.span_suggestion(box_span, - "try using `box()` instead:", - "box()".to_string()); + let box_span = mk_sp(lo, keyword_hi); + let new_expr = format!("box () {}", pprust::expr_to_string(&place)); + self.span_suggestion(box_span, "try using `box ()` instead:", new_expr); self.abort_if_errors(); } let subexpression = try!(self.parse_prefix_expr()); @@ -2650,6 +2674,7 @@ impl<'a> Parser<'a> { // Otherwise, we use the unique pointer default. let subexpression = try!(self.parse_prefix_expr()); hi = subexpression.span.hi; + // FIXME (pnkfelix): After working out kinks with box // desugaring, should be `ExprBox(None, subexpression)` // instead. -- cgit 1.4.1-3-g733a5 From abad7d6bba9d3fa9d5f1126c8ef6f1b413db1152 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 22 Jul 2015 23:23:36 +0200 Subject: placate `make tidy`. --- src/libcore/intrinsics.rs | 2 +- src/libsyntax/parse/parser.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a1d7867431b..1d466895f2c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -190,7 +190,7 @@ extern "rust-intrinsic" { /// Drop glue is not run on the destination. pub fn move_val_init(dst: *mut T, src: T); - // SNAP ba0e1cd + // SNAP d4432b3 #[cfg(stage0)] /// Moves a value to an uninitialized memory location. /// diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c10d6efa50..c229ac31fc0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2638,7 +2638,7 @@ impl<'a> Parser<'a> { // ... but for now: check for a place: `box(PLACE) EXPR`. if try!(self.eat(&token::OpenDelim(token::Paren)) ){ - // SNAP ba0e1cd + // SNAP d4432b3 // Enable this warning after snapshot ... // // let box_span = mk_sp(lo, self.last_span.hi); @@ -2659,9 +2659,15 @@ impl<'a> Parser<'a> { self.span_err(span, &format!("expected expression, found `{}`", this_token_to_string)); + + // Spanning just keyword avoids constructing + // printout of arg expression (which starts + // with parenthesis, as established above). + let box_span = mk_sp(lo, keyword_hi); - let new_expr = format!("box () {}", pprust::expr_to_string(&place)); - self.span_suggestion(box_span, "try using `box ()` instead:", new_expr); + self.span_suggestion(box_span, + "try using `box ()` instead:", + format!("box ()")); self.abort_if_errors(); } let subexpression = try!(self.parse_prefix_expr()); -- cgit 1.4.1-3-g733a5 From 2d68d09b4679018d0ba3faf41d239251991bf17b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 23 Jul 2015 16:22:05 +0200 Subject: review feedback: common-subexpression-elim across functions in pushpop_safe impl. --- src/libsyntax/ext/pushpop_safe.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/pushpop_safe.rs b/src/libsyntax/ext/pushpop_safe.rs index fee445cd31a..a67d550d3cd 100644 --- a/src/libsyntax/ext/pushpop_safe.rs +++ b/src/libsyntax/ext/pushpop_safe.rs @@ -48,24 +48,24 @@ enum PushPop { Push, Pop } pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - feature_gate::check_for_pushpop_syntax( - cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); expand_pushpop_unsafe(cx, sp, tts, PushPop::Push) } pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - feature_gate::check_for_pushpop_syntax( - cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop) } fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree], pp: PushPop) -> Box { + feature_gate::check_for_pushpop_syntax( + cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp); + let mut exprs = match get_exprs_from_tts(cx, sp, tts) { Some(exprs) => exprs.into_iter(), None => return DummyResult::expr(sp), }; + let expr = match (exprs.next(), exprs.next()) { (Some(expr), None) => expr, _ => { -- cgit 1.4.1-3-g733a5 From 4f58db485d82a8d4d4f03f9584ba6de347f704a5 Mon Sep 17 00:00:00 2001 From: Andy Caldwell Date: Fri, 24 Jul 2015 01:10:25 +0000 Subject: Make ICE an error and use a sensible error message --- src/libsyntax/ext/tt/macro_rules.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 634572d4694..e29e0ab54d1 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -302,8 +302,8 @@ fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &NamedMatch, sp: Span) { tt @ &TtSequence(..) => { check_matcher(cx, Some(tt).into_iter(), &Eof); }, - _ => cx.span_bug(sp, "wrong-structured lhs for follow check (didn't find \ - a TtDelimited or TtSequence)") + _ => cx.span_err(sp, "Invalid macro matcher; matchers must be contained \ + in balanced delimiters or a repetition indicator") }, _ => cx.span_bug(sp, "wrong-structured lhs for follow check (didn't find a \ MatchedNonterminal)") -- cgit 1.4.1-3-g733a5 From 742e1242d9b568edfef51d968f4f81787534e475 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 2 Jul 2015 14:07:42 -0700 Subject: Add static_recursion feature gate. --- src/librustc/middle/check_static_recursion.rs | 30 ++++++++++++++++++++++---- src/libsyntax/feature_gate.rs | 6 ++++++ src/test/compile-fail/static-recursion-gate.rs | 16 ++++++++++++++ src/test/run-pass/static-recursive.rs | 2 ++ 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/static-recursion-gate.rs (limited to 'src/libsyntax') diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 822106c5269..55a9a919300 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -8,16 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This compiler pass detects static items that refer to themselves +// This compiler pass detects constants that refer to themselves // recursively. use ast_map; use session::Session; -use middle::def::{DefConst, DefAssociatedConst, DefVariant, DefMap}; +use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap}; use util::nodemap::NodeMap; use syntax::{ast, ast_util}; use syntax::codemap::Span; +use syntax::feature_gate::emit_feature_err; use syntax::visit::Visitor; use syntax::visit; @@ -37,6 +38,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> { impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { fn visit_item(&mut self, it: &'ast ast::Item) { match it.node { + ast::ItemStatic(..) | ast::ItemConst(..) => { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &it.span); @@ -124,8 +126,27 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { } fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F) where F: Fn(&mut Self) { - if self.idstack.iter().any(|x| *x == id) { - span_err!(self.sess, *self.root_span, E0265, "recursive constant"); + if self.idstack.iter().any(|&x| x == id) { + let any_static = self.idstack.iter().any(|&x| { + if let ast_map::NodeItem(item) = self.ast_map.get(x) { + if let ast::ItemStatic(..) = item.node { + true + } else { + false + } + } else { + false + } + }); + if any_static { + if !self.sess.features.borrow().static_recursion { + emit_feature_err(&self.sess.parse_sess.span_diagnostic, + "static_recursion", + *self.root_span, "recursive static"); + } + } else { + span_err!(self.sess, *self.root_span, E0265, "recursive constant"); + } return; } self.idstack.push(id); @@ -216,6 +237,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { match e.node { ast::ExprPath(..) => { match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { + Some(DefStatic(def_id, _)) | Some(DefAssociatedConst(def_id, _)) | Some(DefConst(def_id)) if ast_util::is_local(def_id) => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8c6855036f6..ee895fb1a96 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -160,6 +160,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows using #[prelude_import] on glob `use` items. ("prelude_import", "1.2.0", Active), + + // Allows the definition recursive static items. + ("static_recursion", "1.3.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -338,6 +341,7 @@ pub struct Features { /// #![feature] attrs for non-language (library) features pub declared_lib_features: Vec<(InternedString, Span)>, pub const_fn: bool, + pub static_recursion: bool } impl Features { @@ -362,6 +366,7 @@ impl Features { declared_stable_lang_features: Vec::new(), declared_lib_features: Vec::new(), const_fn: false, + static_recursion: false } } } @@ -859,6 +864,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, declared_stable_lang_features: accepted_features, declared_lib_features: unknown_features, const_fn: cx.has_feature("const_fn"), + static_recursion: cx.has_feature("static_recursion") } } diff --git a/src/test/compile-fail/static-recursion-gate.rs b/src/test/compile-fail/static-recursion-gate.rs new file mode 100644 index 00000000000..29b5689fa93 --- /dev/null +++ b/src/test/compile-fail/static-recursion-gate.rs @@ -0,0 +1,16 @@ +// 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. + +static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; +//~^ ERROR recursive static + +pub fn main() { + unsafe { assert_eq!(S, *(S as *const *const u8)); } +} diff --git a/src/test/run-pass/static-recursive.rs b/src/test/run-pass/static-recursive.rs index edb0678cd78..171aef522d4 100644 --- a/src/test/run-pass/static-recursive.rs +++ b/src/test/run-pass/static-recursive.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(static_recursion)] + static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; pub fn main() { -- cgit 1.4.1-3-g733a5 From 55621b6199dcef7090bdbb660a5ab9354b3effa6 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Fri, 24 Jul 2015 13:39:11 -0700 Subject: Add feature gate --- src/doc/reference.md | 2 ++ src/librustc_typeck/check/mod.rs | 40 +++++++++++++++++++++- src/libsyntax/feature_gate.rs | 9 +++-- src/test/compile-fail/default_ty_param_conflict.rs | 2 ++ .../default_ty_param_conflict_cross_crate.rs | 3 ++ ...t_ty_param_default_dependent_associated_type.rs | 3 ++ .../default_ty_param_dependent_defaults.rs | 1 + .../run-pass/default_ty_param_method_call_test.rs | 2 ++ src/test/run-pass/default_ty_param_struct.rs | 2 ++ .../default_ty_param_struct_and_type_alias.rs | 2 ++ src/test/run-pass/default_ty_param_trait_impl.rs | 8 +++-- .../run-pass/default_ty_param_trait_impl_simple.rs | 8 ++--- src/test/run-pass/default_ty_param_type_alias.rs | 2 ++ 13 files changed, 74 insertions(+), 10 deletions(-) (limited to 'src/libsyntax') diff --git a/src/doc/reference.md b/src/doc/reference.md index 26fd2fd8d20..59721edda70 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2368,6 +2368,8 @@ The currently implemented features of the reference compiler are: internally without imposing on callers (i.e. making them behave like function calls in terms of encapsulation). +* - `default_type_parameter_fallback` - Allows type parameter defaults to + influence type inference. If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 95e916f1a0d..eb0ef30d396 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1709,10 +1709,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Apply "fallbacks" to some types + /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. + pub fn default_type_parameters(&self) { + use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; + for ty in &self.infcx().unsolved_variables() { + let resolved = self.infcx().resolve_type_vars_if_possible(ty); + if self.infcx().type_var_diverges(resolved) { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + } else { + match self.infcx().type_is_unconstrained_numeric(resolved) { + UnconstrainedInt => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + }, + UnconstrainedFloat => { + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + } + Neither => { } + } + } + } + } + fn select_all_obligations_and_apply_defaults(&self) { + if self.tcx().sess.features.borrow().default_type_parameter_fallback { + self.new_select_all_obligations_and_apply_defaults(); + } else { + self.old_select_all_obligations_and_apply_defaults(); + } + } + + // Implements old type inference fallback algorithm + fn old_select_all_obligations_and_apply_defaults(&self) { + self.select_obligations_where_possible(); + self.default_type_parameters(); + self.select_obligations_where_possible(); + } + + fn new_select_all_obligations_and_apply_defaults(&self) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - // For the time being this errs on the side of being memory wasteful but provides better + // For the time being this errs on the side of being memory wasteful but provides better // error reporting. // let type_variables = self.infcx().type_variables.clone(); @@ -1934,6 +1971,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); match fulfillment_cx.select_all_or_error(self.infcx()) { Ok(()) => { } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ee895fb1a96..af7e4a6855f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -163,6 +163,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows the definition recursive static items. ("static_recursion", "1.3.0", Active), +// Allows default type parameters to influence type inference. + ("default_type_parameter_fallback", "1.3.0", Active) ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -341,7 +343,8 @@ pub struct Features { /// #![feature] attrs for non-language (library) features pub declared_lib_features: Vec<(InternedString, Span)>, pub const_fn: bool, - pub static_recursion: bool + pub static_recursion: bool, + pub default_type_parameter_fallback: bool, } impl Features { @@ -366,7 +369,8 @@ impl Features { declared_stable_lang_features: Vec::new(), declared_lib_features: Vec::new(), const_fn: false, - static_recursion: false + static_recursion: false, + default_type_parameter_fallback: false, } } } @@ -865,6 +869,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, declared_lib_features: unknown_features, const_fn: cx.has_feature("const_fn"), static_recursion: cx.has_feature("static_recursion") + default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), } } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 42de545f9d0..48c5cd1ff77 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + use std::fmt::Debug; // Example from the RFC diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index 804a864e074..4d60724372a 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -9,6 +9,9 @@ // except according to those terms. // //aux-build:default_ty_param_cross_crate_crate.rs + +#![feature(default_type_parameter_fallback)] + extern crate default_param_test; use default_param_test::{Foo, bleh}; diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs index fe8c1063c96..8fc2c2e6bce 100644 --- a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs +++ b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // + +#![feature(default_type_parameter_fallback)] + use std::marker::PhantomData; trait Id { diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs index eba86415af4..ac833d0f547 100644 --- a/src/test/run-pass/default_ty_param_dependent_defaults.rs +++ b/src/test/run-pass/default_ty_param_dependent_defaults.rs @@ -9,6 +9,7 @@ // except according to those terms. // +#![feature(default_type_parameter_fallback)] use std::marker::PhantomData; struct Foo { t: T, data: PhantomData } diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs index 35f0fcab001..e8d93092ec5 100644 --- a/src/test/run-pass/default_ty_param_method_call_test.rs +++ b/src/test/run-pass/default_ty_param_method_call_test.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + struct Foo; impl Foo { diff --git a/src/test/run-pass/default_ty_param_struct.rs b/src/test/run-pass/default_ty_param_struct.rs index b94b759fd11..d9ac51fc23b 100644 --- a/src/test/run-pass/default_ty_param_struct.rs +++ b/src/test/run-pass/default_ty_param_struct.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + struct Foo(A); impl Foo { diff --git a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs index 0a8543c03b1..6e3e60a02e5 100644 --- a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs +++ b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs @@ -9,6 +9,8 @@ // except according to those terms. // +#![feature(default_type_parameter_fallback)] + use std::marker::PhantomData; struct DeterministicHasher; diff --git a/src/test/run-pass/default_ty_param_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs index fbceb60b9a8..c67d3a49aff 100644 --- a/src/test/run-pass/default_ty_param_trait_impl.rs +++ b/src/test/run-pass/default_ty_param_trait_impl.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + // Another example from the RFC trait Foo { } trait Bar { } -impl Foo for Vec {} // Impl 1 -impl Bar for usize { } // Impl 2 +impl Foo for Vec {} +impl Bar for usize {} -fn takes_foo(f: F) { } +fn takes_foo(f: F) {} fn main() { let x = Vec::new(); // x: Vec<$0> diff --git a/src/test/run-pass/default_ty_param_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs index 00d7ccf43be..067ad524922 100644 --- a/src/test/run-pass/default_ty_param_trait_impl_simple.rs +++ b/src/test/run-pass/default_ty_param_trait_impl_simple.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + // An example from the RFC trait Foo { fn takes_foo(&self); } trait Bar { } impl Foo for Vec { fn takes_foo(&self) {} -} // Impl 1 - -impl Bar for usize { } // Impl 2 +} -// fn takes_foo(f: F) { } +impl Bar for usize {} fn main() { let x = Vec::new(); // x: Vec<$0> diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/default_ty_param_type_alias.rs index c3e44e55bee..1b4747406d0 100644 --- a/src/test/run-pass/default_ty_param_type_alias.rs +++ b/src/test/run-pass/default_ty_param_type_alias.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(default_type_parameter_fallback)] + use std::collections::HashMap; type IntMap = HashMap; -- cgit 1.4.1-3-g733a5 From 5ad36cb887dadc7fe564cfed1ccac52d009a59c8 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sat, 25 Jul 2015 21:22:38 -0700 Subject: Add omitted trailing comma --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index af7e4a6855f..c3338f02ee4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -868,7 +868,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, declared_stable_lang_features: accepted_features, declared_lib_features: unknown_features, const_fn: cx.has_feature("const_fn"), - static_recursion: cx.has_feature("static_recursion") + static_recursion: cx.has_feature("static_recursion"), default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"), } } -- cgit 1.4.1-3-g733a5 From adfdbc4bd75f2581e9ad0151b26fb786b64475f8 Mon Sep 17 00:00:00 2001 From: mitaa Date: Sat, 25 Jul 2015 22:43:35 +0200 Subject: Remove `ast::LocalSource` with only one used variant `LocalSource` indicated wether a let binding originated from for-loop desugaring to enable specialized error messages, but for-loop expansion has changed and this is now achieved through `MatchSource::ForLoopDesugar`. --- src/librustc/middle/check_match.rs | 8 +------- src/libsyntax/ast.rs | 10 ---------- src/libsyntax/ext/build.rs | 2 -- src/libsyntax/ext/expand.rs | 3 +-- src/libsyntax/fold.rs | 3 +-- src/libsyntax/parse/parser.rs | 3 +-- 6 files changed, 4 insertions(+), 25 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index ea86fa318b4..d1467b67310 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -1016,16 +1016,10 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], fn check_local(cx: &mut MatchCheckCtxt, loc: &ast::Local) { visit::walk_local(cx, loc); - let name = match loc.source { - ast::LocalLet => "local", - ast::LocalFor => "`for` loop" - }; - let mut static_inliner = StaticInliner::new(cx.tcx, None); is_refutable(cx, &*static_inliner.fold_pat(loc.pat.clone()), |pat| { span_err!(cx.tcx.sess, loc.pat.span, E0005, - "refutable pattern in {} binding: `{}` not covered", - name, pat_to_string(pat) + "refutable pattern in local binding: `{}` not covered", pat_to_string(pat) ); }); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fba9db401db..72711f2ed18 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -29,7 +29,6 @@ pub use self::Item_::*; pub use self::KleeneOp::*; pub use self::Lit_::*; pub use self::LitIntType::*; -pub use self::LocalSource::*; pub use self::Mac_::*; pub use self::MacStmtStyle::*; pub use self::MetaItem_::*; @@ -756,14 +755,6 @@ pub enum MacStmtStyle { MacStmtWithoutBraces, } -/// Where a local declaration came from: either a true `let ... = -/// ...;`, or one desugared from the pattern of a for loop. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum LocalSource { - LocalLet, - LocalFor, -} - // FIXME (pending discussion of #1697, #2178...): local should really be // a refinement on pat. /// Local represents a `let` statement, e.g., `let : = ;` @@ -775,7 +766,6 @@ pub struct Local { pub init: Option>, pub id: NodeId, pub span: Span, - pub source: LocalSource, } pub type Decl = Spanned; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 8a80e291a53..79210cb3260 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -538,7 +538,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - source: ast::LocalLet, }); let decl = respan(sp, ast::DeclLocal(local)); P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))) @@ -562,7 +561,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - source: ast::LocalLet, }); let decl = respan(sp, ast::DeclLocal(local)); P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index faa1e5b2f51..286dc91299f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -911,7 +911,7 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE StmtDecl(decl, node_id) => decl.and_then(|Spanned {node: decl, span}| match decl { DeclLocal(local) => { // take it apart: - let rewritten_local = local.map(|Local {id, pat, ty, init, source, span}| { + let rewritten_local = local.map(|Local {id, pat, ty, init, span}| { // expand the ty since TyFixedLengthVec contains an Expr // and thus may have a macro use let expanded_ty = ty.map(|t| fld.fold_ty(t)); @@ -941,7 +941,6 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE pat: rewritten_pat, // also, don't forget to expand the init: init: init.map(|e| fld.fold_expr(e)), - source: source, span: span } }); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 14742d2e74c..dab6d41df30 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -515,12 +515,11 @@ pub fn noop_fold_parenthesized_parameter_data(data: ParenthesizedPara } pub fn noop_fold_local(l: P, fld: &mut T) -> P { - l.map(|Local {id, pat, ty, init, source, span}| Local { + l.map(|Local {id, pat, ty, init, span}| Local { id: fld.new_id(id), ty: ty.map(|t| fld.fold_ty(t)), pat: fld.fold_pat(pat), init: init.map(|e| fld.fold_expr(e)), - source: source, span: fld.new_span(span) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2a2259a80a..04665140e2f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -35,7 +35,7 @@ use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, ItemDefaultImpl}; use ast::{ItemExternCrate, ItemUse}; use ast::{LifetimeDef, Lit, Lit_}; use ast::{LitBool, LitChar, LitByte, LitBinary}; -use ast::{LitStr, LitInt, Local, LocalLet}; +use ast::{LitStr, LitInt, Local}; use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; @@ -3432,7 +3432,6 @@ impl<'a> Parser<'a> { init: init, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, self.last_span.hi), - source: LocalLet, })) } -- cgit 1.4.1-3-g733a5