diff --git a/src/Cargo.lock b/src/Cargo.lock index 7620fe8ddb3c3..fb15df7ffccc9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1912,9 +1912,11 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", + "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d250cfe1880fc..cb43d5bee78ca 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -124,6 +124,7 @@ #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(exact_chunks)] +#![feature(pointer_methods)] #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a00e3d17dd00f..64e815b1fbaa5 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -43,6 +43,7 @@ use core::str as core_str; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; +use core::ptr; use core::iter::FusedIterator; use std_unicode::str::{UnicodeStr, Utf16Encoder}; @@ -2066,9 +2067,59 @@ impl str { /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { - let mut s = String::with_capacity(self.len() * n); - s.extend((0..n).map(|_| self)); - s + if n == 0 { + return String::new(); + } + + // If `n` is larger than zero, it can be split as + // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. + // `2^expn` is the number represented by the leftmost '1' bit of `n`, + // and `rem` is the remaining part of `n`. + + // Using `Vec` to access `set_len()`. + let mut buf = Vec::with_capacity(self.len() * n); + + // `2^expn` repetition is done by doubling `buf` `expn`-times. + buf.extend(self.as_bytes()); + { + let mut m = n >> 1; + // If `m > 0`, there are remaining bits up to the leftmost '1'. + while m > 0 { + // `buf.extend(buf)`: + unsafe { + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut u8).add(buf.len()), + buf.len(), + ); + // `buf` has capacity of `self.len() * n`. + let buf_len = buf.len(); + buf.set_len(buf_len * 2); + } + + m >>= 1; + } + } + + // `rem` (`= n - 2^expn`) repetition is done by copying + // first `rem` repetitions from `buf` itself. + let rem_len = self.len() * n - buf.len(); // `self.len() * rem` + if rem_len > 0 { + // `buf.extend(buf[0 .. rem_len])`: + unsafe { + // This is non-overlapping since `2^expn > rem`. + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut u8).add(buf.len()), + rem_len, + ); + // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). + let buf_cap = buf.capacity(); + buf.set_len(buf_cap); + } + } + + unsafe { String::from_utf8_unchecked(buf) } } /// Checks if all characters in this string are within the ASCII range. diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index c3cd65230bd86..5069c59562678 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1203,7 +1203,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); - if pointee.is_sized(tcx, param_env, DUMMY_SP) { + if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); } @@ -1428,7 +1428,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let param_env = tcx.param_env(def.did); let last_field = def.variants[v].fields.last().unwrap(); let always_sized = tcx.type_of(last_field.did) - .is_sized(tcx, param_env, DUMMY_SP); + .is_sized(tcx.at(DUMMY_SP), param_env); if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } }; diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 47ad7cbcb56f7..3a5e6d97cd4ba 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -20,6 +20,7 @@ use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; use ty::subst::{Subst, UnpackedKind}; +use ty::maps::TyCtxtAt; use ty::TypeVariants::*; use util::common::ErrorReported; use middle::lang_items; @@ -864,11 +865,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } pub fn is_sized(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span)-> bool + tcx_at: TyCtxtAt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>)-> bool { - tcx.at(span).is_sized_raw(param_env.and(self)) + tcx_at.is_sized_raw(param_env.and(self)) } pub fn is_freeze(&'tcx self, diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 3e15af7558da2..e412d1749d1b2 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -13,3 +13,5 @@ serialize = { path = "../libserialize" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } unicode-width = "0.1.4" +atty = "0.2" +termcolor = "0.3" diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 33fce7b1968ad..f481b36daa346 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -17,12 +17,14 @@ use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledStrin use styled_buffer::StyledBuffer; use rustc_data_structures::sync::Lrc; +use atty; use std::borrow::Cow; use std::io::prelude::*; use std::io; -use term; use std::collections::{HashMap, HashSet}; use std::cmp::min; +use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter}; +use termcolor::{WriteColor, Color, Buffer}; use unicode_width; const ANONYMIZED_LINE_NUM: &str = "LL"; @@ -95,11 +97,14 @@ pub enum ColorConfig { } impl ColorConfig { - fn use_color(&self) -> bool { + fn to_color_choice(&self) -> ColorChoice { match *self { - ColorConfig::Always => true, - ColorConfig::Never => false, - ColorConfig::Auto => stderr_isatty(), + ColorConfig::Always => ColorChoice::Always, + ColorConfig::Never => ColorChoice::Never, + ColorConfig::Auto if atty::is(atty::Stream::Stderr) => { + ColorChoice::Auto + } + ColorConfig::Auto => ColorChoice::Never, } } } @@ -123,25 +128,26 @@ impl Drop for EmitterWriter { fn drop(&mut self) { if !self.short_message && !self.error_codes.is_empty() { let mut error_codes = self.error_codes.clone().into_iter().collect::>(); + let mut dst = self.dst.writable(); error_codes.sort(); if error_codes.len() > 1 { let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - writeln!(self.dst, + writeln!(dst, "You've got a few errors: {}{}", error_codes[..limit].join(", "), if error_codes.len() > 9 { "..." } else { "" } ).expect("failed to give tips..."); - writeln!(self.dst, + writeln!(dst, "If you want more information on an error, try using \ \"rustc --explain {}\"", &error_codes[0]).expect("failed to give tips..."); } else { - writeln!(self.dst, + writeln!(dst, "If you want more information on this error, try using \ \"rustc --explain {}\"", &error_codes[0]).expect("failed to give tips..."); } - self.dst.flush().expect("failed to emit errors"); + dst.flush().expect("failed to emit errors"); } } } @@ -152,25 +158,14 @@ impl EmitterWriter { short_message: bool, teach: bool) -> EmitterWriter { - if color_config.use_color() { - let dst = Destination::from_stderr(); - EmitterWriter { - dst, - cm: code_map, - short_message, - teach, - error_codes: HashSet::new(), - ui_testing: false, - } - } else { - EmitterWriter { - dst: Raw(Box::new(io::stderr())), - cm: code_map, - short_message, - teach, - error_codes: HashSet::new(), - ui_testing: false, - } + let dst = Destination::from_stderr(color_config); + EmitterWriter { + dst, + cm: code_map, + short_message, + teach, + error_codes: HashSet::new(), + ui_testing: false, } } @@ -1356,10 +1351,12 @@ impl EmitterWriter { } Err(e) => panic!("failed to emit error: {}", e), } - match write!(&mut self.dst, "\n") { + + let mut dst = self.dst.writable(); + match write!(dst, "\n") { Err(e) => panic!("failed to emit error: {}", e), _ => { - match self.dst.flush() { + match dst.flush() { Err(e) => panic!("failed to emit error: {}", e), _ => (), } @@ -1424,6 +1421,8 @@ fn emit_to_destination(rendered_buffer: &Vec>, -> io::Result<()> { use lock; + let mut dst = dst.writable(); + // In order to prevent error message interleaving, where multiple error lines get intermixed // when multiple compiler processes error simultaneously, we emit errors with additional // steps. @@ -1444,7 +1443,7 @@ fn emit_to_destination(rendered_buffer: &Vec>, if !short_message && part.text.len() == 12 && part.text.starts_with("error[E") { error_codes.insert(part.text[6..11].to_owned()); } - dst.reset_attrs()?; + dst.reset()?; } if !short_message { write!(dst, "\n")?; @@ -1454,180 +1453,136 @@ fn emit_to_destination(rendered_buffer: &Vec>, Ok(()) } -#[cfg(unix)] -fn stderr_isatty() -> bool { - use libc; - unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } -} -#[cfg(windows)] -fn stderr_isatty() -> bool { - type DWORD = u32; - type BOOL = i32; - type HANDLE = *mut u8; - const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; - extern "system" { - fn GetStdHandle(which: DWORD) -> HANDLE; - fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL; - } - unsafe { - let handle = GetStdHandle(STD_ERROR_HANDLE); - let mut out = 0; - GetConsoleMode(handle, &mut out) != 0 - } -} - -pub type BufferedStderr = term::Terminal + Send; - pub enum Destination { - Terminal(Box), - BufferedTerminal(Box), + Terminal(StandardStream), + Buffered(BufferWriter), Raw(Box), } -/// Buffered writer gives us a way on Unix to buffer up an entire error message before we output -/// it. This helps to prevent interleaving of multiple error messages when multiple compiler -/// processes error simultaneously -pub struct BufferedWriter { - buffer: Vec, -} - -impl BufferedWriter { - // note: we use _new because the conditional compilation at its use site may make this - // this function unused on some platforms - fn _new() -> BufferedWriter { - BufferedWriter { buffer: vec![] } - } -} - -impl Write for BufferedWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - for b in buf { - self.buffer.push(*b); - } - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - let mut stderr = io::stderr(); - let result = stderr.write_all(&self.buffer) - .and_then(|_| stderr.flush()); - self.buffer.clear(); - result - } +pub enum WritableDst<'a> { + Terminal(&'a mut StandardStream), + Buffered(&'a mut BufferWriter, Buffer), + Raw(&'a mut Box), } impl Destination { - #[cfg(not(windows))] - /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error - /// to be emitted at one time. - fn from_stderr() -> Destination { - let stderr: Option> = - term::TerminfoTerminal::new(BufferedWriter::_new()) - .map(|t| Box::new(t) as Box); - - match stderr { - Some(t) => BufferedTerminal(t), - None => Raw(Box::new(io::stderr())), + fn from_stderr(color: ColorConfig) -> Destination { + let choice = color.to_color_choice(); + // On Windows we'll be performing global synchronization on the entire + // system for emitting rustc errors, so there's no need to buffer + // anything. + // + // On non-Windows we rely on the atomicity of `write` to ensure errors + // don't get all jumbled up. + if cfg!(windows) { + Terminal(StandardStream::stderr(choice)) + } else { + Buffered(BufferWriter::stderr(choice)) } } - #[cfg(windows)] - /// Return a normal, unbuffered terminal when on Windows. - fn from_stderr() -> Destination { - let stderr: Option> = term::TerminfoTerminal::new(io::stderr()) - .map(|t| Box::new(t) as Box) - .or_else(|| { - term::WinConsole::new(io::stderr()) - .ok() - .map(|t| Box::new(t) as Box) - }); - - match stderr { - Some(t) => Terminal(t), - None => Raw(Box::new(io::stderr())), + fn writable<'a>(&'a mut self) -> WritableDst<'a> { + match *self { + Destination::Terminal(ref mut t) => WritableDst::Terminal(t), + Destination::Buffered(ref mut t) => { + let buf = t.buffer(); + WritableDst::Buffered(t, buf) + } + Destination::Raw(ref mut t) => WritableDst::Raw(t), } } +} +impl<'a> WritableDst<'a> { fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> { + let mut spec = ColorSpec::new(); match style { Style::LineAndColumn => {} Style::LineNumber => { - self.start_attr(term::Attr::Bold)?; + spec.set_bold(true); + spec.set_intense(true); if cfg!(windows) { - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; + spec.set_fg(Some(Color::Cyan)); } else { - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + spec.set_fg(Some(Color::Blue)); } } Style::Quotation => {} Style::OldSchoolNoteText | Style::HeaderMsg => { - self.start_attr(term::Attr::Bold)?; + spec.set_bold(true); if cfg!(windows) { - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))?; + spec.set_intense(true) + .set_fg(Some(Color::White)); } } Style::UnderlinePrimary | Style::LabelPrimary => { - self.start_attr(term::Attr::Bold)?; - self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + spec = lvl.color(); + spec.set_bold(true); } Style::UnderlineSecondary | Style::LabelSecondary => { - self.start_attr(term::Attr::Bold)?; + spec.set_bold(true) + .set_intense(true); if cfg!(windows) { - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; + spec.set_fg(Some(Color::Cyan)); } else { - self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + spec.set_fg(Some(Color::Blue)); } } Style::NoStyle => {} - Style::Level(l) => { - self.start_attr(term::Attr::Bold)?; - self.start_attr(term::Attr::ForegroundColor(l.color()))?; + Style::Level(lvl) => { + spec = lvl.color(); + spec.set_bold(true); + } + Style::Highlight => { + spec.set_bold(true); } - Style::Highlight => self.start_attr(term::Attr::Bold)?, } - Ok(()) + self.set_color(&spec) } - fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { + fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> { match *self { - Terminal(ref mut t) => { - t.attr(attr)?; - } - BufferedTerminal(ref mut t) => { - t.attr(attr)?; - } - Raw(_) => {} + WritableDst::Terminal(ref mut t) => t.set_color(color), + WritableDst::Buffered(_, ref mut t) => t.set_color(color), + WritableDst::Raw(_) => Ok(()) } - Ok(()) } - fn reset_attrs(&mut self) -> io::Result<()> { + fn reset(&mut self) -> io::Result<()> { match *self { - Terminal(ref mut t) => { - t.reset()?; - } - BufferedTerminal(ref mut t) => { - t.reset()?; - } - Raw(_) => {} + WritableDst::Terminal(ref mut t) => t.reset(), + WritableDst::Buffered(_, ref mut t) => t.reset(), + WritableDst::Raw(_) => Ok(()), } - Ok(()) } } -impl Write for Destination { +impl<'a> Write for WritableDst<'a> { fn write(&mut self, bytes: &[u8]) -> io::Result { match *self { - Terminal(ref mut t) => t.write(bytes), - BufferedTerminal(ref mut t) => t.write(bytes), - Raw(ref mut w) => w.write(bytes), + WritableDst::Terminal(ref mut t) => t.write(bytes), + WritableDst::Buffered(_, ref mut buf) => buf.write(bytes), + WritableDst::Raw(ref mut w) => w.write(bytes), } } + fn flush(&mut self) -> io::Result<()> { match *self { - Terminal(ref mut t) => t.flush(), - BufferedTerminal(ref mut t) => t.flush(), - Raw(ref mut w) => w.flush(), + WritableDst::Terminal(ref mut t) => t.flush(), + WritableDst::Buffered(_, ref mut buf) => buf.flush(), + WritableDst::Raw(ref mut w) => w.flush(), + } + } +} + +impl<'a> Drop for WritableDst<'a> { + fn drop(&mut self) { + match *self { + WritableDst::Buffered(ref mut dst, ref mut buf) => { + drop(dst.print(buf)); + } + _ => {} } } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 3eea311a5af5e..924ed71ef0d65 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -21,7 +21,8 @@ #![feature(i128_type)] #![feature(optin_builtin_traits)] -extern crate term; +extern crate atty; +extern crate termcolor; #[cfg(unix)] extern crate libc; extern crate rustc_data_structures; @@ -47,6 +48,8 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::panic; +use termcolor::{ColorSpec, Color}; + mod diagnostic; mod diagnostic_builder; pub mod emitter; @@ -660,20 +663,28 @@ impl fmt::Display for Level { } impl Level { - fn color(self) -> term::color::Color { + fn color(self) -> ColorSpec { + let mut spec = ColorSpec::new(); match self { - Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, + Bug | Fatal | PhaseFatal | Error => { + spec.set_fg(Some(Color::Red)) + .set_intense(true); + } Warning => { - if cfg!(windows) { - term::color::BRIGHT_YELLOW - } else { - term::color::YELLOW - } + spec.set_fg(Some(Color::Yellow)) + .set_intense(cfg!(windows)); + } + Note => { + spec.set_fg(Some(Color::Green)) + .set_intense(true); + } + Help => { + spec.set_fg(Some(Color::Cyan)) + .set_intense(true); } - Note => term::color::BRIGHT_GREEN, - Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), } + return spec } pub fn to_str(self) -> &'static str { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index ef9b3d38c637c..e778b2d386105 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -150,11 +150,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // Detect literal value out of range [min, max] inclusive // avoiding use of -min to prevent overflow/panic - if (negative && v > max + 1) || - (!negative && v > max) { - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t)); + if (negative && v > max + 1) || (!negative && v > max) { + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + ty::TyInt(t), + repr_str, + v, + negative, + ); + return; + } + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for {:?}", t), + ); return; } } @@ -191,9 +203,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } } - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t)); + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + ty::TyUint(t), + repr_str, + lit_val, + false, + ); + return; + } + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for {:?}", t), + ); } } ty::TyFloat(t) => { @@ -338,6 +363,120 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => false, } } + + fn get_bin_hex_repr(cx: &LateContext, lit: &ast::Lit) -> Option { + let src = cx.sess().codemap().span_to_snippet(lit.span).ok()?; + let firstch = src.chars().next()?; + + if firstch == '0' { + match src.chars().nth(1) { + Some('x') | Some('b') => return Some(src), + _ => return None, + } + } + + None + } + + // This function finds the next fitting type and generates a suggestion string. + // It searches for fitting types in the following way (`X < Y`): + // - `iX`: if literal fits in `uX` => `uX`, else => `iY` + // - `-iX` => `iY` + // - `uX` => `uY` + // + // No suggestion for: `isize`, `usize`. + fn get_type_suggestion<'a>( + t: &ty::TypeVariants, + val: u128, + negative: bool, + ) -> Option { + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + macro_rules! find_fit { + ($ty:expr, $val:expr, $negative:expr, + $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { + { + let _neg = if negative { 1 } else { 0 }; + match $ty { + $($type => { + $(if !negative && val <= uint_ty_range($utypes).1 { + return Some(format!("{:?}", $utypes)) + })* + $(if val <= int_ty_range($itypes).1 as u128 + _neg { + return Some(format!("{:?}", $itypes)) + })* + None + },)* + _ => None + } + } + } + } + match t { + &ty::TyInt(i) => find_fit!(i, val, negative, + I8 => [U8] => [I16, I32, I64, I128], + I16 => [U16] => [I32, I64, I128], + I32 => [U32] => [I64, I128], + I64 => [U64] => [I128], + I128 => [U128] => []), + &ty::TyUint(u) => find_fit!(u, val, negative, + U8 => [U8, U16, U32, U64, U128] => [], + U16 => [U16, U32, U64, U128] => [], + U32 => [U32, U64, U128] => [], + U64 => [U64, U128] => [], + U128 => [U128] => []), + _ => None, + } + } + + fn report_bin_hex_error( + cx: &LateContext, + expr: &hir::Expr, + ty: ty::TypeVariants, + repr_str: String, + val: u128, + negative: bool, + ) { + let (t, actually) = match ty { + ty::TyInt(t) => { + let bits = int_ty_bits(t, cx.sess().target.isize_ty); + let actually = (val << (128 - bits)) as i128 >> (128 - bits); + (format!("{:?}", t), actually.to_string()) + } + ty::TyUint(t) => { + let bits = uint_ty_bits(t, cx.sess().target.usize_ty); + let actually = (val << (128 - bits)) >> (128 - bits); + (format!("{:?}", t), actually.to_string()) + } + _ => bug!(), + }; + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + expr.span, + &format!("literal out of range for {}", t), + ); + err.note(&format!( + "the literal `{}` (decimal `{}`) does not fit into \ + an `{}` and will become `{}{}`", + repr_str, val, t, actually, t + )); + if let Some(sugg_ty) = + get_type_suggestion(&cx.tables.node_id_to_type(expr.hir_id).sty, val, negative) + { + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + let (sans_suffix, _) = repr_str.split_at(pos); + err.span_suggestion( + expr.span, + &format!("consider using `{}` instead", sugg_ty), + format!("{}{}", sans_suffix, sugg_ty), + ); + } else { + err.help(&format!("consider using `{}` instead", sugg_ty)); + } + } + + err.emit(); + } } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a06d39d225c45..1feecba60088b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1208,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // shouldn't affect `is_sized`. let gcx = self.tcx().global_tcx(); let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap(); - if !erased_ty.is_sized(gcx, self.param_env, span) { + if !erased_ty.is_sized(gcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 08c16fed5dd3f..25f933c5da6e7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -286,7 +286,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, self.param_env, DUMMY_SP) + ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) } pub fn load_mir( diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index eb4ba21489c3d..501a9f4b1efc3 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -796,7 +796,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let type_has_metadata = |ty: Ty<'tcx>| -> bool { use syntax_pos::DUMMY_SP; - if ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) { + if ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All)) { return false; } let tail = tcx.struct_tail(ty); diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 981b0b854bdab..83cd7bf549d55 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -77,19 +77,12 @@ impl Lower128Bit { }; let bin_statement = block.statements.pop().unwrap(); - let (source_info, place, lhs, mut rhs) = match bin_statement { - Statement { - source_info, - kind: StatementKind::Assign( - place, - Rvalue::BinaryOp(_, lhs, rhs)) - } => (source_info, place, lhs, rhs), - Statement { - source_info, - kind: StatementKind::Assign( - place, - Rvalue::CheckedBinaryOp(_, lhs, rhs)) - } => (source_info, place, lhs, rhs), + let source_info = bin_statement.source_info; + let (place, lhs, mut rhs) = match bin_statement.kind { + StatementKind::Assign(place, Rvalue::BinaryOp(_, lhs, rhs)) + | StatementKind::Assign(place, Rvalue::CheckedBinaryOp(_, lhs, rhs)) => { + (place, lhs, rhs) + } _ => bug!("Statement doesn't match pattern any more?"), }; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 81cc5e59bbbf7..883e95b7297d6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -18,7 +18,7 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex, use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use rustc::{ty, lint}; -use syntax::ast::{self, Name, Ident}; +use syntax::ast::{self, Name, Ident, Path}; use syntax::attr::{self, HasAttrs}; use syntax::codemap::respan; use syntax::errors::DiagnosticBuilder; @@ -166,16 +166,25 @@ impl<'a> base::Resolver for Resolver<'a> { self.whitelisted_legacy_custom_derives.contains(&name) } - fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]) { + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[(Mark, Path)]) { let invocation = self.invocations[&mark]; self.collect_def_ids(mark, invocation, expansion); self.current_module = invocation.module.get(); - self.current_module.unresolved_invocations.borrow_mut().remove(&mark); - self.current_module.unresolved_invocations.borrow_mut().extend(derives); - for &derive in derives { - self.invocations.insert(derive, invocation); + + { + let mut unresolved = self.current_module.unresolved_invocations.borrow_mut(); + unresolved.remove(&mark); + + unresolved.reserve(derives.len()); + self.invocations.reserve(derives.len()); + + for &(derive, _) in derives { + unresolved.insert(derive); + self.invocations.insert(derive, invocation); + } } + let mut visitor = BuildReducedGraphVisitor { resolver: self, legacy_scope: LegacyScope::Invocation(invocation), diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 37bd225a7d9cb..7c4e2340d5bdc 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -44,7 +44,7 @@ pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> b } pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All)) } pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a285e5f263ab7..1a35a3d9b4038 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -435,7 +435,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { use syntax_pos::DUMMY_SP; - if ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) { + if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All)) { return false; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 7b333270d041c..2209b02fe4530 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ pub use self::SyntaxExtension::*; -use ast::{self, Attribute, Name, PatKind, MetaItem}; +use ast::{self, Attribute, Name, PatKind, MetaItem, Path}; use attr::HasAttrs; use codemap::{self, CodeMap, Spanned, respan}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; @@ -615,7 +615,7 @@ pub trait Resolver { fn eliminate_crate_var(&mut self, item: P) -> P; fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; - fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[(Mark, Path)]); fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc); fn resolve_imports(&mut self); @@ -642,7 +642,9 @@ impl Resolver for DummyResolver { fn eliminate_crate_var(&mut self, item: P) -> P { item } fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } - fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} + fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, + _derives: &[(Mark, Path)]) {} + fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc) {} fn resolve_imports(&mut self) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 377f47a3ea5a1..8f5b87f6dc610 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -46,6 +46,7 @@ macro_rules! expansions { $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { #[derive(Copy, Clone, PartialEq, Eq)] pub enum ExpansionKind { OptExpr, $( $kind, )* } + #[derive(Clone)] pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* } impl ExpansionKind { @@ -210,12 +211,36 @@ impl Invocation { pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, + partial_expansions: HashMap, + full_expansions: HashMap, monotonic: bool, // c.f. `cx.monotonic_expander()` } + +// jseyfried (10/04/2017): +// Partial expansion are macro expansions that have unexpanded macro invocations in them. +// That is, the macro itself has resolved and been expanded, but it created more macro invocations +// that have yet to be expanded. This is in contrast to "fully expanded" AST, +// which has no macro invocations left. +struct PartialExpansion { + expansion: Expansion, + derives: Vec<(Mark, Path)>, + expansion_kind: ExpansionKind, + expansion_data: ExpansionData, + unexpanded_children: usize, +} + +pub struct FullExpansion { + pub expansion: Expansion, + pub derives: Vec, +} + impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { - MacroExpander { cx: cx, monotonic: monotonic } + MacroExpander { + cx: cx, monotonic: monotonic, + partial_expansions: HashMap::new(), full_expansions: HashMap::new(), + } } pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -266,12 +291,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; - let (expansion, mut invocations) = self.collect_invocations(expansion, &[]); + let mark = self.cx.current_expansion.mark; + let mut invocations = + self.collect_invocations(mark, expansion, Vec::new(), ExpansionKind::Items); self.resolve_imports(); invocations.reverse(); - let mut expansions = Vec::new(); - let mut derives = HashMap::new(); let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { @@ -285,8 +310,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { continue }; - let scope = - if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; + let mark = invoc.expansion_data.mark; + let scope = if self.monotonic { mark } else { orig_expansion_data.mark }; let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, @@ -297,16 +322,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; progress = true; - let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); self.cx.current_expansion.mark = scope; - // FIXME(jseyfried): Refactor out the following logic - let (expansion, new_invocations) = if let Some(ext) = ext { + let new_invocations = if let Some(ext) = ext { if let Some(ext) = ext { + let expansion_kind = invoc.expansion_kind; let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap(); let expansion = self.expand_invoc(invoc, &*ext).unwrap_or(dummy); - self.collect_invocations(expansion, &[]) + self.collect_invocations(mark, expansion, Vec::new(), expansion_kind) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), "derive") @@ -326,60 +350,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = self.fully_configure(item) .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); - let item_with_markers = - add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); - let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); - - for path in &traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); - derives.push(mark); - let item = match self.cx.resolver.resolve_macro( - Mark::root(), path, MacroKind::Derive, false) { - Ok(ext) => match *ext { - BuiltinDerive(..) => item_with_markers.clone(), - _ => item.clone(), - }, - _ => item.clone(), - }; - invocations.push(Invocation { - kind: InvocationKind::Derive { path: path.clone(), item: item }, - expansion_kind: invoc.expansion_kind, - expansion_data: ExpansionData { - mark, - ..invoc.expansion_data.clone() - }, - }); - } + let item = add_derived_markers(&mut self.cx, item.span(), &traits, item); let expansion = invoc.expansion_kind - .expect_from_annotatables(::std::iter::once(item_with_markers)); - self.collect_invocations(expansion, derives) + .expect_from_annotatables(::std::iter::once(item)); + self.collect_invocations(mark, expansion, traits, invoc.expansion_kind) } else { unreachable!() } } else { - self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[]) + let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap(); + self.collect_invocations(mark, dummy, Vec::new(), invoc.expansion_kind) }; - if expansions.len() < depth { - expansions.push(Vec::new()); - } - expansions[depth - 1].push((mark, expansion)); if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } } self.cx.current_expansion = orig_expansion_data; + self.placeholder_expander().remove(NodeId::placeholder_from_mark(mark)) + } - let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); - while let Some(expansions) = expansions.pop() { - for (mark, expansion) in expansions.into_iter().rev() { - let derives = derives.remove(&mark).unwrap_or_else(Vec::new); - placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives); - } + fn placeholder_expander<'c>(&'c mut self) -> PlaceholderExpander<'c, 'b> { + PlaceholderExpander { + cx: self.cx, + expansions: &mut self.full_expansions, + monotonic: self.monotonic, } - - expansion.fold_with(&mut placeholder_expander) } fn resolve_imports(&mut self) { @@ -390,9 +387,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark]) - -> (Expansion, Vec) { - let result = { + fn collect_invocations(&mut self, + mut mark: Mark, + expansion: Expansion, + traits: Vec, + expansion_kind: ExpansionKind) + -> Vec { + let (expansion, mut invocations) = { let mut collector = InvocationCollector { cfg: StripUnconfigured { should_test: self.cx.ecfg.should_test, @@ -400,20 +401,77 @@ impl<'a, 'b> MacroExpander<'a, 'b> { features: self.cx.ecfg.features, }, cx: self.cx, + mark: mark, invocations: Vec::new(), monotonic: self.monotonic, }; (expansion.fold_with(&mut collector), collector.invocations) }; + let mark_parent = mark.parent(); + let derives: Vec<_> = + traits.into_iter().map(|path| (Mark::fresh(mark_parent), path)).collect(); + if derives.len() > 0 { + self.partial_expansions.get_mut(&mark_parent).unwrap().unexpanded_children += + derives.len(); + } + if self.monotonic { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); let mark = self.cx.current_expansion.mark; - self.cx.resolver.visit_expansion(mark, &result.0, derives); + self.cx.resolver.visit_expansion(mark, &expansion, &derives); self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; } - result + self.partial_expansions.insert(mark, PartialExpansion { + expansion: expansion, derives: derives, expansion_kind: expansion_kind, + expansion_data: self.cx.current_expansion.clone(), + unexpanded_children: invocations.len(), + }); + + if !invocations.is_empty() { + return invocations; + } + + loop { + let partial_expansion = self.partial_expansions.remove(&mark).unwrap(); + let expansion = partial_expansion.expansion.fold_with(&mut self.placeholder_expander()); + + let PartialExpansion { expansion_kind, ref expansion_data, .. } = partial_expansion; + let derives = partial_expansion.derives.into_iter().map(|(mark, path)| { + let item = match expansion.clone() { + Expansion::Items(mut items) => Annotatable::Item(items.pop().unwrap()), + Expansion::TraitItems(mut items) => + Annotatable::TraitItem(P(items.pop().unwrap())), + Expansion::ImplItems(mut items) => + Annotatable::ImplItem(P(items.pop().unwrap())), + _ => panic!("expected item"), + }; + invocations.push(Invocation { + kind: InvocationKind::Derive { path: path, item: item }, + expansion_kind: expansion_kind, + expansion_data: ExpansionData { mark: mark, ..expansion_data.clone() }, + }); + mark + }).collect(); + + self.full_expansions + .insert(mark, FullExpansion { expansion: expansion, derives: derives }); + + if mark == Mark::root() { + break + } + mark = mark.parent(); + if let Some(partial_expansion) = self.partial_expansions.get_mut(&mark) { + partial_expansion.unexpanded_children -= 1; + if partial_expansion.unexpanded_children == 0 { + continue + } + } + break + } + + invocations } fn fully_configure(&mut self, item: Annotatable) -> Annotatable { @@ -793,6 +851,7 @@ impl<'a> Parser<'a> { struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, + mark: Mark, cfg: StripUnconfigured<'a>, invocations: Vec, monotonic: bool, @@ -800,7 +859,7 @@ struct InvocationCollector<'a, 'b: 'a> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(self.mark); self.invocations.push(Invocation { kind, expansion_kind, @@ -1180,7 +1239,6 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { if self.monotonic { - assert_eq!(id, ast::DUMMY_NODE_ID); self.cx.resolver.next_node_id() } else { id diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 9c2c22476e9d9..671994a321f07 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -11,7 +11,7 @@ use ast::{self, NodeId}; use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; -use ext::expand::{Expansion, ExpansionKind}; +use ext::expand::{Expansion, ExpansionKind, FullExpansion}; use ext::hygiene::Mark; use tokenstream::TokenStream; use fold::*; @@ -74,22 +74,15 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { } pub struct PlaceholderExpander<'a, 'b: 'a> { - expansions: HashMap, - cx: &'a mut ExtCtxt<'b>, - monotonic: bool, + pub expansions: &'a mut HashMap, + pub cx: &'a mut ExtCtxt<'b>, + pub monotonic: bool, } impl<'a, 'b> PlaceholderExpander<'a, 'b> { - pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { - PlaceholderExpander { - cx, - expansions: HashMap::new(), - monotonic, - } - } - - pub fn add(&mut self, id: ast::NodeId, expansion: Expansion, derives: Vec) { - let mut expansion = expansion.fold_with(self); + pub fn remove(&mut self, id: ast::NodeId) -> Expansion { + let FullExpansion { mut expansion, derives } = + self.expansions.remove(&id.placeholder_to_mark()).unwrap(); if let Expansion::Items(mut items) = expansion { for derive in derives { match self.remove(NodeId::placeholder_from_mark(derive)) { @@ -99,11 +92,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } expansion = Expansion::Items(items); } - self.expansions.insert(id, expansion); - } - - fn remove(&mut self, id: ast::NodeId) -> Expansion { - self.expansions.remove(&id).unwrap() + expansion } } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 22e78e9b426b2..4ca535ccc587a 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -13,7 +13,7 @@ use std::panic; use errors::FatalError; use proc_macro::{TokenStream, __internal}; use syntax::ast::{self, ItemKind, Attribute, Mac}; -use syntax::attr::{mark_used, mark_known}; +use syntax::attr::{HasAttrs, mark_used, mark_known}; use syntax::codemap::Span; use syntax::ext::base::*; use syntax::visit::Visitor; @@ -70,6 +70,11 @@ impl MultiItemModifier for ProcMacroDerive { } } + let item = item.map_attrs(|mut attrs| { + attrs.retain(|a| a.path != "structural_match" && a.path != "rustc_copy_clone_marker"); + attrs + }); + // Mark attributes as known, and used. MarkAttrs(&self.attrs).visit_item(&item); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1b3917efdd1e7..a96fc17130c07 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -349,21 +349,15 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. -fn find_type_parameters(ty: &ast::Ty, - ty_param_names: &[ast::Name], - span: Span, - cx: &ExtCtxt) - -> Vec> { +fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec> { use syntax::visit; - struct Visitor<'a, 'b: 'a> { - cx: &'a ExtCtxt<'b>, - span: Span, + struct Visitor<'a> { ty_param_names: &'a [ast::Name], types: Vec>, } - impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { + impl<'a> visit::Visitor<'a> for Visitor<'a> { fn visit_ty(&mut self, ty: &'a ast::Ty) { if let ast::TyKind::Path(_, ref path) = ty.node { if let Some(segment) = path.segments.first() { @@ -375,18 +369,11 @@ fn find_type_parameters(ty: &ast::Ty, visit::walk_ty(self, ty) } - - fn visit_mac(&mut self, mac: &ast::Mac) { - let span = mac.span.with_ctxt(self.span.ctxt()); - self.cx.span_err(span, "`derive` cannot be used on items with type macros"); - } } let mut visitor = Visitor { ty_param_names, types: Vec::new(), - span, - cx, }; visit::Visitor::visit_ty(&mut visitor, ty); @@ -616,7 +603,7 @@ impl<'a> TraitDef<'a> { let mut processed_field_types = HashSet::new(); for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, self.span, cx); + let tys = find_type_parameters(&field_ty, &ty_param_names); for ty in tys { // if we have already handled this type, skip it diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index b7fba9fe8dfb0..bbb8177022356 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -75,6 +75,10 @@ impl Mark { Mark(raw) } + pub fn parent(self) -> Mark { + HygieneData::with(|data| data.marks[self.0 as usize].parent) + } + #[inline] pub fn expn_info(self) -> Option { HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone()) diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index fbe2fd10e7a14..1e02fe4befdf5 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -18,7 +18,6 @@ // ignore-hexagon // ignore-mips // ignore-powerpc -// ignore-powerpc64 // ignore-s390x // ignore-sparc // ignore-wasm32 diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index 346c5da8d1b8d..b24899cc363a0 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -25,8 +25,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs index 5bd0c1b4076ee..5661592d0c7b2 100644 --- a/src/test/codegen/global_asm.rs +++ b/src/test/codegen/global_asm.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs index 401b1fad566d5..d8b5db12404ac 100644 --- a/src/test/codegen/global_asm_include.rs +++ b/src/test/codegen/global_asm_include.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs index 8b59165e9e61b..caa0506550dde 100644 --- a/src/test/codegen/global_asm_x2.rs +++ b/src/test/codegen/global_asm_x2.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788ce2..655e67cf7eefe 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -14,7 +14,6 @@ // ignore-mips // ignore-mips64 // ignore-powerpc -// ignore-powerpc64 // See repr-transparent.rs #![crate_type="lib"] diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/type_macros_example.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/type_macros_example.rs new file mode 100644 index 0000000000000..ca7e10e11d1ff --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/type_macros_example.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Example)] +pub fn example(input: TokenStream) -> TokenStream { + assert!(input.to_string().contains("i32")); + "".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/type_macros.rs b/src/test/run-pass-fulldeps/proc-macro/type_macros.rs new file mode 100644 index 0000000000000..a9c6e273e06c6 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/type_macros.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:type_macros_example.rs + +#![feature(proc_macro)] + +extern crate type_macros_example; + +use type_macros_example::Example; + +macro_rules! m { () => { i32 } } + +#[derive(Example)] +struct S { + x: m!(), +} + +fn main() {} diff --git a/src/test/ui/issue-32950.rs b/src/test/run-pass/issue-32950.rs similarity index 83% rename from src/test/ui/issue-32950.rs rename to src/test/run-pass/issue-32950.rs index 4e5cdd50b2a95..bcbc0ee3df63b 100644 --- a/src/test/ui/issue-32950.rs +++ b/src/test/run-pass/issue-32950.rs @@ -11,8 +11,11 @@ #![feature(concat_idents)] #[derive(Debug)] -struct Baz( - concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros +struct Baz(T, + concat_idents!(Foo, Bar) ); +#[derive(Debug)] +struct FooBar; + fn main() {} diff --git a/src/test/ui-fulldeps/custom-derive/auxiliary/plugin.rs b/src/test/ui-fulldeps/custom-derive/auxiliary/plugin.rs index c5ba2aa9413e7..894688ea900a1 100644 --- a/src/test/ui-fulldeps/custom-derive/auxiliary/plugin.rs +++ b/src/test/ui-fulldeps/custom-derive/auxiliary/plugin.rs @@ -19,7 +19,7 @@ use proc_macro::TokenStream; #[proc_macro_derive(Foo)] pub fn derive_foo(input: TokenStream) -> TokenStream { - input + "".parse().unwrap() } #[proc_macro_derive(Bar)] diff --git a/src/test/ui/issue-32950.stderr b/src/test/ui/issue-32950.stderr deleted file mode 100644 index 0363bf05f0080..0000000000000 --- a/src/test/ui/issue-32950.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `derive` cannot be used on items with type macros - --> $DIR/issue-32950.rs:15:5 - | -LL | concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs new file mode 100644 index 0000000000000..495989587e585 --- /dev/null +++ b/src/test/ui/lint/type-overflow.rs @@ -0,0 +1,33 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +#![feature(i128_type)] + +fn main() { + let error = 255i8; //~WARNING literal out of range for i8 + + let ok = 0b1000_0001; // should be ok -> i32 + let ok = 0b0111_1111i8; // should be ok -> 127i8 + + let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 + + let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 + + let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 + + let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + //~^ WARNING literal out of range for i128 + + let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 + + let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 +} diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr new file mode 100644 index 0000000000000..d3fcb1335e209 --- /dev/null +++ b/src/test/ui/lint/type-overflow.stderr @@ -0,0 +1,58 @@ +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:16:17 + | +LL | let error = 255i8; //~WARNING literal out of range for i8 + | ^^^^^ + | + = note: #[warn(overflowing_literals)] on by default + +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:21:16 + | +LL | let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 + | ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8` + | + = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into an `i8` and will become `-127i8` + +warning: literal out of range for i64 + --> $DIR/type-overflow.rs:23:16 + | +LL | let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64` + | + = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into an `i64` and will become `-9223372036854775808i64` + +warning: literal out of range for u32 + --> $DIR/type-overflow.rs:25:16 + | +LL | let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 + | ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64` + | + = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into an `u32` and will become `4294967295u32` + +warning: literal out of range for i128 + --> $DIR/type-overflow.rs:27:22 + | +LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into an `i128` and will become `-170141183460469231731687303715884105728i128` + = help: consider using `u128` instead + +warning: literal out of range for i32 + --> $DIR/type-overflow.rs:30:16 + | +LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into an `i32` and will become `-2i32` + = help: consider using `i128` instead + +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:32:17 + | +LL | let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 + | ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16` + | + = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into an `i8` and will become `-1i8` + diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 3c9dae915b5a2..cf63cb2e5d901 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -43,7 +43,6 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("mips", "mips"), ("msp430", "msp430"), ("powerpc", "powerpc"), - ("powerpc64", "powerpc64"), ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"),