From f0e3258a7700b47aece5b3e2140bb33c9bfc5541 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 30 Jul 2019 15:57:10 -0700 Subject: [PATCH 01/18] rustc: implement argsfiles for command line This makes `rustc` support `@path` arguments on the command line. The `path` is opened and the file is interpreted as new command line options which are logically inserted at that point in the command-line. The options in the file are one per line. The file is UTF-8 encoded, and may have either Unix or Windows line endings. It does not support recursive use of `@path`. This is useful for very large command lines, or when command-lines are being generated into files by other tooling. --- src/doc/rustc/src/command-line-arguments.md | 7 + src/librustc_driver/args/mod.rs | 145 ++++++++++++++++++ src/librustc_driver/args/tests.rs | 137 +++++++++++++++++ src/librustc_driver/lib.rs | 15 +- src/test/ui/commandline-argfile-badutf8.args | 2 + src/test/ui/commandline-argfile-badutf8.rs | 13 ++ .../ui/commandline-argfile-badutf8.stderr | 2 + src/test/ui/commandline-argfile-missing.rs | 13 ++ .../ui/commandline-argfile-missing.stderr | 2 + src/test/ui/commandline-argfile.args | 2 + src/test/ui/commandline-argfile.rs | 13 ++ 11 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 src/librustc_driver/args/mod.rs create mode 100644 src/librustc_driver/args/tests.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.args create mode 100644 src/test/ui/commandline-argfile-badutf8.rs create mode 100644 src/test/ui/commandline-argfile-badutf8.stderr create mode 100644 src/test/ui/commandline-argfile-missing.rs create mode 100644 src/test/ui/commandline-argfile-missing.stderr create mode 100644 src/test/ui/commandline-argfile.args create mode 100644 src/test/ui/commandline-argfile.rs diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d774e465118b3..59e7c808cdad5 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -304,3 +304,10 @@ to customize the output: Note that it is invalid to combine the `--json` argument with the `--color` argument, and it is required to combine `--json` with `--error-format=json`. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. \ No newline at end of file diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs new file mode 100644 index 0000000000000..23472d27cb22b --- /dev/null +++ b/src/librustc_driver/args/mod.rs @@ -0,0 +1,145 @@ +#![allow(dead_code)] + +use std::env; +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; + +#[cfg(test)] +mod tests; + +/// States for parsing text +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum State { + Normal, // within normal text + Cr, // just saw \r + Lf, // just saw \n +} + +struct FileArgs { + path: String, + input: Vec, + offset: usize, +} + +impl FileArgs { + pub fn new(path: String, input: Vec) -> Self { + FileArgs { path, input, offset: 0 } + } +} + +impl Iterator for FileArgs { + type Item = Result; + + fn next(&mut self) -> Option { + if self.offset >= self.input.len() { + // All done + return None; + } + + use State::*; + let mut state = Normal; + let start = self.offset; + let mut end = start; + + for (idx, b) in self.input[start..].iter().enumerate() { + let idx = start + idx + 1; + + self.offset = idx; + + match (b, state) { + (b'\r', Normal) => state = Cr, + (b'\n', Normal) => state = Lf, + + (b'\r', Lf) | (b'\n', Cr) => { + // Two-character line break (accept \r\n and \n\r(?)), so consume them both + break; + } + + (_, Cr) | (_, Lf) => { + // Peeked at character after single-character line break, so rewind to visit it + // next time around. + self.offset = idx - 1; + break; + } + + (_, _) => { + end = idx; + state = Normal; + } + } + } + + Some( + String::from_utf8(self.input[start..end].to_vec()) + .map_err(|_| Error::Utf8Error(Some(self.path.clone()))), + ) + } +} + +pub struct ArgsIter { + base: env::ArgsOs, + file: Option, +} + +impl ArgsIter { + pub fn new() -> Self { + ArgsIter { base: env::args_os(), file: None } + } +} + +impl Iterator for ArgsIter { + type Item = Result; + + fn next(&mut self) -> Option { + loop { + if let Some(ref mut file) = &mut self.file { + match file.next() { + Some(res) => return Some(res.map_err(From::from)), + None => self.file = None, + } + } + + let arg = + self.base.next().map(|arg| arg.into_string().map_err(|_| Error::Utf8Error(None))); + match arg { + Some(Err(err)) => return Some(Err(err)), + Some(Ok(ref arg)) if arg.starts_with("@") => { + // can't not be utf-8 now + let path = str::from_utf8(&arg.as_bytes()[1..]).unwrap(); + let file = match fs::read(path) { + Ok(file) => file, + Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), + }; + self.file = Some(FileArgs::new(path.to_string(), file)); + } + Some(Ok(arg)) => return Some(Ok(arg)), + None => return None, + } + } + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + IOError(String, io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Utf8Error(None) => write!(fmt, "Utf8 error"), + Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {}", path), + Error::IOError(path, err) => write!(fmt, "IO Error: {}: {}", path, err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs new file mode 100644 index 0000000000000..8bbc2cb053ea9 --- /dev/null +++ b/src/librustc_driver/args/tests.rs @@ -0,0 +1,137 @@ +use super::*; + +fn want_args(v: impl IntoIterator) -> Vec { + v.into_iter().map(String::from).collect() +} + +fn got_args(file: &[u8]) -> Result, Error> { + FileArgs::new(String::new(), file.to_vec()).collect() +} + +#[test] +fn nothing() { + let file = b""; + + assert_eq!(got_args(file).unwrap(), want_args(vec![])); +} + +#[test] +fn empty() { + let file = b"\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec![""])); +} + +#[test] +fn simple() { + let file = b"foo"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn simple_eol() { + let file = b"foo\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi() { + let file = b"foo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol() { + let file = b"foo\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty() { + let file = b"foo\n\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol() { + let file = b"foo\n\nbar\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start() { + let file = b"\nfoo\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end() { + let file = b"foo\nbar\n\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +fn simple_eol_crlf() { + let file = b"foo\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo"])); +} + +#[test] +fn multi_crlf() { + let file = b"foo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_eol_crlf() { + let file = b"foo\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar"])); +} + +#[test] +fn multi_empty_crlf() { + let file = b"foo\r\n\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_eol_crlf() { + let file = b"foo\r\n\r\nbar\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "", "bar"])); +} + +#[test] +fn multi_empty_start_crlf() { + let file = b"\r\nfoo\r\nbar"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["", "foo", "bar"])); +} + +#[test] +fn multi_empty_end_crlf() { + let file = b"foo\r\nbar\r\n\r\n"; + + assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); +} + +#[test] +fn bad_utf8() { + let file = b"foo\x80foo"; + + match got_args(file).unwrap_err() { + Error::Utf8Error(_) => (), + bad => panic!("bad err: {:?}", bad), + } +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e9d85a53d1e42..b853bd99c7885 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -66,6 +66,7 @@ use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; pub mod pretty; +mod args; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -777,11 +778,17 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{}\nAdditional help: + let at_path = if verbose { + " @path Read newline separated options from `path`\n" + } else { + "" + }; + println!("{}{}\nAdditional help: -C help Print codegen options -W help \ Print 'lint' options and default settings{}{}\n", options.usage(message), + at_path, nightly_help, verbose_help); } @@ -1186,10 +1193,10 @@ pub fn main() { init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); let result = report_ices_to_stderr_if_any(|| { - let args = env::args_os().enumerate() - .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { + let args = args::ArgsIter::new().enumerate() + .map(|(i, arg)| arg.unwrap_or_else(|err| { early_error(ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg)) + &format!("Argument {} is not valid: {}", i, err)) })) .collect::>(); run_compiler(&args, &mut callbacks, None, None) diff --git a/src/test/ui/commandline-argfile-badutf8.args b/src/test/ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken€ \ No newline at end of file diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..161715685b57f --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..82348d5e89aa0 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Argument 19 is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..86a6ec54a3ae4 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..9bd929111eb81 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Argument 18 is not valid: IO Error: $DIR/commandline-argfile-missing.args: No such file or directory (os error 2) + diff --git a/src/test/ui/commandline-argfile.args b/src/test/ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/ui/commandline-argfile.rs b/src/test/ui/commandline-argfile.rs new file mode 100644 index 0000000000000..fc1ba0c8d677d --- /dev/null +++ b/src/test/ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} From a0dbeea9810739f6c494ba59840c09434ad8b221 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 1 Aug 2019 11:06:52 -0700 Subject: [PATCH 02/18] Use named arguments for formatting usage message. It was getting a bit awkward. --- src/librustc_driver/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b853bd99c7885..7b11a41d6cd80 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -783,14 +783,14 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "" }; - println!("{}{}\nAdditional help: + println!("{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{}{}\n", - options.usage(message), - at_path, - nightly_help, - verbose_help); + Print 'lint' options and default settings{nightly}{verbose}\n", + options = options.usage(message), + at_path = at_path, + nightly = nightly_help, + verbose = verbose_help); } fn print_wall_help() { From 4fc66a75fa4a56a30989d392598fd717a6c35e78 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 8 Aug 2019 16:47:44 -0700 Subject: [PATCH 03/18] Use BufReader::lines() to parse out the lines It already imlements the right behaviour, and it saves us implementing the state machine. --- src/librustc_driver/args/mod.rs | 84 +++++++------------------------ src/librustc_driver/args/tests.rs | 3 +- 2 files changed, 19 insertions(+), 68 deletions(-) diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs index 23472d27cb22b..349812877e54e 100644 --- a/src/librustc_driver/args/mod.rs +++ b/src/librustc_driver/args/mod.rs @@ -1,87 +1,38 @@ -#![allow(dead_code)] - use std::env; use std::error; use std::fmt; use std::fs; -use std::io; +use std::io::{self, BufRead}; use std::str; #[cfg(test)] mod tests; -/// States for parsing text -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -enum State { - Normal, // within normal text - Cr, // just saw \r - Lf, // just saw \n -} - struct FileArgs { path: String, input: Vec, - offset: usize, } impl FileArgs { - pub fn new(path: String, input: Vec) -> Self { - FileArgs { path, input, offset: 0 } + fn new(path: String, input: Vec) -> Self { + FileArgs { path, input } } -} - -impl Iterator for FileArgs { - type Item = Result; - - fn next(&mut self) -> Option { - if self.offset >= self.input.len() { - // All done - return None; - } - - use State::*; - let mut state = Normal; - let start = self.offset; - let mut end = start; - - for (idx, b) in self.input[start..].iter().enumerate() { - let idx = start + idx + 1; - - self.offset = idx; - - match (b, state) { - (b'\r', Normal) => state = Cr, - (b'\n', Normal) => state = Lf, - - (b'\r', Lf) | (b'\n', Cr) => { - // Two-character line break (accept \r\n and \n\r(?)), so consume them both - break; - } - - (_, Cr) | (_, Lf) => { - // Peeked at character after single-character line break, so rewind to visit it - // next time around. - self.offset = idx - 1; - break; - } - - (_, _) => { - end = idx; - state = Normal; - } - } - } - Some( - String::from_utf8(self.input[start..end].to_vec()) - .map_err(|_| Error::Utf8Error(Some(self.path.clone()))), - ) + fn lines(self) -> impl Iterator> { + let Self { input, path } = self; + io::Cursor::new(input).lines().map(move |res| { + let path = path.clone(); + res.map_err(move |err| match err.kind() { + io::ErrorKind::InvalidData => Error::Utf8Error(Some(path)), + _ => Error::IOError(path, err), + }) + }) } } pub struct ArgsIter { base: env::ArgsOs, - file: Option, + file: Option>>>, } impl ArgsIter { @@ -107,13 +58,12 @@ impl Iterator for ArgsIter { match arg { Some(Err(err)) => return Some(Err(err)), Some(Ok(ref arg)) if arg.starts_with("@") => { - // can't not be utf-8 now - let path = str::from_utf8(&arg.as_bytes()[1..]).unwrap(); - let file = match fs::read(path) { - Ok(file) => file, + let path = &arg[1..]; + let lines = match fs::read(path) { + Ok(file) => FileArgs::new(path.to_string(), file).lines(), Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), }; - self.file = Some(FileArgs::new(path.to_string(), file)); + self.file = Some(Box::new(lines)); } Some(Ok(arg)) => return Some(Ok(arg)), None => return None, diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs index 8bbc2cb053ea9..88a0dbc00e2c2 100644 --- a/src/librustc_driver/args/tests.rs +++ b/src/librustc_driver/args/tests.rs @@ -5,7 +5,7 @@ fn want_args(v: impl IntoIterator) -> Vec { } fn got_args(file: &[u8]) -> Result, Error> { - FileArgs::new(String::new(), file.to_vec()).collect() + FileArgs::new(String::new(), file.to_vec()).lines().collect() } #[test] @@ -78,6 +78,7 @@ fn multi_empty_end() { assert_eq!(got_args(file).unwrap(), want_args(vec!["foo", "bar", ""])); } +#[test] fn simple_eol_crlf() { let file = b"foo\r\n"; From 892ae4168867374835c5b434aa9330aa6757abee Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 9 Aug 2019 18:38:26 -0700 Subject: [PATCH 04/18] Require -Zunstable-options to use @path --- src/librustc_driver/args/mod.rs | 12 +++++++++++- src/librustc_driver/lib.rs | 8 +++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs index 349812877e54e..e9323b7051d35 100644 --- a/src/librustc_driver/args/mod.rs +++ b/src/librustc_driver/args/mod.rs @@ -4,10 +4,17 @@ use std::fmt; use std::fs; use std::io::{self, BufRead}; use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; #[cfg(test)] mod tests; +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + struct FileArgs { path: String, input: Vec, @@ -60,7 +67,10 @@ impl Iterator for ArgsIter { Some(Ok(ref arg)) if arg.starts_with("@") => { let path = &arg[1..]; let lines = match fs::read(path) { - Ok(file) => FileArgs::new(path.to_string(), file).lines(), + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + FileArgs::new(path.to_string(), file).lines() + } Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), }; self.file = Some(Box::new(lines)); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7b11a41d6cd80..eb5a8dec97ca3 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -778,7 +778,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - let at_path = if verbose { + let at_path = if verbose && nightly_options::is_nightly_build() { " @path Read newline separated options from `path`\n" } else { "" @@ -1015,6 +1015,12 @@ pub fn handle_options(args: &[String]) -> Option { // (unstable option being used on stable) nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); + // Late check to see if @file was used without unstable options enabled + if crate::args::used_unstable_argsfile() && !nightly_options::is_unstable_enabled(&matches) { + early_error(ErrorOutputType::default(), + "@path is unstable - use -Z unstable-options to enable its use"); + } + if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); From b5404f0ccbfd148fd558ec87e6c37e37f612bfcf Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 13 Aug 2019 09:47:51 -0700 Subject: [PATCH 05/18] Simplify by removing FileArgs --- src/librustc_driver/args/mod.rs | 45 +++++-------------- src/librustc_driver/args/tests.rs | 9 +++- .../ui/commandline-argfile-badutf8.stderr | 2 +- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/librustc_driver/args/mod.rs b/src/librustc_driver/args/mod.rs index e9323b7051d35..a59f9afd8beb5 100644 --- a/src/librustc_driver/args/mod.rs +++ b/src/librustc_driver/args/mod.rs @@ -2,7 +2,7 @@ use std::env; use std::error; use std::fmt; use std::fs; -use std::io::{self, BufRead}; +use std::io; use std::str; use std::sync::atomic::{AtomicBool, Ordering}; @@ -15,36 +15,14 @@ pub fn used_unstable_argsfile() -> bool { USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) } -struct FileArgs { - path: String, - input: Vec, -} - -impl FileArgs { - fn new(path: String, input: Vec) -> Self { - FileArgs { path, input } - } - - fn lines(self) -> impl Iterator> { - let Self { input, path } = self; - io::Cursor::new(input).lines().map(move |res| { - let path = path.clone(); - res.map_err(move |err| match err.kind() { - io::ErrorKind::InvalidData => Error::Utf8Error(Some(path)), - _ => Error::IOError(path, err), - }) - }) - } -} - pub struct ArgsIter { base: env::ArgsOs, - file: Option>>>, + file: std::vec::IntoIter, } impl ArgsIter { pub fn new() -> Self { - ArgsIter { base: env::args_os(), file: None } + ArgsIter { base: env::args_os(), file: vec![].into_iter() } } } @@ -53,11 +31,8 @@ impl Iterator for ArgsIter { fn next(&mut self) -> Option { loop { - if let Some(ref mut file) = &mut self.file { - match file.next() { - Some(res) => return Some(res.map_err(From::from)), - None => self.file = None, - } + if let Some(line) = self.file.next() { + return Some(Ok(line)); } let arg = @@ -66,14 +41,18 @@ impl Iterator for ArgsIter { Some(Err(err)) => return Some(Err(err)), Some(Ok(ref arg)) if arg.starts_with("@") => { let path = &arg[1..]; - let lines = match fs::read(path) { + let file = match fs::read_to_string(path) { Ok(file) => { USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); - FileArgs::new(path.to_string(), file).lines() + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Some(Err(Error::Utf8Error(Some(path.to_string())))); } Err(err) => return Some(Err(Error::IOError(path.to_string(), err))), }; - self.file = Some(Box::new(lines)); + self.file = + file.lines().map(ToString::to_string).collect::>().into_iter(); } Some(Ok(arg)) => return Some(Ok(arg)), None => return None, diff --git a/src/librustc_driver/args/tests.rs b/src/librustc_driver/args/tests.rs index 88a0dbc00e2c2..080dd5cb746c3 100644 --- a/src/librustc_driver/args/tests.rs +++ b/src/librustc_driver/args/tests.rs @@ -1,11 +1,18 @@ use super::*; +use std::str; + fn want_args(v: impl IntoIterator) -> Vec { v.into_iter().map(String::from).collect() } fn got_args(file: &[u8]) -> Result, Error> { - FileArgs::new(String::new(), file.to_vec()).lines().collect() + let ret = str::from_utf8(file) + .map_err(|_| Error::Utf8Error(None))? + .lines() + .map(ToString::to_string) + .collect::>(); + Ok(ret) } #[test] diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr index 82348d5e89aa0..98cd207931f8c 100644 --- a/src/test/ui/commandline-argfile-badutf8.stderr +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -1,2 +1,2 @@ -error: Argument 19 is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args +error: Argument 18 is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args From 1ab9e523f37bdc156bb9ab9d8b52749bc428437c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 14 Aug 2019 10:35:24 +0300 Subject: [PATCH 06/18] Update rustc-demangle to 0.1.16. --- Cargo.lock | 8 ++++---- src/librustc_codegen_utils/Cargo.toml | 2 +- src/test/ui/symbol-names/issue-60925.legacy.stderr | 4 ++-- src/test/ui/symbol-names/issue-60925.rs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab6731e4d433d..02a5876243be9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2736,7 +2736,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2894,7 +2894,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_metadata 0.0.0", "rustc_target 0.0.0", @@ -4600,7 +4600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61673783f2089e01033ffa82d1988f55175402071b31253a358292e1624d4602" "checksum rustc-ap-syntax 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28f3dd1346d5b0269c07a4a78855e309a298ab569c9c1302d4d4f57f8eee4e84" "checksum rustc-ap-syntax_pos 546.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45e67b526dbda3a0c7dab91c8947d43685e7697f52686a4949da3c179cd7c979" -"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363" "checksum rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543" diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index d93589ea84be0..89b50c5daccae 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,7 +13,7 @@ test = false flate2 = "1.0" log = "0.4" punycode = "0.4.0" -rustc-demangle = "0.1.15" +rustc-demangle = "0.1.16" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 7fcd2ede31b69..de8efdde737f0 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -4,13 +4,13 @@ error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3f LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo::foo::h059a991a004536ad) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling-alt(issue_60925::foo::Foo::foo) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 89de15cc0f3e4..02438351dbc6e 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -20,8 +20,8 @@ mod foo { impl Foo<::llvm::Foo> { #[rustc_symbol_name] //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo - //[legacy]~| ERROR demangling(issue_60925::foo::Foo::foo + //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo::foo) //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) //[v0]~| ERROR demangling(>::foo) //[v0]~| ERROR demangling-alt(>::foo) From 55caf1dcd35789bee98a4fd2b537f57cf7edd77a Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Wed, 14 Aug 2019 08:30:59 -0700 Subject: [PATCH 07/18] Remap paths for proc-macro crates. The remap-debuginfo config option remaps paths in most crates, but it does not apply to proc-macros, so they are still non-reproducible. This patch fixes that. --- src/bootstrap/bin/rustc.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 54b689fb062a5..c524cf646dd57 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -305,6 +305,16 @@ fn main() { cmd.arg("-C").arg("target-feature=-crt-static"); } } + + let crate_type = args.windows(2) + .find(|w| &*w[0] == "--crate-type") + .and_then(|w| w[1].to_str()); + + if let Some("proc-macro") = crate_type { + if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { + cmd.arg("--remap-path-prefix").arg(&map); + } + } } // Force all crates compiled by this compiler to (a) be unstable and (b) From 9e2d02a1a1c657fece7ed4f5c71fbdf484931ddc Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Wed, 14 Aug 2019 10:47:06 -0700 Subject: [PATCH 08/18] Remap debuginfo for all crates. --- src/bootstrap/bin/rustc.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index c524cf646dd57..8d59d2e93c0cc 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -287,10 +287,6 @@ fn main() { cmd.arg("-C").arg("target-feature=-crt-static"); } } - - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { - cmd.arg("--remap-path-prefix").arg(&map); - } } else { // Override linker if necessary. if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { @@ -305,16 +301,10 @@ fn main() { cmd.arg("-C").arg("target-feature=-crt-static"); } } + } - let crate_type = args.windows(2) - .find(|w| &*w[0] == "--crate-type") - .and_then(|w| w[1].to_str()); - - if let Some("proc-macro") = crate_type { - if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { - cmd.arg("--remap-path-prefix").arg(&map); - } - } + if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { + cmd.arg("--remap-path-prefix").arg(&map); } // Force all crates compiled by this compiler to (a) be unstable and (b) From 6589dcea724a5bc96b7a76040777d44be5a25db7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 15 Aug 2019 14:23:01 -0700 Subject: [PATCH 09/18] Normalize test results for different test environments --- src/test/ui/commandline-argfile-badutf8.rs | 1 + src/test/ui/commandline-argfile-badutf8.stderr | 2 +- src/test/ui/commandline-argfile-missing.rs | 2 ++ src/test/ui/commandline-argfile-missing.stderr | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs index 161715685b57f..c017e7b5ea60b 100644 --- a/src/test/ui/commandline-argfile-badutf8.rs +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -1,6 +1,7 @@ // Check to see if we can get parameters from an @argsfile file // // build-fail +// normalize-stderr-test: "Argument \d+" -> "Argument $$N" // compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args #[cfg(not(cmdline_set))] diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr index 98cd207931f8c..cd8a03e34eac9 100644 --- a/src/test/ui/commandline-argfile-badutf8.stderr +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -1,2 +1,2 @@ -error: Argument 18 is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args +error: Argument $N is not valid: Utf8 error in $DIR/commandline-argfile-badutf8.args diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs index 86a6ec54a3ae4..ad223feb2d1c1 100644 --- a/src/test/ui/commandline-argfile-missing.rs +++ b/src/test/ui/commandline-argfile-missing.rs @@ -1,6 +1,8 @@ // Check to see if we can get parameters from an @argsfile file // // build-fail +// normalize-stderr-test: "Argument \d+" -> "Argument $$N" +// normalize-stderr-test: "os error \d+" -> "os error $$ERR" // compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args #[cfg(not(cmdline_set))] diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr index 9bd929111eb81..e33d312e7ce1d 100644 --- a/src/test/ui/commandline-argfile-missing.stderr +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -1,2 +1,2 @@ -error: Argument 18 is not valid: IO Error: $DIR/commandline-argfile-missing.args: No such file or directory (os error 2) +error: Argument $N is not valid: IO Error: $DIR/commandline-argfile-missing.args: No such file or directory (os error $ERR) From 178abd7d810a15a39baf2ab366e8fde0974287c7 Mon Sep 17 00:00:00 2001 From: Justin Restivo Date: Fri, 16 Aug 2019 12:39:45 -0400 Subject: [PATCH 10/18] add git keyword to submodule option --- config.toml.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.toml.example b/config.toml.example index cb9f388a8e47b..a3ec4f2044cbd 100644 --- a/config.toml.example +++ b/config.toml.example @@ -141,10 +141,10 @@ # library and facade crates. #compiler-docs = false -# Indicate whether submodules are managed and updated automatically. +# Indicate whether git submodules are managed and updated automatically. #submodules = true -# Update submodules only when the checked out commit in the submodules differs +# Update git submodules only when the checked out commit in the submodules differs # from what is committed in the main rustc repo. #fast-submodules = true From 0f1da639d4ad18a762834069c588e89b2b252cab Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 16 Aug 2019 20:02:31 +0300 Subject: [PATCH 11/18] Rename overflowing_{add,sub,mul} intrinsics to wrapping_{add,sub,mul}. --- src/libcore/intrinsics.rs | 22 +++++++++ src/libcore/num/mod.rs | 48 ++++++++++++++++--- src/librustc_codegen_llvm/intrinsic.rs | 8 ++-- src/librustc_mir/interpret/intrinsics.rs | 12 ++--- src/librustc_mir/transform/qualify_consts.rs | 6 +-- .../transform/qualify_min_const_fn.rs | 6 +-- src/librustc_typeck/check/intrinsic.rs | 4 +- 7 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ceaa870d2b3f7..995ee56440ea5 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1293,18 +1293,40 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) + #[cfg(bootstrap)] pub fn overflowing_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) + #[cfg(bootstrap)] pub fn overflowing_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) + #[cfg(bootstrap)] pub fn overflowing_mul(a: T, b: T) -> T; + /// Returns (a + b) mod 2N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_add` method. For example, + /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) + #[cfg(not(bootstrap))] + pub fn wrapping_add(a: T, b: T) -> T; + /// Returns (a - b) mod 2N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_sub` method. For example, + /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) + #[cfg(not(bootstrap))] + pub fn wrapping_sub(a: T, b: T) -> T; + /// Returns (a * b) mod 2N, where N is the width of T in bits. + /// The stabilized versions of this intrinsic are available on the integer + /// primitives via the `wrapping_mul` method. For example, + /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) + #[cfg(not(bootstrap))] + pub fn wrapping_mul(a: T, b: T) -> T; + /// Computes `a + b`, while saturating at numeric bounds. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `saturating_add` method. For example, diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 67e30e7ffcb24..f82d94153e846 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1112,7 +1112,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::overflowing_add(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_add(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_add(self, rhs) + } } } @@ -1135,7 +1141,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::overflowing_sub(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_sub(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_sub(self, rhs) + } } } @@ -1157,7 +1169,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::overflowing_mul(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_mul(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_mul(self, rhs) + } } } @@ -3031,7 +3049,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::overflowing_add(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_add(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_add(self, rhs) + } } } @@ -3053,7 +3077,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::overflowing_sub(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_sub(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_sub(self, rhs) + } } } @@ -3076,7 +3106,13 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::overflowing_mul(self, rhs) + #[cfg(bootstrap)] { + intrinsics::overflowing_mul(self, rhs) + } + + #[cfg(not(bootstrap))] { + intrinsics::wrapping_mul(self, rhs) + } } doc_comment! { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index a9b8962f45b1b..9483ffca448e3 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -328,7 +328,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { }, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | - "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "mul_with_overflow" | "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" | "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => { @@ -398,9 +398,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; }, - "overflowing_add" => self.add(args[0].immediate(), args[1].immediate()), - "overflowing_sub" => self.sub(args[0].immediate(), args[1].immediate()), - "overflowing_mul" => self.mul(args[0].immediate(), args[1].immediate()), + "wrapping_add" => self.add(args[0].immediate(), args[1].immediate()), + "wrapping_sub" => self.sub(args[0].immediate(), args[1].immediate()), + "wrapping_mul" => self.mul(args[0].immediate(), args[1].immediate()), "exact_div" => if signed { self.exactsdiv(args[0].immediate(), args[1].immediate()) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 89c5be137a4e5..ee105fed1a324 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -110,18 +110,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(out_val, dest)?; } - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" + | "wrapping_add" + | "wrapping_sub" + | "wrapping_mul" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let lhs = self.read_immediate(args[0])?; let rhs = self.read_immediate(args[1])?; let (bin_op, ignore_overflow) = match intrinsic_name { - "overflowing_add" => (BinOp::Add, true), - "overflowing_sub" => (BinOp::Sub, true), - "overflowing_mul" => (BinOp::Mul, true), + "wrapping_add" => (BinOp::Add, true), + "wrapping_sub" => (BinOp::Sub, true), + "wrapping_mul" => (BinOp::Mul, true), "add_with_overflow" => (BinOp::Add, false), "sub_with_overflow" => (BinOp::Sub, false), "mul_with_overflow" => (BinOp::Mul, false), diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index dcfc80968f31c..fba1e19dd0e8e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -537,9 +537,9 @@ impl Qualif for IsNotPromotable { | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" - | "overflowing_add" - | "overflowing_sub" - | "overflowing_mul" + | "wrapping_add" + | "wrapping_sub" + | "wrapping_mul" | "unchecked_shl" | "unchecked_shr" | "rotate_left" diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index b84bc31ec2ae2..334d0cee9fbe7 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -379,9 +379,9 @@ fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { | "add_with_overflow" // ~> .overflowing_add | "sub_with_overflow" // ~> .overflowing_sub | "mul_with_overflow" // ~> .overflowing_mul - | "overflowing_add" // ~> .wrapping_add - | "overflowing_sub" // ~> .wrapping_sub - | "overflowing_mul" // ~> .wrapping_mul + | "wrapping_add" // ~> .wrapping_add + | "wrapping_sub" // ~> .wrapping_sub + | "wrapping_mul" // ~> .wrapping_mul | "saturating_add" // ~> .saturating_add | "saturating_sub" // ~> .saturating_sub | "unchecked_shl" // ~> .wrapping_shl diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 8bb24eef5e94c..dfbf8bcd0f60f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -67,7 +67,7 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { match intrinsic { "size_of" | "min_align_of" | "needs_drop" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | - "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "wrapping_add" | "wrapping_sub" | "wrapping_mul" | "saturating_add" | "saturating_sub" | "rotate_left" | "rotate_right" | "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" | @@ -314,7 +314,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { (1, vec![param(0), param(0)], param(0)), "unchecked_add" | "unchecked_sub" | "unchecked_mul" => (1, vec![param(0), param(0)], param(0)), - "overflowing_add" | "overflowing_sub" | "overflowing_mul" => + "wrapping_add" | "wrapping_sub" | "wrapping_mul" => (1, vec![param(0), param(0)], param(0)), "saturating_add" | "saturating_sub" => (1, vec![param(0), param(0)], param(0)), From 892ef6fa48bd20c037351e0cf8ea12c4c429a868 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 16 Aug 2019 20:12:10 +0300 Subject: [PATCH 12/18] rustbuild: work around the stdarch cfg(bootstrap) bug. --- src/bootstrap/bin/rustc.rs | 9 +++++++-- src/libcore/intrinsics.rs | 12 ++++++------ src/libcore/num/mod.rs | 24 ++++++++++++------------ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 9c01de8aa8251..d7887f74cc1c0 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -102,8 +102,13 @@ fn main() { // FIXME: the fact that core here is excluded is due to core_arch from our stdarch submodule // being broken on the beta compiler with bootstrap passed, so this is a temporary workaround // (we've just snapped, so there are no cfg(bootstrap) related annotations in core). - if stage == "0" && crate_name != Some("core") { - cmd.arg("--cfg").arg("bootstrap"); + if stage == "0" { + if crate_name != Some("core") { + cmd.arg("--cfg").arg("bootstrap"); + } else { + // NOTE(eddyb) see FIXME above, except now we need annotations again in core. + cmd.arg("--cfg").arg("boostrap_stdarch_ignore_this"); + } } // Print backtrace in case of ICE diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 995ee56440ea5..d145f2212f93a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1293,38 +1293,38 @@ extern "rust-intrinsic" { /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) - #[cfg(bootstrap)] + #[cfg(boostrap_stdarch_ignore_this)] pub fn overflowing_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) - #[cfg(bootstrap)] + #[cfg(boostrap_stdarch_ignore_this)] pub fn overflowing_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) - #[cfg(bootstrap)] + #[cfg(boostrap_stdarch_ignore_this)] pub fn overflowing_mul(a: T, b: T) -> T; /// Returns (a + b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) - #[cfg(not(bootstrap))] + #[cfg(not(boostrap_stdarch_ignore_this))] pub fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) - #[cfg(not(bootstrap))] + #[cfg(not(boostrap_stdarch_ignore_this))] pub fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) - #[cfg(not(bootstrap))] + #[cfg(not(boostrap_stdarch_ignore_this))] pub fn wrapping_mul(a: T, b: T) -> T; /// Computes `a + b`, while saturating at numeric bounds. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f82d94153e846..b46e06f8d8ada 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1112,11 +1112,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_add(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_add(self, rhs) } } @@ -1141,11 +1141,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_sub(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_sub(self, rhs) } } @@ -1169,11 +1169,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_mul(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_mul(self, rhs) } } @@ -3049,11 +3049,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_add(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_add(self, rhs) } } @@ -3077,11 +3077,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_sub(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_sub(self, rhs) } } @@ -3106,11 +3106,11 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - #[cfg(bootstrap)] { + #[cfg(boostrap_stdarch_ignore_this)] { intrinsics::overflowing_mul(self, rhs) } - #[cfg(not(bootstrap))] { + #[cfg(not(boostrap_stdarch_ignore_this))] { intrinsics::wrapping_mul(self, rhs) } } From 4087fc583e543f2801bf2e8c3b8051b31d26a078 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 05:44:32 +0200 Subject: [PATCH 13/18] Feature gate 'yield ?' pre-expansion. --- src/libsyntax/feature_gate.rs | 12 ++++++----- src/libsyntax/parse/mod.rs | 3 +++ src/libsyntax/parse/parser/expr.rs | 3 +++ .../feature-gates/feature-gate-generators.rs | 6 ++++++ .../feature-gate-generators.stderr | 20 ++++++++++++++++++- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8a56ae13b6f6e..9d1920dc410a6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2088,11 +2088,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "type ascription is experimental"); } } - ast::ExprKind::Yield(..) => { - gate_feature_post!(&self, generators, - e.span, - "yield syntax is experimental"); - } ast::ExprKind::TryBlock(_) => { gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); } @@ -2464,6 +2459,13 @@ pub fn check_crate(krate: &ast::Crate, "async closures are unstable" )); + for_each_in_lock(&sess.yield_spans, |span| gate_feature!( + &ctx, + generators, + *span, + "yield syntax is experimental" + )); + let visitor = &mut PostExpansionVisitor { context: &ctx, builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 26f78b9c5c784..9088f929372c9 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -63,6 +63,8 @@ pub struct ParseSess { pub let_chains_spans: Lock>, // Places where `async || ..` exprs were used and should be feature gated. pub async_closure_spans: Lock>, + // Places where `yield e?` exprs were used and should be feature gated. + pub yield_spans: Lock>, pub injected_crate_name: Once, } @@ -92,6 +94,7 @@ impl ParseSess { param_attr_spans: Lock::new(Vec::new()), let_chains_spans: Lock::new(Vec::new()), async_closure_spans: Lock::new(Vec::new()), + yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), } } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index f4b6a926734fb..ccc6bd1506709 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -997,6 +997,9 @@ impl<'a> Parser<'a> { } else { ex = ExprKind::Yield(None); } + + let span = lo.to(hi); + self.sess.yield_spans.borrow_mut().push(span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { diff --git a/src/test/ui/feature-gates/feature-gate-generators.rs b/src/test/ui/feature-gates/feature-gate-generators.rs index cee930fd785b9..382d891feed84 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.rs +++ b/src/test/ui/feature-gates/feature-gate-generators.rs @@ -2,3 +2,9 @@ fn main() { yield true; //~ ERROR yield syntax is experimental //~^ ERROR yield statement outside of generator literal } + +#[cfg(FALSE)] +fn foo() { + yield; //~ ERROR yield syntax is experimental + yield 0; //~ ERROR yield syntax is experimental +} diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index cdb056012542b..24b814b410c9d 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -7,12 +7,30 @@ LL | yield true; = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add `#![feature(generators)]` to the crate attributes to enable +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:8:5 + | +LL | yield; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + +error[E0658]: yield syntax is experimental + --> $DIR/feature-gate-generators.rs:9:5 + | +LL | yield 0; + | ^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 + = help: add `#![feature(generators)]` to the crate attributes to enable + error[E0627]: yield statement outside of generator literal --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. From 20661f18df695058224427fb84d21a0eeec8c657 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 14 Aug 2019 06:09:11 +0200 Subject: [PATCH 14/18] Simplify pre-expansion gating in general. --- src/libsyntax/feature_gate.rs | 42 +++++++++-------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d1920dc410a6..1a87a903156d2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,6 @@ use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; @@ -2422,10 +2421,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], features } -fn for_each_in_lock(vec: &Lock>, f: impl Fn(&T)) { - vec.borrow().iter().for_each(f); -} - pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, @@ -2438,33 +2433,16 @@ pub fn check_crate(krate: &ast::Crate, plugin_attributes, }; - for_each_in_lock(&sess.param_attr_spans, |span| gate_feature!( - &ctx, - param_attrs, - *span, - "attributes on function parameters are unstable" - )); - - for_each_in_lock(&sess.let_chains_spans, |span| gate_feature!( - &ctx, - let_chains, - *span, - "`let` expressions in this position are experimental" - )); - - for_each_in_lock(&sess.async_closure_spans, |span| gate_feature!( - &ctx, - async_closure, - *span, - "async closures are unstable" - )); - - for_each_in_lock(&sess.yield_spans, |span| gate_feature!( - &ctx, - generators, - *span, - "yield syntax is experimental" - )); + macro_rules! gate_all { + ($spans:ident, $gate:ident, $msg:literal) => { + for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); } + } + } + + gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable"); + gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure_spans, async_closure, "async closures are unstable"); + gate_all!(yield_spans, generators, "yield syntax is experimental"); let visitor = &mut PostExpansionVisitor { context: &ctx, From ea81d8cedb68076cb194204f86a0ffb1204be8f9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 29 Jul 2019 21:19:50 +0300 Subject: [PATCH 15/18] resolve: Populate external modules in more automatic and lazy way The modules are now populated implicitly on the first access --- src/librustc_resolve/build_reduced_graph.rs | 29 +++++----------- src/librustc_resolve/diagnostics.rs | 27 +++++++-------- src/librustc_resolve/late.rs | 2 +- src/librustc_resolve/late/diagnostics.rs | 14 +++----- src/librustc_resolve/lib.rs | 38 +++++++++++++-------- src/librustc_resolve/resolve_imports.rs | 34 +++++++++++------- 6 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 539e4a301e012..852353b7c1f01 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -159,19 +159,6 @@ impl<'a> Resolver<'a> { Some(ext) } - /// Ensures that the reduced graph rooted at the given external module - /// is built, building it if it is not. - crate fn populate_module_if_necessary(&mut self, module: Module<'a>) { - if module.populated.get() { return } - let def_id = module.def_id().unwrap(); - for child in self.cstore.item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); - BuildReducedGraphVisitor { parent_scope: ParentScope::module(module), r: self } - .build_reduced_graph_for_external_crate_res(child); - } - module.populated.set(true) - } - crate fn build_reduced_graph( &mut self, fragment: &AstFragment, parent_scope: ParentScope<'a> ) -> LegacyScope<'a> { @@ -186,6 +173,10 @@ struct BuildReducedGraphVisitor<'a, 'b> { parent_scope: ParentScope<'a>, } +impl<'a> AsMut> for BuildReducedGraphVisitor<'a, '_> { + fn as_mut(&mut self) -> &mut Resolver<'a> { self.r } +} + impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { let parent_scope = &self.parent_scope; @@ -603,8 +594,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) }; - self.r.populate_module_if_necessary(module); - let used = self.process_legacy_macro_imports(item, module); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); @@ -922,6 +911,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { span); self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); + module.populate_on_access.set(false); for child in self.r.cstore.item_children_untracked(def_id, self.r.session) { let res = child.res.map_id(|_| panic!("unexpected id")); let ns = if let Res::Def(DefKind::AssocTy, _) = res { @@ -935,7 +925,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.has_self.insert(res.def_id()); } } - module.populated.set(true); } Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); @@ -952,7 +941,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } fn legacy_import_macro(&mut self, - name: Name, + name: ast::Name, binding: &'a NameBinding<'a>, span: Span, allow_shadowing: bool) { @@ -1021,9 +1010,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if let Some(span) = import_all { let directive = macro_use_directive(self, span); self.r.potentially_unused_imports.push(directive); - module.for_each_child(|ident, ns, binding| if ns == MacroNS { - let imported_binding = self.r.import(binding, directive); - self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); + module.for_each_child(self, |this, ident, ns, binding| if ns == MacroNS { + let imported_binding = this.r.import(binding, directive); + this.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); }); } else { for ident in single_imports.iter().cloned() { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 861b0fd44ac41..80d1322ff3176 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -73,10 +73,13 @@ crate fn add_typo_suggestion( false } -crate fn add_module_candidates( - module: Module<'_>, names: &mut Vec, filter_fn: &impl Fn(Res) -> bool +crate fn add_module_candidates<'a>( + resolver: &mut Resolver<'a>, + module: Module<'a>, + names: &mut Vec, + filter_fn: &impl Fn(Res) -> bool, ) { - for (&(ident, _), resolution) in module.resolutions.borrow().iter() { + for (&(ident, _), resolution) in resolver.resolutions(module).borrow().iter() { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); if filter_fn(res) { @@ -402,10 +405,10 @@ impl<'a> Resolver<'a> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - add_module_candidates(root_module, &mut suggestions, filter_fn); + add_module_candidates(this, root_module, &mut suggestions, filter_fn); } Scope::Module(module) => { - add_module_candidates(module, &mut suggestions, filter_fn); + add_module_candidates(this, module, &mut suggestions, filter_fn); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| { @@ -453,7 +456,7 @@ impl<'a> Resolver<'a> { Scope::StdLibPrelude => { if let Some(prelude) = this.prelude { let mut tmp_suggestions = Vec::new(); - add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); + add_module_candidates(this, prelude, &mut tmp_suggestions, filter_fn); suggestions.extend(tmp_suggestions.into_iter().filter(|s| { use_prelude || this.is_builtin_macro(s.res) })); @@ -509,11 +512,9 @@ impl<'a> Resolver<'a> { while let Some((in_module, path_segments, in_module_is_extern)) = worklist.pop() { - self.populate_module_if_necessary(in_module); - // We have to visit module children in deterministic order to avoid // instabilities in reported imports (#43552). - in_module.for_each_child_stable(|ident, ns, name_binding| { + in_module.for_each_child_stable(self, |this, ident, ns, name_binding| { // avoid imports entirely if name_binding.is_import() && !name_binding.is_extern_crate() { return; } // avoid non-importable candidates as well @@ -547,7 +548,7 @@ impl<'a> Resolver<'a> { // outside crate private modules => no need to check this) if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { let did = match res { - Res::Def(DefKind::Ctor(..), did) => self.parent(did), + Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), }; candidates.push(ImportSuggestion { did, path }); @@ -607,8 +608,6 @@ impl<'a> Resolver<'a> { krate: crate_id, index: CRATE_DEF_INDEX, }); - self.populate_module_if_necessary(&crate_root); - suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, crate_root, ident, &filter_fn)); } @@ -805,7 +804,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// at the root of the crate instead of the module where it is defined /// ``` pub(crate) fn check_for_module_export_macro( - &self, + &mut self, directive: &'b ImportDirective<'b>, module: ModuleOrUniformRoot<'b>, ident: Ident, @@ -826,7 +825,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return None; } - let resolutions = crate_module.resolutions.borrow(); + let resolutions = self.r.resolutions(crate_module).borrow(); let resolution = resolutions.get(&(ident, MacroNS))?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index ffdfd85002bca..d8bd86699b7af 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1929,7 +1929,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { let mut traits = module.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - module.for_each_child(|name, ns, binding| { + module.for_each_child(self.r, |_, name, ns, binding| { if ns != TypeNS { return } match binding.res() { Res::Def(DefKind::Trait, _) | diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 68f9c1684d6fb..960bde3180915 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -548,7 +548,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { // Items in scope if let RibKind::ModuleRibKind(module) = rib.kind { // Items from this module - add_module_candidates(module, &mut names, &filter_fn); + add_module_candidates(self.r, module, &mut names, &filter_fn); if let ModuleKind::Block(..) = module.kind { // We can see through blocks @@ -577,7 +577,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { })); if let Some(prelude) = self.r.prelude { - add_module_candidates(prelude, &mut names, &filter_fn); + add_module_candidates(self.r, prelude, &mut names, &filter_fn); } } break; @@ -599,7 +599,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { mod_path, Some(TypeNS), false, span, CrateLint::No ) { if let ModuleOrUniformRoot::Module(module) = module { - add_module_candidates(module, &mut names, &filter_fn); + add_module_candidates(self.r, module, &mut names, &filter_fn); } } } @@ -717,9 +717,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { // abort if the module is already found if result.is_some() { break; } - self.r.populate_module_if_necessary(in_module); - - in_module.for_each_child_stable(|ident, _, name_binding| { + in_module.for_each_child_stable(self.r, |_, ident, _, name_binding| { // abort if the module is already found or if name_binding is private external if result.is_some() || !name_binding.vis.is_visible_locally() { return @@ -750,10 +748,8 @@ impl<'a> LateResolutionVisitor<'a, '_> { fn collect_enum_variants(&mut self, def_id: DefId) -> Option> { self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| { - self.r.populate_module_if_necessary(enum_module); - let mut variants = Vec::new(); - enum_module.for_each_child_stable(|ident, _, name_binding| { + enum_module.for_each_child_stable(self.r, |_, ident, _, name_binding| { if let Res::Def(DefKind::Variant, _) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); segms.push(ast::PathSegment::from_ident(ident)); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9b5eb51eb582d..bf51ba212ff07 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -431,6 +431,8 @@ impl ModuleKind { } } +type Resolutions<'a> = RefCell>>>; + /// One node in the tree of modules. pub struct ModuleData<'a> { parent: Option>, @@ -439,7 +441,11 @@ pub struct ModuleData<'a> { // The def id of the closest normal module (`mod`) ancestor (including this module). normal_ancestor_id: DefId, - resolutions: RefCell>>>, + // Mapping between names and their (possibly in-progress) resolutions in this module. + // Resolutions in modules from other crates are not populated until accessed. + lazy_resolutions: Resolutions<'a>, + // True if this is a module from other crate that needs to be populated on access. + populate_on_access: Cell, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -452,11 +458,6 @@ pub struct ModuleData<'a> { // Used to memoize the traits in this module for faster searches through all traits in scope. traits: RefCell)]>>>, - // Whether this module is populated. If not populated, any attempt to - // access the children must be preceded with a - // `populate_module_if_necessary` call. - populated: Cell, - /// Span of the module itself. Used for error reporting. span: Span, @@ -475,30 +476,34 @@ impl<'a> ModuleData<'a> { parent, kind, normal_ancestor_id, - resolutions: Default::default(), + lazy_resolutions: Default::default(), + populate_on_access: Cell::new(!normal_ancestor_id.is_local()), unresolved_invocations: Default::default(), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new(Vec::new()), traits: RefCell::new(None), - populated: Cell::new(normal_ancestor_id.is_local()), span, expansion, } } - fn for_each_child)>(&self, mut f: F) { - for (&(ident, ns), name_resolution) in self.resolutions.borrow().iter() { - name_resolution.borrow().binding.map(|binding| f(ident, ns, binding)); + fn for_each_child(&'a self, resolver: &mut R, mut f: F) + where R: AsMut>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>) + { + for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { + name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding)); } } - fn for_each_child_stable)>(&self, mut f: F) { - let resolutions = self.resolutions.borrow(); + fn for_each_child_stable(&'a self, resolver: &mut R, mut f: F) + where R: AsMut>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>) + { + let resolutions = resolver.as_mut().resolutions(self).borrow(); let mut resolutions = resolutions.iter().collect::>(); resolutions.sort_by_cached_key(|&(&(ident, ns), _)| (ident.as_str(), ns)); for &(&(ident, ns), &resolution) in resolutions.iter() { - resolution.borrow().binding.map(|binding| f(ident, ns, binding)); + resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding)); } } @@ -983,6 +988,10 @@ impl<'a> ResolverArenas<'a> { } } +impl<'a> AsMut> for Resolver<'a> { + fn as_mut(&mut self) -> &mut Resolver<'a> { self } +} + impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> { fn parent(self, id: DefId) -> Option { match id.krate { @@ -2634,7 +2643,6 @@ impl<'a> Resolver<'a> { return None; }; let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); - self.populate_module_if_necessary(&crate_root); Some((crate_root, ty::Visibility::Public, DUMMY_SP, ExpnId::root()) .to_name_binding(self.arenas)) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 693893e9ef13b..d68dbb78e9d00 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -7,9 +7,10 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use crate::{Resolver, ResolutionError, Segment}; +use crate::{Resolutions, Resolver, ResolutionError, Segment}; use crate::{names_to_string, module_to_string}; use crate::ModuleKind; +use crate::build_reduced_graph::BuildReducedGraphVisitor; use crate::diagnostics::Suggestion; use errors::Applicability; @@ -161,9 +162,22 @@ impl<'a> NameResolution<'a> { } impl<'a> Resolver<'a> { - crate fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) + crate fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { + if module.populate_on_access.get() { + module.populate_on_access.set(false); + let def_id = module.def_id().expect("unpopulated module without a def-id"); + for child in self.cstore.item_children_untracked(def_id, self.session) { + let child = child.map_id(|_| panic!("unexpected id")); + BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self } + .build_reduced_graph_for_external_crate_res(module, child); + } + } + &module.lazy_resolutions + } + + crate fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell> { - *module.resolutions.borrow_mut().entry((ident.modern(), ns)) + *self.resolutions(module).borrow_mut().entry((ident.modern(), ns)) .or_insert_with(|| self.arenas.alloc_name_resolution()) } @@ -242,8 +256,6 @@ impl<'a> Resolver<'a> { } }; - self.populate_module_if_necessary(module); - let resolution = self.resolution(module, ident, ns) .try_borrow_mut() .map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. @@ -1027,7 +1039,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return if all_ns_failed { let resolutions = match module { - ModuleOrUniformRoot::Module(module) => Some(module.resolutions.borrow()), + ModuleOrUniformRoot::Module(module) => Some(self.r.resolutions(module).borrow()), _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); @@ -1265,8 +1277,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } }; - self.r.populate_module_if_necessary(module); - if module.is_trait() { self.r.session.span_err(directive.span, "items in traits are not importable."); return; @@ -1282,7 +1292,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| { + let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(&ident, resolution)| { resolution.borrow().binding().map(|binding| (ident, binding)) }).collect::>(); for ((mut ident, ns), binding) in bindings { @@ -1310,7 +1320,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut reexports = Vec::new(); - for (&(ident, ns), resolution) in module.resolutions.borrow().iter() { + for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() { let resolution = &mut *resolution.borrow_mut(); let binding = match resolution.binding { Some(binding) => binding, @@ -1369,8 +1379,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Some(ModuleOrUniformRoot::Module(module)) => module, _ => bug!("module should exist"), }; - let resolutions = imported_module.parent.expect("parent should exist") - .resolutions.borrow(); + let parent_module = imported_module.parent.expect("parent should exist"); + let resolutions = self.r.resolutions(parent_module).borrow(); let enum_path_segment_index = directive.module_path.len() - 1; let enum_ident = directive.module_path[enum_path_segment_index].ident; From fe2524cb9cf09e7a0aa84bbb36a130e65255e1c0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 16 Aug 2019 01:15:36 +0300 Subject: [PATCH 16/18] resolve: Populate external traits lazily as well --- src/librustc_resolve/build_reduced_graph.rs | 31 ++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 852353b7c1f01..643a68d1e53de 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -870,7 +870,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene match res { Res::Def(kind @ DefKind::Mod, def_id) - | Res::Def(kind @ DefKind::Enum, def_id) => { + | Res::Def(kind @ DefKind::Enum, def_id) + | Res::Def(kind @ DefKind::Trait, def_id) => { let module = self.r.new_module(parent, ModuleKind::Def(kind, def_id, ident.name), def_id, @@ -883,6 +884,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | Res::Def(DefKind::ForeignTy, _) | Res::Def(DefKind::OpaqueTy, _) | Res::Def(DefKind::TraitAlias, _) + | Res::Def(DefKind::AssocTy, _) + | Res::Def(DefKind::AssocOpaqueTy, _) | Res::PrimTy(..) | Res::ToolMod => { self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); @@ -890,6 +893,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Fn, _) | Res::Def(DefKind::Static, _) | Res::Def(DefKind::Const, _) + | Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => { self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); } @@ -902,28 +906,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.struct_constructors.insert(struct_def_id, (res, vis)); } } - Res::Def(DefKind::Trait, def_id) => { - let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); - let module = self.r.new_module(parent, - module_kind, - parent.normal_ancestor_id, - expansion, - span); - self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Method, def_id) => { + self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); - module.populate_on_access.set(false); - for child in self.r.cstore.item_children_untracked(def_id, self.r.session) { - let res = child.res.map_id(|_| panic!("unexpected id")); - let ns = if let Res::Def(DefKind::AssocTy, _) = res { - TypeNS - } else { ValueNS }; - self.r.define(module, child.ident, ns, - (res, ty::Visibility::Public, DUMMY_SP, expansion)); - - if self.r.cstore.associated_item_cloned_untracked(child.res.def_id()) - .method_has_self_argument { - self.r.has_self.insert(res.def_id()); - } + if self.r.cstore.associated_item_cloned_untracked(def_id).method_has_self_argument { + self.r.has_self.insert(def_id); } } Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { From ab4cc2db56c0985ff5a0eb722898d8f45186d5aa Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 16 Aug 2019 01:18:14 +0300 Subject: [PATCH 17/18] resolve: Move some code around --- src/librustc_resolve/build_reduced_graph.rs | 54 ++++++++++----------- src/librustc_resolve/diagnostics.rs | 32 ++++++------ src/librustc_resolve/late/diagnostics.rs | 9 ++-- src/librustc_resolve/lib.rs | 20 ++++++++ src/librustc_resolve/resolve_imports.rs | 32 +++--------- 5 files changed, 73 insertions(+), 74 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 643a68d1e53de..9f4d35525a86a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -868,6 +868,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // This is only a guess, two equivalent idents may incorrectly get different gensyms here. let ident = ident.gensym_if_underscore(); let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene + // Record primary definitions. match res { Res::Def(kind @ DefKind::Mod, def_id) | Res::Def(kind @ DefKind::Enum, def_id) @@ -879,7 +880,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { span); self.r.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } - Res::Def(DefKind::Variant, _) + Res::Def(DefKind::Struct, _) + | Res::Def(DefKind::Union, _) + | Res::Def(DefKind::Variant, _) | Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::ForeignTy, _) | Res::Def(DefKind::OpaqueTy, _) @@ -887,43 +890,40 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | Res::Def(DefKind::AssocTy, _) | Res::Def(DefKind::AssocOpaqueTy, _) | Res::PrimTy(..) - | Res::ToolMod => { - self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); - } + | Res::ToolMod => + self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)), Res::Def(DefKind::Fn, _) + | Res::Def(DefKind::Method, _) | Res::Def(DefKind::Static, _) | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) - | Res::Def(DefKind::Ctor(CtorOf::Variant, ..), _) => { - self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); - } - Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { - self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); - - if let Some(struct_def_id) = - self.r.cstore.def_key(def_id).parent - .map(|index| DefId { krate: def_id.krate, index: index }) { - self.r.struct_constructors.insert(struct_def_id, (res, vis)); - } + | Res::Def(DefKind::Ctor(..), _) => + self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)), + Res::Def(DefKind::Macro(..), _) + | Res::NonMacroAttr(..) => + self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)), + Res::Def(DefKind::TyParam, _) | Res::Def(DefKind::ConstParam, _) + | Res::Local(..) | Res::SelfTy(..) | Res::SelfCtor(..) | Res::Err => + bug!("unexpected resolution: {:?}", res) + } + // Record some extra data for better diagnostics. + match res { + Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { + let field_names = self.r.cstore.struct_field_names_untracked(def_id); + self.insert_field_names(def_id, field_names); } Res::Def(DefKind::Method, def_id) => { - self.r.define(parent, ident, ValueNS, (res, vis, DUMMY_SP, expansion)); - if self.r.cstore.associated_item_cloned_untracked(def_id).method_has_self_argument { self.r.has_self.insert(def_id); } } - Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) => { - self.r.define(parent, ident, TypeNS, (res, vis, DUMMY_SP, expansion)); - - // Record field names for error reporting. - let field_names = self.r.cstore.struct_field_names_untracked(def_id); - self.insert_field_names(def_id, field_names); - } - Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.r.define(parent, ident, MacroNS, (res, vis, DUMMY_SP, expansion)); + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { + let parent = self.r.cstore.def_key(def_id).parent; + if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) { + self.r.struct_constructors.insert(struct_def_id, (res, vis)); + } } - _ => bug!("unexpected resolution: {:?}", res) + _ => {} } } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 80d1322ff3176..afdcec19d8ef6 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -73,23 +73,23 @@ crate fn add_typo_suggestion( false } -crate fn add_module_candidates<'a>( - resolver: &mut Resolver<'a>, - module: Module<'a>, - names: &mut Vec, - filter_fn: &impl Fn(Res) -> bool, -) { - for (&(ident, _), resolution) in resolver.resolutions(module).borrow().iter() { - if let Some(binding) = resolution.borrow().binding { - let res = binding.res(); - if filter_fn(res) { - names.push(TypoSuggestion::from_res(ident.name, res)); +impl<'a> Resolver<'a> { + crate fn add_module_candidates( + &mut self, + module: Module<'a>, + names: &mut Vec, + filter_fn: &impl Fn(Res) -> bool, + ) { + for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() { + if let Some(binding) = resolution.borrow().binding { + let res = binding.res(); + if filter_fn(res) { + names.push(TypoSuggestion::from_res(ident.name, res)); + } } } } -} -impl<'a> Resolver<'a> { /// Combines an error with provided span and emits it. /// /// This takes the error provided, combines it with the span and any additional spans inside the @@ -405,10 +405,10 @@ impl<'a> Resolver<'a> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - add_module_candidates(this, root_module, &mut suggestions, filter_fn); + this.add_module_candidates(root_module, &mut suggestions, filter_fn); } Scope::Module(module) => { - add_module_candidates(this, module, &mut suggestions, filter_fn); + this.add_module_candidates(module, &mut suggestions, filter_fn); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| { @@ -456,7 +456,7 @@ impl<'a> Resolver<'a> { Scope::StdLibPrelude => { if let Some(prelude) = this.prelude { let mut tmp_suggestions = Vec::new(); - add_module_candidates(this, prelude, &mut tmp_suggestions, filter_fn); + this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); suggestions.extend(tmp_suggestions.into_iter().filter(|s| { use_prelude || this.is_builtin_macro(s.res) })); diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 960bde3180915..a822fa049ca1c 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -1,8 +1,7 @@ use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; use crate::path_names_to_string; -use crate::diagnostics::{add_typo_suggestion, add_module_candidates}; -use crate::diagnostics::{ImportSuggestion, TypoSuggestion}; +use crate::diagnostics::{add_typo_suggestion, ImportSuggestion, TypoSuggestion}; use crate::late::{LateResolutionVisitor, RibKind}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; @@ -548,7 +547,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { // Items in scope if let RibKind::ModuleRibKind(module) = rib.kind { // Items from this module - add_module_candidates(self.r, module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn); if let ModuleKind::Block(..) = module.kind { // We can see through blocks @@ -577,7 +576,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { })); if let Some(prelude) = self.r.prelude { - add_module_candidates(self.r, prelude, &mut names, &filter_fn); + self.r.add_module_candidates(prelude, &mut names, &filter_fn); } } break; @@ -599,7 +598,7 @@ impl<'a> LateResolutionVisitor<'a, '_> { mod_path, Some(TypeNS), false, span, CrateLint::No ) { if let ModuleOrUniformRoot::Module(module) = module { - add_module_candidates(self.r, module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bf51ba212ff07..1c1448c9aa123 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -59,6 +59,7 @@ use std::collections::BTreeSet; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; +use build_reduced_graph::BuildReducedGraphVisitor; use diagnostics::{Suggestion, ImportSuggestion}; use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; use late::{PathSource, Rib, RibKind::*}; @@ -1257,6 +1258,25 @@ impl<'a> Resolver<'a> { self.arenas.alloc_module(module) } + fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { + if module.populate_on_access.get() { + module.populate_on_access.set(false); + let def_id = module.def_id().expect("unpopulated module without a def-id"); + for child in self.cstore.item_children_untracked(def_id, self.session) { + let child = child.map_id(|_| panic!("unexpected id")); + BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self } + .build_reduced_graph_for_external_crate_res(module, child); + } + } + &module.lazy_resolutions + } + + fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace) + -> &'a RefCell> { + *self.resolutions(module).borrow_mut().entry((ident.modern(), ns)) + .or_insert_with(|| self.arenas.alloc_name_resolution()) + } + fn record_use(&mut self, ident: Ident, ns: Namespace, used_binding: &'a NameBinding<'a>, is_lexical_scope: bool) { if let Some((b2, kind)) = used_binding.ambiguity { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index d68dbb78e9d00..b49f186870669 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -7,10 +7,8 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use crate::{Resolutions, Resolver, ResolutionError, Segment}; +use crate::{Resolver, ResolutionError, Segment, ModuleKind}; use crate::{names_to_string, module_to_string}; -use crate::ModuleKind; -use crate::build_reduced_graph::BuildReducedGraphVisitor; use crate::diagnostics::Suggestion; use errors::Applicability; @@ -38,7 +36,7 @@ use syntax_pos::{MultiSpan, Span}; use log::*; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::{mem, ptr}; type Res = def::Res; @@ -162,25 +160,6 @@ impl<'a> NameResolution<'a> { } impl<'a> Resolver<'a> { - crate fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { - if module.populate_on_access.get() { - module.populate_on_access.set(false); - let def_id = module.def_id().expect("unpopulated module without a def-id"); - for child in self.cstore.item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); - BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self } - .build_reduced_graph_for_external_crate_res(module, child); - } - } - &module.lazy_resolutions - } - - crate fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace) - -> &'a RefCell> { - *self.resolutions(module).borrow_mut().entry((ident.modern(), ns)) - .or_insert_with(|| self.arenas.alloc_name_resolution()) - } - crate fn resolve_ident_in_module_unadjusted( &mut self, module: ModuleOrUniformRoot<'a>, @@ -1039,7 +1018,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { return if all_ns_failed { let resolutions = match module { - ModuleOrUniformRoot::Module(module) => Some(self.r.resolutions(module).borrow()), + ModuleOrUniformRoot::Module(module) => + Some(self.r.resolutions(module).borrow()), _ => None, }; let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); @@ -1292,8 +1272,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(&ident, resolution)| { - resolution.borrow().binding().map(|binding| (ident, binding)) + let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| { + resolution.borrow().binding().map(|binding| (*ident, binding)) }).collect::>(); for ((mut ident, ns), binding) in bindings { let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) { From 5e47cd4a1784bd9d86a3f5a413d606e938679044 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 16 Aug 2019 21:19:43 +0300 Subject: [PATCH 18/18] Fix rebase Move some code into `build_reduced_graph.rs` to keep `BuildReducedGraphVisitor` it private Also move the def collector call to `build_reduced_graph.rs`, it belongs there. --- src/librustc_resolve/build_reduced_graph.rs | 11 +++++++++++ src/librustc_resolve/lib.rs | 8 +------- src/librustc_resolve/macros.rs | 2 -- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9f4d35525a86a..1510d74babb6d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -16,6 +16,7 @@ use crate::{ResolutionError, Determinacy, PathResult, CrateLint}; use rustc::bug; use rustc::hir::def::{self, *}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; +use rustc::hir::map::DefCollector; use rustc::ty; use rustc::middle::cstore::CrateStore; use rustc_metadata::cstore::LoadedMacro; @@ -162,10 +163,20 @@ impl<'a> Resolver<'a> { crate fn build_reduced_graph( &mut self, fragment: &AstFragment, parent_scope: ParentScope<'a> ) -> LegacyScope<'a> { + fragment.visit_with(&mut DefCollector::new(&mut self.definitions, parent_scope.expansion)); let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope }; fragment.visit_with(&mut visitor); visitor.parent_scope.legacy } + + crate fn build_reduced_graph_external(&mut self, module: Module<'a>) { + let def_id = module.def_id().expect("unpopulated module without a def-id"); + for child in self.cstore.item_children_untracked(def_id, self.session) { + let child = child.map_id(|_| panic!("unexpected id")); + BuildReducedGraphVisitor { r: self, parent_scope: ParentScope::module(module) } + .build_reduced_graph_for_external_crate_res(child); + } + } } struct BuildReducedGraphVisitor<'a, 'b> { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1c1448c9aa123..12c4f5bfe8e61 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -59,7 +59,6 @@ use std::collections::BTreeSet; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; -use build_reduced_graph::BuildReducedGraphVisitor; use diagnostics::{Suggestion, ImportSuggestion}; use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; use late::{PathSource, Rib, RibKind::*}; @@ -1261,12 +1260,7 @@ impl<'a> Resolver<'a> { fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { if module.populate_on_access.get() { module.populate_on_access.set(false); - let def_id = module.def_id().expect("unpopulated module without a def-id"); - for child in self.cstore.item_children_untracked(def_id, self.session) { - let child = child.map_id(|_| panic!("unexpected id")); - BuildReducedGraphVisitor { parent_scope: self.dummy_parent_scope(), r: self } - .build_reduced_graph_for_external_crate_res(module, child); - } + self.build_reduced_graph_external(module); } &module.lazy_resolutions } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 079145e816cd5..6f49377c187aa 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,6 @@ use crate::{ModuleOrUniformRoot, KNOWN_TOOLS}; use crate::Namespace::*; use crate::resolve_imports::ImportResolver; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; -use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; use syntax::ast::{self, Ident}; @@ -131,7 +130,6 @@ impl<'a> base::Resolver for Resolver<'a> { parent_scope.module.unresolved_invocations.borrow_mut().extend(derives); // Integrate the new AST fragment into all the definition and module structures. - fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expansion)); let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope); self.output_legacy_scopes.insert(expansion, output_legacy_scope); }