From 5fa97c35da2f0eeda4321da7fb5933490b798d79 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Tue, 6 Feb 2018 23:03:14 -0500 Subject: [PATCH 01/42] add tests for macro trailing commas --- src/test/compile-fail/macro-comma-behavior.rs | 101 +++++ src/test/compile-fail/macro-comma-support.rs | 20 + .../run-pass/auxiliary/macro-comma-support.rs | 11 + src/test/run-pass/macro-comma-behavior.rs | 98 +++++ src/test/run-pass/macro-comma-support.rs | 371 ++++++++++++++++++ 5 files changed, 601 insertions(+) create mode 100644 src/test/compile-fail/macro-comma-behavior.rs create mode 100644 src/test/compile-fail/macro-comma-support.rs create mode 100644 src/test/run-pass/auxiliary/macro-comma-support.rs create mode 100644 src/test/run-pass/macro-comma-behavior.rs create mode 100644 src/test/run-pass/macro-comma-support.rs diff --git a/src/test/compile-fail/macro-comma-behavior.rs b/src/test/compile-fail/macro-comma-behavior.rs new file mode 100644 index 0000000000000..620e57b463d1a --- /dev/null +++ b/src/test/compile-fail/macro-comma-behavior.rs @@ -0,0 +1,101 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Companion test to the similarly-named file in run-pass. + +// compile-flags: -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +// (see documentation of the similarly-named test in run-pass) +fn to_format_or_not_to_format() { + let falsum = || false; + + // assert!(true, "{}",); // see run-pass + + assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // debug_assert!(true, "{}",); // see run-pass + + debug_assert_eq!(1, 1, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + debug_assert_ne!(1, 2, "{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + #[cfg(std)] { + eprint!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // eprintln!("{}",); + // [std]~^ ERROR no arguments + } + + #[cfg(std)] { + format!("{}",); + //[std]~^ ERROR no arguments + } + + format_args!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { panic!("{}",); } // see run-pass + + #[cfg(std)] { + print!("{}",); + //[std]~^ ERROR no arguments + } + + #[cfg(std)] { + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // println!("{}",); + // [std]~^ ERROR no arguments + } + + unimplemented!("{}",); + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // if falsum() { unreachable!("{}",); } // see run-pass + + struct S; + impl fmt::Display for S { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}",)?; + //[core]~^ ERROR no arguments + //[std]~^^ ERROR no arguments + + // FIXME: compile-fail says "expected error not found" even though + // rustc does emit an error + // writeln!(f, "{}",)?; + // [core]~^ ERROR no arguments + // [std]~^^ ERROR no arguments + Ok(()) + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/macro-comma-support.rs b/src/test/compile-fail/macro-comma-support.rs new file mode 100644 index 0000000000000..e5fe9b4dd7f10 --- /dev/null +++ b/src/test/compile-fail/macro-comma-support.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a companion to the similarly-named test in run-pass. +// +// It tests macros that unavoidably produce compile errors. + +fn compile_error() { + compile_error!("lel"); //~ ERROR lel + compile_error!("lel",); //~ ERROR lel +} + +fn main() {} diff --git a/src/test/run-pass/auxiliary/macro-comma-support.rs b/src/test/run-pass/auxiliary/macro-comma-support.rs new file mode 100644 index 0000000000000..6eafd520a726b --- /dev/null +++ b/src/test/run-pass/auxiliary/macro-comma-support.rs @@ -0,0 +1,11 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +() diff --git a/src/test/run-pass/macro-comma-behavior.rs b/src/test/run-pass/macro-comma-behavior.rs new file mode 100644 index 0000000000000..f8065f0ff148b --- /dev/null +++ b/src/test/run-pass/macro-comma-behavior.rs @@ -0,0 +1,98 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ideally, any macro call with a trailing comma should behave +// identically to a call without the comma. +// +// This checks the behavior of macros with trailing commas in key +// places where regressions in behavior seem highly possible (due +// to it being e.g. a place where the addition of an argument +// causes it to go down a code path with subtly different behavior). +// +// There is a companion test in compile-fail. + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +// an easy mistake in the implementation of 'assert!' +// would cause this to say "explicit panic" +#[test] +#[should_panic(expected = "assertion failed")] +fn assert_1arg() { + assert!(false,); +} + +// same as 'assert_1arg' +#[test] +#[should_panic(expected = "assertion failed")] +fn debug_assert_1arg() { + debug_assert!(false,); +} + +// make sure we don't accidentally forward to `write!("text")` +#[cfg(std)] +#[test] +fn writeln_2arg() { + use fmt::Write; + + let mut s = String::new(); + writeln!(&mut s, "hi",).unwrap(); + assert_eq!(&s, "hi\n"); +} + +// A number of format_args-like macros have special-case treatment +// for a single message string, which is not formatted. +// +// This test ensures that the addition of a trailing comma does not +// suddenly cause these strings to get formatted when they otherwise +// would not be. This is an easy mistake to make by having such a macro +// accept ", $($tok:tt)*" instead of ", $($tok:tt)+" after its minimal +// set of arguments. +// +// (Example: Issue #48042) +#[test] +fn to_format_or_not_to_format() { + // ("{}" is the easiest string to test because if this gets + // sent to format_args!, it'll simply fail to compile. + // "{{}}" is an example of an input that could compile and + // produce an incorrect program, but testing the panics + // would be burdensome.) + let falsum = || false; + + assert!(true, "{}",); + + // assert_eq!(1, 1, "{}",); // see compile-fail + // assert_ne!(1, 2, "{}",); // see compile-fail + + debug_assert!(true, "{}",); + + // debug_assert_eq!(1, 1, "{}",); // see compile-fail + // debug_assert_ne!(1, 2, "{}",); // see compile-fail + // eprint!("{}",); // see compile-fail + // eprintln!("{}",); // see compile-fail + // format!("{}",); // see compile-fail + // format_args!("{}",); // see compile-fail + + if falsum() { panic!("{}",); } + + // print!("{}",); // see compile-fail + // println!("{}",); // see compile-fail + // unimplemented!("{}",); // see compile-fail + + if falsum() { unreachable!("{}",); } + + // write!(&mut stdout, "{}",); // see compile-fail + // writeln!(&mut stdout, "{}",); // see compile-fail +} diff --git a/src/test/run-pass/macro-comma-support.rs b/src/test/run-pass/macro-comma-support.rs new file mode 100644 index 0000000000000..f73dfb7b3b1d4 --- /dev/null +++ b/src/test/run-pass/macro-comma-support.rs @@ -0,0 +1,371 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a comprehensive test of invocations with and without +// trailing commas (or other, similar optionally-trailing separators). +// Every macro is accounted for, even those not tested in this file. +// (There will be a note indicating why). +// +// The expectation is for this to be updated as new macros are added, +// or as functionality is added to existing macros. +// +// (FIXME: (please discuss in PR) is the above expectation reasonable?) + +// std and core are both tested because they may contain separate +// implementations for some macro_rules! macros as an implementation +// detail. + +// compile-flags: --test -C debug_assertions=yes +// revisions: std core + +#![cfg_attr(core, no_std)] + +#![feature(concat_idents)] + +#[cfg(std)] use std::fmt; +#[cfg(core)] use core::fmt; + +#[test] +fn assert() { + assert!(true); + assert!(true,); + assert!(true, "hello"); + assert!(true, "hello",); + assert!(true, "hello {}", "world"); + assert!(true, "hello {}", "world",); +} + +#[test] +fn assert_eq() { + assert_eq!(1, 1); + assert_eq!(1, 1,); + assert_eq!(1, 1, "hello"); + assert_eq!(1, 1, "hello",); + assert_eq!(1, 1, "hello {}", "world"); + assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn assert_ne() { + assert_ne!(1, 2); + assert_ne!(1, 2,); + assert_ne!(1, 2, "hello"); + assert_ne!(1, 2, "hello",); + assert_ne!(1, 2, "hello {}", "world"); + assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn cfg() { + let _ = cfg!(pants); + let _ = cfg!(pants,); + let _ = cfg!(pants = "pants"); + let _ = cfg!(pants = "pants",); + let _ = cfg!(all(pants)); + let _ = cfg!(all(pants),); + let _ = cfg!(all(pants,)); + let _ = cfg!(all(pants,),); +} + +#[test] +fn column() { + let _ = column!(); +} + +// compile_error! is in a companion to this test in compile-fail + +#[test] +fn concat() { + let _ = concat!(); + let _ = concat!("hello"); + let _ = concat!("hello",); + let _ = concat!("hello", " world"); + let _ = concat!("hello", " world",); +} + +#[test] +fn concat_idents() { + fn foo() {} + fn foobar() {} + + concat_idents!(foo)(); + concat_idents!(foo,)(); + concat_idents!(foo, bar)(); + concat_idents!(foo, bar,)(); +} + +#[test] +fn debug_assert() { + debug_assert!(true); + debug_assert!(true, ); + debug_assert!(true, "hello"); + debug_assert!(true, "hello",); + debug_assert!(true, "hello {}", "world"); + debug_assert!(true, "hello {}", "world",); +} + +#[test] +fn debug_assert_eq() { + debug_assert_eq!(1, 1); + debug_assert_eq!(1, 1,); + debug_assert_eq!(1, 1, "hello"); + debug_assert_eq!(1, 1, "hello",); + debug_assert_eq!(1, 1, "hello {}", "world"); + debug_assert_eq!(1, 1, "hello {}", "world",); +} + +#[test] +fn debug_assert_ne() { + debug_assert_ne!(1, 2); + debug_assert_ne!(1, 2,); + debug_assert_ne!(1, 2, "hello"); + debug_assert_ne!(1, 2, "hello",); + debug_assert_ne!(1, 2, "hello {}", "world"); + debug_assert_ne!(1, 2, "hello {}", "world",); +} + +#[test] +fn env() { + let _ = env!("PATH"); + let _ = env!("PATH",); + let _ = env!("PATH", "not found"); + let _ = env!("PATH", "not found",); +} + +#[cfg(std)] +#[test] +fn eprint() { + eprint!("hello"); + eprint!("hello",); + eprint!("hello {}", "world"); + eprint!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn eprintln() { + eprintln!(); + eprintln!("hello"); + eprintln!("hello",); + eprintln!("hello {}", "world"); + eprintln!("hello {}", "world",); +} + +#[test] +fn file() { + let _ = file!(); +} + +#[cfg(std)] +#[test] +fn format() { + let _ = format!("hello"); + let _ = format!("hello",); + let _ = format!("hello {}", "world"); + let _ = format!("hello {}", "world",); +} + +#[test] +fn format_args() { + let _ = format_args!("hello"); + let _ = format_args!("hello",); + let _ = format_args!("hello {}", "world"); + let _ = format_args!("hello {}", "world",); +} + +#[test] +fn include() { + let _ = include!("auxiliary/macro-comma-support.rs"); + let _ = include!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_bytes() { + let _ = include_bytes!("auxiliary/macro-comma-support.rs"); + let _ = include_bytes!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn include_str() { + let _ = include_str!("auxiliary/macro-comma-support.rs"); + let _ = include_str!("auxiliary/macro-comma-support.rs",); +} + +#[test] +fn line() { + let _ = line!(); +} + +#[test] +fn module_path() { + let _ = module_path!(); +} + +#[test] +fn option_env() { + let _ = option_env!("PATH"); + let _ = option_env!("PATH",); +} + +#[test] +fn panic() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { panic!(); } + if falsum() { panic!("hello"); } + if falsum() { panic!("hello",); } + if falsum() { panic!("hello {}", "world"); } + if falsum() { panic!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn print() { + print!("hello"); + print!("hello",); + print!("hello {}", "world"); + print!("hello {}", "world",); +} + +#[cfg(std)] +#[test] +fn println() { + println!(); + println!("hello"); + println!("hello",); + println!("hello {}", "world"); + println!("hello {}", "world",); +} + +// FIXME: select! (please discuss in PR) +// +// Test cases for select! are obnoxiously large, see here: +// +// https://github.com/ExpHP/rust-macro-comma-test/blob/0062e75e01ab/src/main.rs#L190-L250 +// +// and due to other usability issues described there, it is unclear to me that it is +// going anywhere in its current state. This is a job far too big for a macro_rules! macro, +// and for as long as it exists in this form it will have many many problems far worse than +// just lack of trailing comma support. + +// stringify! is N/A + +#[cfg(std)] +#[test] +fn thread_local() { + // this has an optional trailing *semicolon* + thread_local! { + #[allow(unused)] pub static A: () = () + } + + thread_local! { + #[allow(unused)] pub static AA: () = (); + } + + thread_local! { + #[allow(unused)] pub static AAA: () = (); + #[allow(unused)] pub static AAAA: () = () + } + + thread_local! { + #[allow(unused)] pub static AAAAG: () = (); + #[allow(unused)] pub static AAAAGH: () = (); + } +} + +#[test] +fn try() { + fn inner() -> Result<(), ()> { + try!(Ok(())); + try!(Ok(()),); + Ok(()) + } + + inner().unwrap(); +} + +#[test] +fn unimplemented() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unimplemented!(); } + if falsum() { unimplemented!("hello"); } + if falsum() { unimplemented!("hello",); } + if falsum() { unimplemented!("hello {}", "world"); } + if falsum() { unimplemented!("hello {}", "world",); } +} + +#[test] +fn unreachable() { + // prevent 'unreachable code' warnings + let falsum = || false; + + if falsum() { unreachable!(); } + if falsum() { unreachable!("hello"); } + if falsum() { unreachable!("hello",); } + if falsum() { unreachable!("hello {}", "world"); } + if falsum() { unreachable!("hello {}", "world",); } +} + +#[cfg(std)] +#[test] +fn vec() { + let _: Vec<()> = vec![]; + let _ = vec![0]; + let _ = vec![0,]; + let _ = vec![0, 1]; + let _ = vec![0, 1,]; +} + +// give a test body access to a fmt::Formatter, which seems +// to be the easiest way to use 'write!' on core. +macro_rules! test_with_formatter { + ( + #[test] + fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block + ) => { + #[test] + fn $fname() { + struct Struct; + impl fmt::Display for Struct { + fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result { + Ok($block) + } + } + + // suppress "unused" + assert!(true, "{}", Struct); + } + }; +} + +test_with_formatter! { + #[test] + fn write(f: &mut fmt::Formatter) { + let _ = write!(f, "hello"); + let _ = write!(f, "hello",); + let _ = write!(f, "hello {}", "world"); + let _ = write!(f, "hello {}", "world",); + } +} + +test_with_formatter! { + #[test] + fn writeln(f: &mut fmt::Formatter) { + let _ = writeln!(f); + let _ = writeln!(f,); + let _ = writeln!(f, "hello"); + let _ = writeln!(f, "hello",); + let _ = writeln!(f, "hello {}", "world"); + let _ = writeln!(f, "hello {}", "world",); + } +} From 96eed862a08f0ee1d234f4f83419dd46fe58ccef Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:31:22 -0500 Subject: [PATCH 02/42] libcore/libstd: fix commas in macro_rules! macros BREAKING CHANGE: (or perhaps, *bugfix*) In #![no_std] applications, the following calls to `panic!` used to behave differently; they now behave the same. Old behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{" New behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{{" This only affects calls to `panic!` (and by proxy `assert` and `debug_assert`) with a single string literal followed by a trailing comma, and only in `#![no_std]` applications. --- src/libcore/macros.rs | 17 +++++++++++++++-- src/libstd/macros.rs | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f00128a8147de..c12edaf0b29a0 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -19,7 +19,10 @@ macro_rules! panic { ($msg:expr) => ({ $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) }); - ($fmt:expr, $($arg:tt)*) => ({ + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &(file!(), line!(), __rust_unstable_column!())) }); @@ -79,6 +82,9 @@ macro_rules! assert { panic!(concat!("assertion failed: ", stringify!($cond))) } ); + ($cond:expr,) => ( + assert!($cond) + ); ($cond:expr, $($arg:tt)+) => ( if !$cond { panic!($($arg)+) @@ -359,7 +365,8 @@ macro_rules! try { $crate::result::Result::Err(err) => { return $crate::result::Result::Err($crate::convert::From::from(err)) } - }) + }); + ($expr:expr,) => (try!($expr)); } /// Write formatted data into a buffer. @@ -456,6 +463,9 @@ macro_rules! writeln { ($dst:expr) => ( write!($dst, "\n") ); + ($dst:expr,) => ( + writeln!($dst) + ); ($dst:expr, $fmt:expr) => ( write!($dst, concat!($fmt, "\n")) ); @@ -524,6 +534,9 @@ macro_rules! unreachable { ($msg:expr) => ({ unreachable!("{}", $msg) }); + ($msg:expr,) => ({ + unreachable!($msg) + }); ($fmt:expr, $($arg:tt)*) => ({ panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f058b1caef509..5a01674a3d0a0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,9 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); + ($msg:expr,) => ({ + panic!($msg) + }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) From 1137fb193583971f35e1d4b3cfcb25725948da4f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:32:26 -0500 Subject: [PATCH 03/42] libsyntax/ext: trailing commas in builtin macros Most notably this changes 'syntax::ext::base::get_single_str_from_tts' to accept a trailing comma, and revises the documentation so that this aspect is not surprising. I made this change under the understanding that this crate is private rustc implementation detail (I hope this is correct!). After reviewing all call sites, I believe the revised semantics are closer to the intended spirit of the function. --- src/libsyntax/ext/base.rs | 6 ++++-- src/libsyntax_ext/cfg.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 025aa94ce06f5..520ec942e4288 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -890,8 +890,8 @@ pub fn check_zero_tts(cx: &ExtCtxt, } } -/// Extract the string literal from the first token of `tts`. If this -/// is not a string literal, emit an error and return None. +/// Interpreting `tts` as a comma-separated sequence of expressions, +/// expect exactly one string literal, or emit an error and return None. pub fn get_single_str_from_tts(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree], @@ -903,6 +903,8 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt, return None } let ret = panictry!(p.parse_expr()); + let _ = p.eat(&token::Comma); + if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 1d8dc4064685b..1eeba9b30b8e2 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -28,6 +28,8 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, let mut p = cx.new_parser_from_tts(tts); let cfg = panictry!(p.parse_meta_item()); + let _ = p.eat(&token::Comma); + if !p.eat(&token::Eof) { cx.span_err(sp, "expected 1 cfg-pattern"); return DummyResult::expr(sp); From b7c6dc6c0600eaee4d149c63dd3cf1faa00a098f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 10:24:34 -0500 Subject: [PATCH 04/42] update the builtin macro doc stubs --- src/libcore/macros.rs | 25 ++++++++++++++++++++----- src/libstd/macros.rs | 25 ++++++++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c12edaf0b29a0..19bbf85cadb7c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -616,7 +616,10 @@ mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] #[cfg(dox)] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -652,7 +655,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -728,7 +734,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -738,7 +747,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -768,5 +780,8 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5a01674a3d0a0..a18c811d19634 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -315,7 +315,10 @@ pub mod builtin { /// ``` #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -403,7 +406,10 @@ pub mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -583,7 +589,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiรณs". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -617,7 +626,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiรณs". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -703,7 +715,10 @@ pub mod builtin { /// "๐Ÿ™ˆ๐Ÿ™Š๐Ÿ™‰๐Ÿ™ˆ๐Ÿ™Š๐Ÿ™‰". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. From ae46434b7936d1f1d71cb92c45ddcf936ec0eb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 3 Feb 2018 21:15:00 +0100 Subject: [PATCH 05/42] Remove "static item recursion checking" in favor of relying on cycle checks in the query engine --- src/librustc_driver/driver.rs | 6 +- src/librustc_passes/diagnostics.rs | 16 - src/librustc_passes/lib.rs | 1 - src/librustc_passes/static_recursion.rs | 280 ------------------ src/test/compile-fail/issue-17252.rs | 4 +- .../ui/{issue-23302.rs => issue-23302-1.rs} | 13 +- src/test/ui/issue-23302-1.stderr | 15 + .../issue-23302-2.rs} | 12 +- src/test/ui/issue-23302-2.stderr | 15 + .../issue-23302-3.rs} | 10 +- src/test/ui/issue-23302-3.stderr | 20 ++ src/test/ui/issue-23302.stderr | 26 -- src/test/ui/issue-36163.rs | 10 +- src/test/ui/issue-36163.stderr | 30 +- 14 files changed, 84 insertions(+), 374 deletions(-) delete mode 100644 src/librustc_passes/static_recursion.rs rename src/test/ui/{issue-23302.rs => issue-23302-1.rs} (71%) create mode 100644 src/test/ui/issue-23302-1.stderr rename src/test/{compile-fail/issue-17718-recursive.rs => ui/issue-23302-2.rs} (64%) create mode 100644 src/test/ui/issue-23302-2.stderr rename src/test/{compile-fail/const-recursive.rs => ui/issue-23302-3.rs} (69%) create mode 100644 src/test/ui/issue-23302-3.stderr delete mode 100644 src/test/ui/issue-23302.stderr diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 50c19b5a99a54..0c0c946cd4c51 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -36,7 +36,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats}; +use rustc_passes::{self, ast_validation, loops, consts, hir_stats}; use rustc_const_eval::{self, check_match}; use super::Compilation; @@ -972,10 +972,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, "loop checking", || loops::check_crate(sess, &hir_map)); - time(time_passes, - "static item recursion checking", - || static_recursion::check_crate(sess, &hir_map))?; - let mut local_providers = ty::maps::Providers::default(); default_provide(&mut local_providers); trans.provide(&mut local_providers); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..8a19615c1adcb 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -128,22 +128,6 @@ impl !Enterprise for Foo { } Please note that negative impls are only allowed for auto traits. "##, -E0265: r##" -This error indicates that a static or constant references itself. -All statics and constants need to resolve to a value in an acyclic manner. - -For example, neither of the following can be sensibly compiled: - -```compile_fail,E0265 -const X: u32 = X; -``` - -```compile_fail,E0265 -const X: u32 = Y; -const Y: u32 = X; -``` -"##, - E0267: r##" This error indicates the use of a loop keyword (`break` or `continue`) inside a closure but outside of any loop. Erroneous code example: diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 73c71ec0b2f00..bfcf68908bc8c 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -42,7 +42,6 @@ pub mod consts; pub mod hir_stats; pub mod loops; mod mir_stats; -pub mod static_recursion; #[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs deleted file mode 100644 index 987243b523473..0000000000000 --- a/src/librustc_passes/static_recursion.rs +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This compiler pass detects constants that refer to themselves -// recursively. - -use rustc::hir::map as hir_map; -use rustc::session::Session; -use rustc::hir::def::{Def, CtorKind}; -use rustc::util::common::ErrorReported; -use rustc::util::nodemap::{NodeMap, NodeSet}; - -use syntax::ast; -use syntax_pos::Span; -use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; -use rustc::hir; - -struct CheckCrateVisitor<'a, 'hir: 'a> { - sess: &'a Session, - hir_map: &'a hir_map::Map<'hir>, - // `discriminant_map` is a cache that associates the `NodeId`s of local - // variant definitions with the discriminant expression that applies to - // each one. If the variant uses the default values (starting from `0`), - // then `None` is stored. - discriminant_map: NodeMap>, - detected_recursive_ids: NodeSet, -} - -impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { - NestedVisitorMap::None - } - - fn visit_item(&mut self, it: &'hir hir::Item) { - match it.node { - hir::ItemStatic(..) | - hir::ItemConst(..) => { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_item(it); - } - hir::ItemEnum(ref enum_def, ref generics) => { - // We could process the whole enum, but handling the variants - // with discriminant expressions one by one gives more specific, - // less redundant output. - for variant in &enum_def.variants { - if let Some(_) = variant.node.disr_expr { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.populate_enum_discriminants(enum_def); - recursion_visitor.visit_variant(variant, generics, it.id); - } - } - } - _ => {} - } - intravisit::walk_item(self, it) - } - - fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) { - match ti.node { - hir::TraitItemKind::Const(_, ref default) => { - if let Some(_) = *default { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_trait_item(ti); - } - } - _ => {} - } - intravisit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) { - match ii.node { - hir::ImplItemKind::Const(..) => { - let mut recursion_visitor = CheckItemRecursionVisitor::new(self); - recursion_visitor.visit_impl_item(ii); - } - _ => {} - } - intravisit::walk_impl_item(self, ii) - } -} - -pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) - -> Result<(), ErrorReported> -{ - let mut visitor = CheckCrateVisitor { - sess, - hir_map, - discriminant_map: NodeMap(), - detected_recursive_ids: NodeSet(), - }; - sess.track_errors(|| { - // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like - hir_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); - }) -} - -struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> { - sess: &'b Session, - hir_map: &'b hir_map::Map<'hir>, - discriminant_map: &'a mut NodeMap>, - idstack: Vec, - detected_recursive_ids: &'a mut NodeSet, -} - -impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> { - fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self { - CheckItemRecursionVisitor { - sess: v.sess, - hir_map: v.hir_map, - discriminant_map: &mut v.discriminant_map, - idstack: Vec::new(), - detected_recursive_ids: &mut v.detected_recursive_ids, - } - } - fn with_item_id_pushed(&mut self, id: ast::NodeId, f: F, span: Span) - where F: Fn(&mut Self) - { - if self.idstack.iter().any(|&x| x == id) { - if self.detected_recursive_ids.contains(&id) { - return; - } - self.detected_recursive_ids.insert(id); - let any_static = self.idstack.iter().any(|&x| { - if let hir_map::NodeItem(item) = self.hir_map.get(x) { - if let hir::ItemStatic(..) = item.node { - true - } else { - false - } - } else { - false - } - }); - if !any_static { - struct_span_err!(self.sess, span, E0265, "recursive constant") - .span_label(span, "recursion not allowed in constant") - .emit(); - } - return; - } - self.idstack.push(id); - f(self); - self.idstack.pop(); - } - // If a variant has an expression specifying its discriminant, then it needs - // to be checked just like a static or constant. However, if there are more - // variants with no explicitly specified discriminant, those variants will - // increment the same expression to get their values. - // - // So for every variant, we need to track whether there is an expression - // somewhere in the enum definition that controls its discriminant. We do - // this by starting from the end and searching backward. - fn populate_enum_discriminants(&mut self, enum_definition: &'hir hir::EnumDef) { - // Get the map, and return if we already processed this enum or if it - // has no variants. - match enum_definition.variants.first() { - None => { - return; - } - Some(variant) if self.discriminant_map.contains_key(&variant.node.data.id()) => { - return; - } - _ => {} - } - - // Go through all the variants. - let mut variant_stack: Vec = Vec::new(); - for variant in enum_definition.variants.iter().rev() { - variant_stack.push(variant.node.data.id()); - // When we find an expression, every variant currently on the stack - // is affected by that expression. - if let Some(expr) = variant.node.disr_expr { - for id in &variant_stack { - self.discriminant_map.insert(*id, Some(expr)); - } - variant_stack.clear() - } - } - // If we are at the top, that always starts at 0, so any variant on the - // stack has a default value and does not need to be checked. - for id in &variant_stack { - self.discriminant_map.insert(*id, None); - } - } -} - -impl<'a, 'b: 'a, 'hir: 'b> Visitor<'hir> for CheckItemRecursionVisitor<'a, 'b, 'hir> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { - NestedVisitorMap::OnlyBodies(&self.hir_map) - } - fn visit_item(&mut self, it: &'hir hir::Item) { - self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span); - } - - fn visit_enum_def(&mut self, - enum_definition: &'hir hir::EnumDef, - generics: &'hir hir::Generics, - item_id: ast::NodeId, - _: Span) { - self.populate_enum_discriminants(enum_definition); - intravisit::walk_enum_def(self, enum_definition, generics, item_id); - } - - fn visit_variant(&mut self, - variant: &'hir hir::Variant, - _: &'hir hir::Generics, - _: ast::NodeId) { - let variant_id = variant.node.data.id(); - let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| { - span_bug!(variant.span, - "`check_static_recursion` attempted to visit \ - variant with unknown discriminant") - }); - // If `maybe_expr` is `None`, that's because no discriminant is - // specified that affects this variant. Thus, no risk of recursion. - if let Some(expr) = maybe_expr { - let expr = &self.hir_map.body(expr).value; - self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span); - } - } - - fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) { - self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti), ti.span); - } - - fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) { - self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii), ii.span); - } - - fn visit_path(&mut self, path: &'hir hir::Path, _: ast::NodeId) { - match path.def { - Def::Static(def_id, _) | - Def::AssociatedConst(def_id) | - Def::Const(def_id) => { - if let Some(node_id) = self.hir_map.as_local_node_id(def_id) { - match self.hir_map.get(node_id) { - hir_map::NodeItem(item) => self.visit_item(item), - hir_map::NodeTraitItem(item) => self.visit_trait_item(item), - hir_map::NodeImplItem(item) => self.visit_impl_item(item), - hir_map::NodeForeignItem(_) => {} - _ => { - span_bug!(path.span, - "expected item, found {}", - self.hir_map.node_to_string(node_id)); - } - } - } - } - // For variants, we only want to check expressions that - // affect the specific variant used, but we need to check - // the whole enum definition to see what expression that - // might be (if any). - Def::VariantCtor(variant_id, CtorKind::Const) => { - if let Some(variant_id) = self.hir_map.as_local_node_id(variant_id) { - let variant = self.hir_map.expect_variant(variant_id); - let enum_id = self.hir_map.get_parent(variant_id); - let enum_item = self.hir_map.expect_item(enum_id); - if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node { - self.populate_enum_discriminants(enum_def); - self.visit_variant(variant, generics, enum_id); - } else { - span_bug!(path.span, - "`check_static_recursion` found \ - non-enum in Def::VariantCtor"); - } - } - } - _ => (), - } - intravisit::walk_path(self, path); - } -} diff --git a/src/test/compile-fail/issue-17252.rs b/src/test/compile-fail/issue-17252.rs index 0c04e295e1458..1c3e6890c8e2e 100644 --- a/src/test/compile-fail/issue-17252.rs +++ b/src/test/compile-fail/issue-17252.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const FOO: usize = FOO; //~ ERROR recursive constant +const FOO: usize = FOO; //~ ERROR E0391 fn main() { let _x: [u8; FOO]; // caused stack overflow prior to fix let _y: usize = 1 + { - const BAR: usize = BAR; //~ ERROR recursive constant + const BAR: usize = BAR; let _z: [u8; BAR]; // caused stack overflow prior to fix 1 }; diff --git a/src/test/ui/issue-23302.rs b/src/test/ui/issue-23302-1.rs similarity index 71% rename from src/test/ui/issue-23302.rs rename to src/test/ui/issue-23302-1.rs index 2d93ab0c30c8f..10a538301162c 100644 --- a/src/test/ui/issue-23302.rs +++ b/src/test/ui/issue-23302-1.rs @@ -11,18 +11,7 @@ // Check that an enum with recursion in the discriminant throws // the appropriate error (rather than, say, blowing the stack). enum X { - A = X::A as isize, //~ ERROR E0265 + A = X::A as isize, //~ ERROR E0391 } -// Since `Y::B` here defaults to `Y::A+1`, this is also a -// recursive definition. -enum Y { - A = Y::B as isize, //~ ERROR E0265 - B, -} - -const A: i32 = B; //~ ERROR E0265 - -const B: i32 = A; //~ ERROR E0265 - fn main() { } diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr new file mode 100644 index 0000000000000..4fbd0e72bf2c8 --- /dev/null +++ b/src/test/ui/issue-23302-1.stderr @@ -0,0 +1,15 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-1.rs:14:9 + | +14 | A = X::A as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ cyclic reference + | +note: the cycle begins when const-evaluating `X::A::{{initializer}}`... + --> $DIR/issue-23302-1.rs:14:5 + | +14 | A = X::A as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^^^^^ + = note: ...which then again requires const-evaluating `X::A::{{initializer}}`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-17718-recursive.rs b/src/test/ui/issue-23302-2.rs similarity index 64% rename from src/test/compile-fail/issue-17718-recursive.rs rename to src/test/ui/issue-23302-2.rs index 9959b0c6fc523..d1af19eb579f5 100644 --- a/src/test/compile-fail/issue-17718-recursive.rs +++ b/src/test/ui/issue-23302-2.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const A: usize = B; //~ ERROR: recursive constant -const B: usize = A; //~ ERROR: recursive constant +// Since `Y::B` here defaults to `Y::A+1`, this is also a +// recursive definition. +enum Y { + A = Y::B as isize, //~ ERROR E0391 + B, +} -fn main() {} +fn main() { } diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr new file mode 100644 index 0000000000000..90d828621e937 --- /dev/null +++ b/src/test/ui/issue-23302-2.stderr @@ -0,0 +1,15 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-2.rs:14:9 + | +14 | A = Y::B as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ cyclic reference + | +note: the cycle begins when const-evaluating `Y::A::{{initializer}}`... + --> $DIR/issue-23302-2.rs:14:5 + | +14 | A = Y::B as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^^^^^ + = note: ...which then again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/compile-fail/const-recursive.rs b/src/test/ui/issue-23302-3.rs similarity index 69% rename from src/test/compile-fail/const-recursive.rs rename to src/test/ui/issue-23302-3.rs index 7c05a817243b4..1d750b09025b9 100644 --- a/src/test/compile-fail/const-recursive.rs +++ b/src/test/ui/issue-23302-3.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const a: isize = b; //~ ERROR recursive constant -const b: isize = a; //~ ERROR recursive constant +const A: i32 = B; //~ ERROR E0391 -fn main() { -} +const B: i32 = A; + +fn main() { } diff --git a/src/test/ui/issue-23302-3.stderr b/src/test/ui/issue-23302-3.stderr new file mode 100644 index 0000000000000..a72010c2c797f --- /dev/null +++ b/src/test/ui/issue-23302-3.stderr @@ -0,0 +1,20 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + --> $DIR/issue-23302-3.rs:11:16 + | +11 | const A: i32 = B; //~ ERROR E0391 + | ^ cyclic reference + | +note: the cycle begins when processing `B`... + --> $DIR/issue-23302-3.rs:13:1 + | +13 | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ +note: ...which then requires processing `A`... + --> $DIR/issue-23302-3.rs:13:16 + | +13 | const B: i32 = A; + | ^ + = note: ...which then again requires processing `B`, completing the cycle. + +error: aborting due to previous error + diff --git a/src/test/ui/issue-23302.stderr b/src/test/ui/issue-23302.stderr deleted file mode 100644 index 4e93809fac374..0000000000000 --- a/src/test/ui/issue-23302.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:14:9 - | -14 | A = X::A as isize, //~ ERROR E0265 - | ^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:20:9 - | -20 | A = Y::B as isize, //~ ERROR E0265 - | ^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:24:1 - | -24 | const A: i32 = B; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-23302.rs:26:1 - | -26 | const B: i32 = A; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/issue-36163.rs b/src/test/ui/issue-36163.rs index 2337f82afa49f..4c74d9d9173d8 100644 --- a/src/test/ui/issue-36163.rs +++ b/src/test/ui/issue-36163.rs @@ -8,16 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const A: i32 = Foo::B; //~ ERROR E0265 +const A: isize = Foo::B as isize; enum Foo { - B = A, //~ ERROR E0265 + B = A, //~ ERROR E0391 } -enum Bar { - C = Bar::C, //~ ERROR E0265 -} - -const D: i32 = A; - fn main() {} diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr index 5a107d88f2e4f..3868d58e7f7ae 100644 --- a/src/test/ui/issue-36163.stderr +++ b/src/test/ui/issue-36163.stderr @@ -1,20 +1,20 @@ -error[E0265]: recursive constant - --> $DIR/issue-36163.rs:11:1 - | -11 | const A: i32 = Foo::B; //~ ERROR E0265 - | ^^^^^^^^^^^^^^^^^^^^^^ recursion not allowed in constant - -error[E0265]: recursive constant +error[E0391]: unsupported cyclic reference between types/traits detected --> $DIR/issue-36163.rs:14:9 | -14 | B = A, //~ ERROR E0265 - | ^ recursion not allowed in constant - -error[E0265]: recursive constant - --> $DIR/issue-36163.rs:18:9 +14 | B = A, //~ ERROR E0391 + | ^ cyclic reference + | +note: the cycle begins when const-evaluating `Foo::B::{{initializer}}`... + --> $DIR/issue-36163.rs:14:5 + | +14 | B = A, //~ ERROR E0391 + | ^^^^^ +note: ...which then requires const-evaluating `A`... + --> $DIR/issue-36163.rs:14:9 | -18 | C = Bar::C, //~ ERROR E0265 - | ^^^^^^ recursion not allowed in constant +14 | B = A, //~ ERROR E0391 + | ^ + = note: ...which then again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle. -error: aborting due to 3 previous errors +error: aborting due to previous error From 46a3f2fa188a8b8c68a2941afb43182691662493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 10 Feb 2018 00:28:23 +0100 Subject: [PATCH 06/42] Change error message for E0391 to "cyclic dependency detected" --- src/librustc/ty/maps/plumbing.rs | 2 +- .../coherence-inherited-assoc-ty-cycle-err.rs | 2 +- src/test/compile-fail/const-size_of-cycle.rs | 2 +- .../cycle-projection-based-on-where-clause.rs | 2 +- .../compile-fail/cycle-trait-default-type-trait.rs | 2 +- src/test/compile-fail/cycle-trait-supertrait-direct.rs | 2 +- src/test/compile-fail/infinite-vec-type-recursion.rs | 2 +- src/test/compile-fail/issue-20772.rs | 2 +- src/test/compile-fail/issue-20825.rs | 2 +- src/test/compile-fail/issue-21177.rs | 2 +- src/test/compile-fail/issue-22673.rs | 2 +- src/test/compile-fail/issue-26548.rs | 2 +- src/test/compile-fail/issue-34373.rs | 2 +- src/test/compile-fail/issue-44415.rs | 2 +- src/test/compile-fail/resolve-self-in-impl.rs | 10 +++++----- src/test/ui/cycle-trait-supertrait-indirect.rs | 2 +- src/test/ui/cycle-trait-supertrait-indirect.stderr | 2 +- src/test/ui/impl-trait/auto-trait-leak.rs | 2 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 2 +- src/test/ui/issue-12511.rs | 2 +- src/test/ui/issue-12511.stderr | 2 +- src/test/ui/issue-23302-1.stderr | 2 +- src/test/ui/issue-23302-2.stderr | 2 +- src/test/ui/issue-23302-3.stderr | 2 +- src/test/ui/issue-36163.stderr | 2 +- src/test/ui/resolve/issue-23305.rs | 2 +- src/test/ui/resolve/issue-23305.stderr | 2 +- 27 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..1a2b80626fe47 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!(self.sess, span, E0391, - "unsupported cyclic reference between types/traits detected"); + "cyclic dependency detected"); err.span_label(span, "cyclic reference"); err.span_note(self.sess.codemap().def_span(stack[0].0), diff --git a/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs b/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs index 5d7f33967402c..2f4d82e2ef514 100644 --- a/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs +++ b/src/test/compile-fail/coherence-inherited-assoc-ty-cycle-err.rs @@ -17,7 +17,7 @@ #![feature(specialization)] trait Trait { type Assoc; } -//~^ unsupported cyclic reference between types/traits detected [E0391] +//~^ cyclic dependency detected [E0391] impl Trait for Vec { type Assoc = (); diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs index cbeafdfe6acc9..6218dcbf5f2c5 100644 --- a/src/test/compile-fail/const-size_of-cycle.rs +++ b/src/test/compile-fail/const-size_of-cycle.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unsupported cyclic reference between types/traits detected +// error-pattern: cyclic dependency detected #![feature(const_fn)] diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs index 7af2f11bd2815..ee4722c010f16 100644 --- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs +++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs @@ -25,7 +25,7 @@ trait Trait { type Item; } struct A where T : Trait, T : Add - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected //~| ERROR associated type `Item` not found for `T` { data: T diff --git a/src/test/compile-fail/cycle-trait-default-type-trait.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs index e6caeb34a8c8f..88672088bcb4c 100644 --- a/src/test/compile-fail/cycle-trait-default-type-trait.rs +++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs @@ -12,7 +12,7 @@ // again references the trait. trait Foo> { - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected } fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-direct.rs b/src/test/compile-fail/cycle-trait-supertrait-direct.rs index ef3fead18f6aa..626567ccc0ead 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-direct.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-direct.rs @@ -11,7 +11,7 @@ // Test a supertrait cycle where a trait extends itself. trait Chromosome: Chromosome { - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected } fn main() { } diff --git a/src/test/compile-fail/infinite-vec-type-recursion.rs b/src/test/compile-fail/infinite-vec-type-recursion.rs index e5120840f7672..25d0590db1b75 100644 --- a/src/test/compile-fail/infinite-vec-type-recursion.rs +++ b/src/test/compile-fail/infinite-vec-type-recursion.rs @@ -9,6 +9,6 @@ // except according to those terms. type x = Vec; -//~^ ERROR unsupported cyclic reference +//~^ ERROR cyclic dependency detected fn main() { let b: x = Vec::new(); } diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs index 7ae4250d4203b..88395e5f1eafa 100644 --- a/src/test/compile-fail/issue-20772.rs +++ b/src/test/compile-fail/issue-20772.rs @@ -9,7 +9,7 @@ // except according to those terms. trait T : Iterator -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| ERROR associated type `Item` not found for `Self` {} diff --git a/src/test/compile-fail/issue-20825.rs b/src/test/compile-fail/issue-20825.rs index 7d082a3148f76..aeb798b382875 100644 --- a/src/test/compile-fail/issue-20825.rs +++ b/src/test/compile-fail/issue-20825.rs @@ -13,7 +13,7 @@ pub trait Subscriber { } pub trait Processor: Subscriber { - //~^ ERROR unsupported cyclic reference between types/traits detected [E0391] + //~^ ERROR cyclic dependency detected [E0391] type Input; } diff --git a/src/test/compile-fail/issue-21177.rs b/src/test/compile-fail/issue-21177.rs index f49b71953835b..40c95b98f1264 100644 --- a/src/test/compile-fail/issue-21177.rs +++ b/src/test/compile-fail/issue-21177.rs @@ -14,7 +14,7 @@ trait Trait { } fn foo>() { } -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| ERROR associated type `B` not found for `T` fn main() { } diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs index 442e6bcda5a09..fde2d001542b8 100644 --- a/src/test/compile-fail/issue-22673.rs +++ b/src/test/compile-fail/issue-22673.rs @@ -9,7 +9,7 @@ // except according to those terms. trait Expr : PartialEq { - //~^ ERROR: unsupported cyclic reference between types/traits detected + //~^ ERROR: cyclic dependency detected type Item; } diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 39c6e97268f98..16a650cc6d886 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: unsupported cyclic reference between types/traits detected +// error-pattern: cyclic dependency detected // note-pattern: the cycle begins when computing layout of // note-pattern: ...which then requires computing layout of // note-pattern: ...which then again requires computing layout of diff --git a/src/test/compile-fail/issue-34373.rs b/src/test/compile-fail/issue-34373.rs index 7bbc680197e84..b18e05af47c97 100644 --- a/src/test/compile-fail/issue-34373.rs +++ b/src/test/compile-fail/issue-34373.rs @@ -15,7 +15,7 @@ trait Trait { } pub struct Foo>>; -type DefaultFoo = Foo; //~ ERROR unsupported cyclic reference +type DefaultFoo = Foo; //~ ERROR cyclic dependency detected fn main() { } diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs index 3b7089f497526..930a427e9a5e0 100644 --- a/src/test/compile-fail/issue-44415.rs +++ b/src/test/compile-fail/issue-44415.rs @@ -15,7 +15,7 @@ use std::intrinsics; struct Foo { bytes: [u8; unsafe { intrinsics::size_of::() }], - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected x: usize, } diff --git a/src/test/compile-fail/resolve-self-in-impl.rs b/src/test/compile-fail/resolve-self-in-impl.rs index 55ae37404a9fa..7210c857125d6 100644 --- a/src/test/compile-fail/resolve-self-in-impl.rs +++ b/src/test/compile-fail/resolve-self-in-impl.rs @@ -21,10 +21,10 @@ impl Tr for S where Self: Copy {} // OK impl Tr for S where S: Copy {} // OK impl Tr for S where Self::A: Copy {} // OK -impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected -impl S {} //~ ERROR unsupported cyclic reference between types/traits detected -impl Tr for S {} //~ ERROR unsupported cyclic reference between types/traits detected +impl Tr for Self {} //~ ERROR cyclic dependency detected +impl Tr for S {} //~ ERROR cyclic dependency detected +impl Self {} //~ ERROR cyclic dependency detected +impl S {} //~ ERROR cyclic dependency detected +impl Tr for S {} //~ ERROR cyclic dependency detected fn main() {} diff --git a/src/test/ui/cycle-trait-supertrait-indirect.rs b/src/test/ui/cycle-trait-supertrait-indirect.rs index c3b0276bcf9cb..447505e886f81 100644 --- a/src/test/ui/cycle-trait-supertrait-indirect.rs +++ b/src/test/ui/cycle-trait-supertrait-indirect.rs @@ -18,7 +18,7 @@ trait B: C { } trait C: B { } - //~^ ERROR unsupported cyclic reference + //~^ ERROR cyclic dependency detected //~| cyclic reference fn main() { } diff --git a/src/test/ui/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait-supertrait-indirect.stderr index 107644037a9ca..a01565546462d 100644 --- a/src/test/ui/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait-supertrait-indirect.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/cycle-trait-supertrait-indirect.rs:20:1 | 20 | trait C: B { } diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index 705390e3b969c..5a6aac43ec770 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -42,7 +42,7 @@ fn after() -> impl Fn(i32) { // independently resolved and only require the concrete // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { - //~^ ERROR unsupported cyclic reference between types/traits detected + //~^ ERROR cyclic dependency detected //~| cyclic reference send(cycle2().clone()); diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 838a3002e3aa7..d6e31ba1e1f9c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -28,7 +28,7 @@ note: required by `send` 24 | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/auto-trait-leak.rs:44:1 | 44 | fn cycle1() -> impl Clone { diff --git a/src/test/ui/issue-12511.rs b/src/test/ui/issue-12511.rs index e1335c7d558e1..e4d6076868717 100644 --- a/src/test/ui/issue-12511.rs +++ b/src/test/ui/issue-12511.rs @@ -12,7 +12,7 @@ trait t1 : t2 { } trait t2 : t1 { -//~^ ERROR unsupported cyclic reference between types/traits detected +//~^ ERROR cyclic dependency detected //~| cyclic reference } diff --git a/src/test/ui/issue-12511.stderr b/src/test/ui/issue-12511.stderr index cbf005a70b028..aec828a90d1a7 100644 --- a/src/test/ui/issue-12511.stderr +++ b/src/test/ui/issue-12511.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-12511.rs:14:1 | 14 | trait t2 : t1 { diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr index 4fbd0e72bf2c8..0658c07fb1dbe 100644 --- a/src/test/ui/issue-23302-1.stderr +++ b/src/test/ui/issue-23302-1.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-1.rs:14:9 | 14 | A = X::A as isize, //~ ERROR E0391 diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr index 90d828621e937..c4a1c4f80c82c 100644 --- a/src/test/ui/issue-23302-2.stderr +++ b/src/test/ui/issue-23302-2.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-2.rs:14:9 | 14 | A = Y::B as isize, //~ ERROR E0391 diff --git a/src/test/ui/issue-23302-3.stderr b/src/test/ui/issue-23302-3.stderr index a72010c2c797f..76f543cff7913 100644 --- a/src/test/ui/issue-23302-3.stderr +++ b/src/test/ui/issue-23302-3.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23302-3.rs:11:16 | 11 | const A: i32 = B; //~ ERROR E0391 diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr index 3868d58e7f7ae..d0337fc32b03e 100644 --- a/src/test/ui/issue-36163.stderr +++ b/src/test/ui/issue-36163.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-36163.rs:14:9 | 14 | B = A, //~ ERROR E0391 diff --git a/src/test/ui/resolve/issue-23305.rs b/src/test/ui/resolve/issue-23305.rs index f249e0e1127ee..34f8a0a48431c 100644 --- a/src/test/ui/resolve/issue-23305.rs +++ b/src/test/ui/resolve/issue-23305.rs @@ -13,6 +13,6 @@ pub trait ToNbt { } impl ToNbt {} -//~^ ERROR unsupported cyclic reference +//~^ ERROR cyclic dependency detected fn main() {} diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 5bba9fc41e276..a0b4d424ec968 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -1,4 +1,4 @@ -error[E0391]: unsupported cyclic reference between types/traits detected +error[E0391]: cyclic dependency detected --> $DIR/issue-23305.rs:15:12 | 15 | impl ToNbt {} From 335e25fd79e57c4cd7453c0af25e5c6bd0406602 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 15:50:37 +0100 Subject: [PATCH 07/42] incr.comp.: Don't keep RefCells in on-disk-cache borrowed in order to allow for recursive invocations. --- src/librustc/ty/maps/on_disk_cache.rs | 34 +++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 56ed0f9106f30..17b44f6959f2f 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -347,22 +347,21 @@ impl<'sess> OnDiskCache<'sess> { return None }; - let mut cnum_map = self.cnum_map.borrow_mut(); - if cnum_map.is_none() { + // Initialize the cnum_map if it is not initialized yet. + if self.cnum_map.borrow().is_none() { + let mut cnum_map = self.cnum_map.borrow_mut(); *cnum_map = Some(Self::compute_cnum_map(tcx, &self.prev_cnums[..])); } - - let mut synthetic_expansion_infos = self.synthetic_expansion_infos.borrow_mut(); - let mut file_index_to_file = self.file_index_to_file.borrow_mut(); + let cnum_map = self.cnum_map.borrow(); let mut decoder = CacheDecoder { tcx, opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), codemap: self.codemap, cnum_map: cnum_map.as_ref().unwrap(), - file_index_to_file: &mut file_index_to_file, + file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, - synthetic_expansion_infos: &mut synthetic_expansion_infos, + synthetic_expansion_infos: &self.synthetic_expansion_infos, }; match decode_tagged(&mut decoder, dep_node_index) { @@ -421,21 +420,21 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { opaque: opaque::Decoder<'x>, codemap: &'x CodeMap, cnum_map: &'x IndexVec>, - synthetic_expansion_infos: &'x mut FxHashMap, - file_index_to_file: &'x mut FxHashMap>, + synthetic_expansion_infos: &'x RefCell>, + file_index_to_file: &'x RefCell>>, file_index_to_stable_id: &'x FxHashMap, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { - fn file_index_to_file(&mut self, index: FileMapIndex) -> Rc { + fn file_index_to_file(&self, index: FileMapIndex) -> Rc { let CacheDecoder { - ref mut file_index_to_file, + ref file_index_to_file, ref file_index_to_stable_id, ref codemap, .. } = *self; - file_index_to_file.entry(index).or_insert_with(|| { + file_index_to_file.borrow_mut().entry(index).or_insert_with(|| { let stable_id = file_index_to_stable_id[&index]; codemap.filemap_by_stable_id(stable_id) .expect("Failed to lookup FileMap in new context.") @@ -572,19 +571,24 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { let pos = AbsoluteBytePos::new(self.opaque.position()); let expn_info: ExpnInfo = Decodable::decode(self)?; let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); ctxt } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - if let Some(ctxt) = self.synthetic_expansion_infos.get(&pos).cloned() { + let cached_ctxt = self.synthetic_expansion_infos + .borrow() + .get(&pos) + .cloned(); + + if let Some(ctxt) = cached_ctxt { ctxt } else { let expn_info = self.with_position(pos.to_usize(), |this| { ExpnInfo::decode(this) })?; let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.insert(pos, ctxt); + self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); ctxt } } From 75f72c0de141573eef56f13fd48a3af12deaee4f Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 15:40:27 -0800 Subject: [PATCH 08/42] Make nested impl Trait a hard error --- src/librustc_passes/ast_validation.rs | 69 ++++++++++++++++++ src/librustc_passes/diagnostics.rs | 1 + src/libsyntax/feature_gate.rs | 70 +------------------ .../compile-fail/impl-trait/where-allowed.rs | 4 +- src/test/run-pass/impl-trait/lifetimes.rs | 11 ++- src/test/ui/error-codes/E0657.rs | 6 +- .../nested_impl_trait.rs} | 10 +-- src/test/ui/nested_impl_trait.stderr | 50 +++++++++++++ 8 files changed, 138 insertions(+), 83 deletions(-) rename src/test/{compile-fail/feature-gate-nested_impl_trait.rs => ui/nested_impl_trait.rs} (80%) create mode 100644 src/test/ui/nested_impl_trait.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6971033c8994b..826f27c2ddbf4 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -420,6 +420,75 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } +// Bans nested `impl Trait`, e.g. `impl Into`. +// Nested `impl Trait` _is_ allowed in associated type position, +// e.g `impl Iterator` +struct NestedImplTraitVisitor<'a> { + session: &'a Session, + outer_impl_trait: Option, +} + +impl<'a> NestedImplTraitVisitor<'a> { + fn with_impl_trait(&mut self, outer_impl_trait: Option, f: F) + where F: FnOnce(&mut NestedImplTraitVisitor<'a>) + { + let old_outer_impl_trait = self.outer_impl_trait; + self.outer_impl_trait = outer_impl_trait; + f(self); + self.outer_impl_trait = old_outer_impl_trait; + } +} + + +impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + if let TyKind::ImplTrait(_) = t.node { + if let Some(outer_impl_trait) = self.outer_impl_trait { + struct_span_err!(self.session, t.span, E0666, + "nested `impl Trait` is not allowed") + .span_label(outer_impl_trait, "outer `impl Trait`") + .span_label(t.span, "devilishly nested `impl Trait` here") + .emit(); + + } + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + } else { + visit::walk_ty(self, t); + } + } + fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a PathParameters) { + match *path_parameters { + PathParameters::AngleBracketed(ref params) => { + for type_ in ¶ms.types { + self.visit_ty(type_); + } + for type_binding in ¶ms.bindings { + // Type bindings such as `Item=impl Debug` in `Iterator` + // are allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty)); + } + } + PathParameters::Parenthesized(ref params) => { + for type_ in ¶ms.inputs { + self.visit_ty(type_); + } + if let Some(ref type_) = params.output { + // `-> Foo` syntax is essentially an associated type binding, + // so it is also allowed to contain nested `impl Trait`. + self.with_impl_trait(None, |this| visit::walk_ty(this, type_)); + } + } + } + } +} + + pub fn check_crate(session: &Session, krate: &Crate) { + visit::walk_crate( + &mut NestedImplTraitVisitor { + session, + outer_impl_trait: None, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 743f7b7326e9e..6dfc52f842e16 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -320,4 +320,5 @@ register_diagnostics! { E0567, // auto traits can not have generic parameters E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies + E0666, // nested `impl Trait` is illegal } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c33..a3eba63706cb0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -432,9 +432,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660)), - // Nested `impl Trait` - (active, nested_impl_trait, "1.24.0", Some(34511)), - // Termination trait in main (RFC 1937) (active, termination_trait, "1.24.0", Some(43301)), @@ -1352,73 +1349,8 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool { } } -// Bans nested `impl Trait`, e.g. `impl Into`. -// Nested `impl Trait` _is_ allowed in associated type position, -// e.g `impl Iterator` -struct NestedImplTraitVisitor<'a> { - context: &'a Context<'a>, - is_in_impl_trait: bool, -} - -impl<'a> NestedImplTraitVisitor<'a> { - fn with_impl_trait(&mut self, is_in_impl_trait: bool, f: F) - where F: FnOnce(&mut NestedImplTraitVisitor<'a>) - { - let old_is_in_impl_trait = self.is_in_impl_trait; - self.is_in_impl_trait = is_in_impl_trait; - f(self); - self.is_in_impl_trait = old_is_in_impl_trait; - } -} - - -impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { - fn visit_ty(&mut self, t: &'a ast::Ty) { - if let ast::TyKind::ImplTrait(_) = t.node { - if self.is_in_impl_trait { - gate_feature_post!(&self, nested_impl_trait, t.span, - "nested `impl Trait` is experimental" - ); - } - self.with_impl_trait(true, |this| visit::walk_ty(this, t)); - } else { - visit::walk_ty(self, t); - } - } - fn visit_path_parameters(&mut self, _: Span, path_parameters: &'a ast::PathParameters) { - match *path_parameters { - ast::PathParameters::AngleBracketed(ref params) => { - for type_ in ¶ms.types { - self.visit_ty(type_); - } - for type_binding in ¶ms.bindings { - // Type bindings such as `Item=impl Debug` in `Iterator` - // are allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, &type_binding.ty)); - } - } - ast::PathParameters::Parenthesized(ref params) => { - for type_ in ¶ms.inputs { - self.visit_ty(type_); - } - if let Some(ref type_) = params.output { - // `-> Foo` syntax is essentially an associated type binding, - // so it is also allowed to contain nested `impl Trait`. - self.with_impl_trait(false, |this| visit::walk_ty(this, type_)); - } - } - } - } -} - impl<'a> PostExpansionVisitor<'a> { - fn whole_crate_feature_gates(&mut self, krate: &ast::Crate) { - visit::walk_crate( - &mut NestedImplTraitVisitor { - context: self.context, - is_in_impl_trait: false, - }, krate); - + fn whole_crate_feature_gates(&mut self, _krate: &ast::Crate) { for &(ident, span) in &*self.context.parse_sess.non_modrs_mods.borrow() { if !span.allows_unstable() { let cx = &self.context; diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index a9fe1e04664e9..52c5471681df3 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,7 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(conservative_impl_trait, nested_impl_trait, universal_impl_trait, dyn_trait)] +#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)] use std::fmt::Debug; // Allowed @@ -60,6 +60,7 @@ fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } @@ -68,6 +69,7 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 1f2d76f289472..4d40e707ddcb9 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait, underscore_lifetimes, universal_impl_trait)] #![allow(warnings)] use std::fmt::Debug; @@ -55,12 +55,11 @@ fn pass_through_elision_with_fn_ptr(x: &fn(&u32) -> &u32) -> impl Into<&fn(&u32) fn pass_through_elision_with_fn_path &u32>( x: &T -) -> impl Into<&impl Fn(&u32) -> &u32> { x } +) -> &impl Fn(&u32) -> &u32 { x } -fn foo(x: &impl Debug) -> impl Into<&impl Debug> { x } -fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> impl Into<&'a impl Debug> { x } -fn foo_no_outer_impl(x: &impl Debug) -> &impl Debug { x } -fn foo_explicit_arg(x: &T) -> impl Into<&impl Debug> { x } +fn foo(x: &impl Debug) -> &impl Debug { x } +fn foo_explicit_lifetime<'a>(x: &'a impl Debug) -> &'a impl Debug { x } +fn foo_explicit_arg(x: &T) -> &impl Debug { x } fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () } fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() } diff --git a/src/test/ui/error-codes/E0657.rs b/src/test/ui/error-codes/E0657.rs index 4595e413081a5..31b3acd86ef55 100644 --- a/src/test/ui/error-codes/E0657.rs +++ b/src/test/ui/error-codes/E0657.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(warnings)] -#![feature(conservative_impl_trait, nested_impl_trait)] +#![feature(conservative_impl_trait)] trait Id {} trait Lt<'a> {} @@ -17,7 +17,7 @@ impl<'a> Lt<'a> for () {} impl Id for T {} fn free_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657] { () @@ -26,7 +26,7 @@ fn free_fn_capture_hrtb_in_impl_trait() struct Foo; impl Foo { fn impl_fn_capture_hrtb_in_impl_trait() - -> impl for<'a> Id> + -> Box Id>> //~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level { () diff --git a/src/test/compile-fail/feature-gate-nested_impl_trait.rs b/src/test/ui/nested_impl_trait.rs similarity index 80% rename from src/test/compile-fail/feature-gate-nested_impl_trait.rs rename to src/test/ui/nested_impl_trait.rs index 7c35263d05dd7..f6302c0f3b3e2 100644 --- a/src/test/compile-fail/feature-gate-nested_impl_trait.rs +++ b/src/test/ui/nested_impl_trait.rs @@ -14,18 +14,19 @@ use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed fn bad_in_fn_syntax(x: fn() -> impl Into) {} -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed +//~^^ `impl Trait` not allowed fn bad_in_arg_position(_: impl Into) { } -//~^ ERROR nested `impl Trait` is experimental +//~^ ERROR nested `impl Trait` is not allowed struct X; impl X { fn bad(x: impl Into) -> impl Into { x } - //~^ ERROR nested `impl Trait` is experimental + //~^ ERROR nested `impl Trait` is not allowed } fn allowed_in_assoc_type() -> impl Iterator { @@ -33,6 +34,7 @@ fn allowed_in_assoc_type() -> impl Iterator { } fn allowed_in_ret_type() -> impl Fn() -> impl Into { +//~^ `impl Trait` not allowed || 5 } diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr new file mode 100644 index 0000000000000..6649f9ab99cc1 --- /dev/null +++ b/src/test/ui/nested_impl_trait.stderr @@ -0,0 +1,50 @@ +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:16:56 + | +16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:19:42 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:23:37 + | +23 | fn bad_in_arg_position(_: impl Into) { } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0666]: nested `impl Trait` is not allowed + --> $DIR/nested_impl_trait.rs:28:44 + | +28 | fn bad(x: impl Into) -> impl Into { x } + | ----------^^^^^^^^^^- + | | | + | | devilishly nested `impl Trait` here + | outer `impl Trait` + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:19:32 + | +19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/nested_impl_trait.rs:36:42 + | +36 | fn allowed_in_ret_type() -> impl Fn() -> impl Into { + | ^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + From 70e1f4fc6d951dfc0547ff5acb3d8780d16635e6 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 8 Feb 2018 16:50:14 -0800 Subject: [PATCH 09/42] Disallow projections from impl Trait types --- src/librustc_passes/ast_validation.rs | 68 ++++++++++++++++++++++- src/librustc_passes/diagnostics.rs | 1 + src/test/ui/impl_trait_projections.rs | 43 ++++++++++++++ src/test/ui/impl_trait_projections.stderr | 28 ++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/impl_trait_projections.rs create mode 100644 src/test/ui/impl_trait_projections.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 826f27c2ddbf4..14ea5c0ce7982 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -447,7 +447,7 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { struct_span_err!(self.session, t.span, E0666, "nested `impl Trait` is not allowed") .span_label(outer_impl_trait, "outer `impl Trait`") - .span_label(t.span, "devilishly nested `impl Trait` here") + .span_label(t.span, "nested `impl Trait` here") .emit(); } @@ -482,6 +482,66 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> { } } +// Bans `impl Trait` in path projections like `::Item` or `Foo::Bar`. +struct ImplTraitProjectionVisitor<'a> { + session: &'a Session, + is_banned: bool, +} + +impl<'a> ImplTraitProjectionVisitor<'a> { + fn with_ban(&mut self, f: F) + where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>) + { + let old_is_banned = self.is_banned; + self.is_banned = true; + f(self); + self.is_banned = old_is_banned; + } +} + +impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> { + fn visit_ty(&mut self, t: &'a Ty) { + match t.node { + TyKind::ImplTrait(_) => { + if self.is_banned { + struct_span_err!(self.session, t.span, E0667, + "`impl Trait` is not allowed in path parameters") + .emit(); + } + } + TyKind::Path(ref qself, ref path) => { + // We allow these: + // - `Option` + // - `option::Option` + // - `option::Option::Foo + // + // But not these: + // - `::Foo` + // - `option::Option::Foo`. + // + // To implement this, we disallow `impl Trait` from `qself` + // (for cases like `::Foo>`) + // but we allow `impl Trait` in `PathParameters` + // iff there are no more PathSegments. + if let Some(ref qself) = *qself { + // `impl Trait` in `qself` is always illegal + self.with_ban(|this| this.visit_ty(&qself.ty)); + } + + for (i, segment) in path.segments.iter().enumerate() { + // Allow `impl Trait` iff we're on the final path segment + if i == (path.segments.len() - 1) { + visit::walk_path_segment(self, path.span, segment); + } else { + self.with_ban(|this| + visit::walk_path_segment(this, path.span, segment)); + } + } + } + _ => visit::walk_ty(self, t), + } + } +} pub fn check_crate(session: &Session, krate: &Crate) { visit::walk_crate( @@ -490,5 +550,11 @@ pub fn check_crate(session: &Session, krate: &Crate) { outer_impl_trait: None, }, krate); + visit::walk_crate( + &mut ImplTraitProjectionVisitor { + session, + is_banned: false, + }, krate); + visit::walk_crate(&mut AstValidator { session: session }, krate) } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 6dfc52f842e16..980808a6905c1 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -321,4 +321,5 @@ register_diagnostics! { E0568, // auto traits can not have super traits E0642, // patterns aren't allowed in methods without bodies E0666, // nested `impl Trait` is illegal + E0667, // `impl Trait` in projections } diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs new file mode 100644 index 0000000000000..e34b7799fb724 --- /dev/null +++ b/src/test/ui/impl_trait_projections.rs @@ -0,0 +1,43 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(conservative_impl_trait, universal_impl_trait)] + +use std::fmt::Debug; +use std::option; + +fn parametrized_type_is_allowed() -> Option { + Some(5i32) +} + +fn path_parametrized_type_is_allowed() -> option::Option { + Some(5i32) +} + +fn projection_is_disallowed(x: impl Iterator) -> ::Item { +//~^ ERROR `impl Trait` is not allowed in path parameters +//~^^ ERROR ambiguous associated type + x.next().unwrap() +} + +fn projection_with_named_trait_is_disallowed(x: impl Iterator) + -> ::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + x.next().unwrap() +} + +fn projection_with_named_trait_inside_path_is_disallowed() + -> <::std::ops::Range as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + (1i32..100).next().unwrap() +} + +fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr new file mode 100644 index 0000000000000..2e8bfc931f82e --- /dev/null +++ b/src/test/ui/impl_trait_projections.stderr @@ -0,0 +1,28 @@ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:23:51 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:30:9 + | +30 | -> ::Item + | ^^^^^^^^^^^^^ + +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:37:27 + | +37 | -> <::std::ops::Range as Iterator>::Item + | ^^^^^^^^^^ + +error[E0223]: ambiguous associated type + --> $DIR/impl_trait_projections.rs:23:50 + | +23 | fn projection_is_disallowed(x: impl Iterator) -> ::Item { + | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type + | + = note: specify the type using the syntax `::Item` + +error: aborting due to 4 previous errors + From f1fbf79223aca762c42c6674d125c4c5223f9949 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:46:33 -0800 Subject: [PATCH 10/42] Amend nested impl Trait error message --- src/test/ui/nested_impl_trait.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/nested_impl_trait.stderr b/src/test/ui/nested_impl_trait.stderr index 6649f9ab99cc1..094926120cdee 100644 --- a/src/test/ui/nested_impl_trait.stderr +++ b/src/test/ui/nested_impl_trait.stderr @@ -4,7 +4,7 @@ error[E0666]: nested `impl Trait` is not allowed 16 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -13,7 +13,7 @@ error[E0666]: nested `impl Trait` is not allowed 19 | fn bad_in_fn_syntax(x: fn() -> impl Into) {} | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -22,7 +22,7 @@ error[E0666]: nested `impl Trait` is not allowed 23 | fn bad_in_arg_position(_: impl Into) { } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed @@ -31,7 +31,7 @@ error[E0666]: nested `impl Trait` is not allowed 28 | fn bad(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | - | | devilishly nested `impl Trait` here + | | nested `impl Trait` here | outer `impl Trait` error[E0562]: `impl Trait` not allowed outside of function and inherent method return types From dbacf0c56ba2bd5ed38fc2a2e4bc20150271e7f2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 13 Feb 2018 17:52:22 -0800 Subject: [PATCH 11/42] Test err on impl Trait projection within dyn Trait --- src/test/ui/impl_trait_projections.rs | 9 ++++++++- src/test/ui/impl_trait_projections.stderr | 8 +++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index e34b7799fb724..f69a78b1450f1 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(conservative_impl_trait, universal_impl_trait)] +#![feature(dyn_trait, conservative_impl_trait, universal_impl_trait)] use std::fmt::Debug; use std::option; @@ -40,4 +40,11 @@ fn projection_with_named_trait_inside_path_is_disallowed() (1i32..100).next().unwrap() } +fn projection_from_impl_trait_inside_dyn_trait_is_disallowed() + -> as Iterator>::Item +//~^ ERROR `impl Trait` is not allowed in path parameters +{ + panic!() +} + fn main() {} diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr index 2e8bfc931f82e..08de0eb99a307 100644 --- a/src/test/ui/impl_trait_projections.stderr +++ b/src/test/ui/impl_trait_projections.stderr @@ -16,6 +16,12 @@ error[E0667]: `impl Trait` is not allowed in path parameters 37 | -> <::std::ops::Range as Iterator>::Item | ^^^^^^^^^^ +error[E0667]: `impl Trait` is not allowed in path parameters + --> $DIR/impl_trait_projections.rs:44:29 + | +44 | -> as Iterator>::Item + | ^^^^^^^^^^ + error[E0223]: ambiguous associated type --> $DIR/impl_trait_projections.rs:23:50 | @@ -24,5 +30,5 @@ error[E0223]: ambiguous associated type | = note: specify the type using the syntax `::Item` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 9205f3d8e33fab70c89d0e283442c4b4d8b63b35 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 14 Feb 2018 02:15:27 -0500 Subject: [PATCH 12/42] macro-commas test cleanup --- src/test/run-pass/macro-comma-behavior.rs | 6 +++--- src/test/run-pass/macro-comma-support.rs | 18 ++---------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/test/run-pass/macro-comma-behavior.rs b/src/test/run-pass/macro-comma-behavior.rs index f8065f0ff148b..2a434009e134f 100644 --- a/src/test/run-pass/macro-comma-behavior.rs +++ b/src/test/run-pass/macro-comma-behavior.rs @@ -44,12 +44,12 @@ fn debug_assert_1arg() { // make sure we don't accidentally forward to `write!("text")` #[cfg(std)] #[test] -fn writeln_2arg() { +fn writeln_1arg() { use fmt::Write; let mut s = String::new(); - writeln!(&mut s, "hi",).unwrap(); - assert_eq!(&s, "hi\n"); + writeln!(&mut s,).unwrap(); + assert_eq!(&s, "\n"); } // A number of format_args-like macros have special-case treatment diff --git a/src/test/run-pass/macro-comma-support.rs b/src/test/run-pass/macro-comma-support.rs index f73dfb7b3b1d4..7d3f16728b279 100644 --- a/src/test/run-pass/macro-comma-support.rs +++ b/src/test/run-pass/macro-comma-support.rs @@ -8,15 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This is a comprehensive test of invocations with and without +// This is meant to be a comprehensive test of invocations with/without // trailing commas (or other, similar optionally-trailing separators). // Every macro is accounted for, even those not tested in this file. // (There will be a note indicating why). -// -// The expectation is for this to be updated as new macros are added, -// or as functionality is added to existing macros. -// -// (FIXME: (please discuss in PR) is the above expectation reasonable?) // std and core are both tested because they may contain separate // implementations for some macro_rules! macros as an implementation @@ -245,16 +240,7 @@ fn println() { println!("hello {}", "world",); } -// FIXME: select! (please discuss in PR) -// -// Test cases for select! are obnoxiously large, see here: -// -// https://github.com/ExpHP/rust-macro-comma-test/blob/0062e75e01ab/src/main.rs#L190-L250 -// -// and due to other usability issues described there, it is unclear to me that it is -// going anywhere in its current state. This is a job far too big for a macro_rules! macro, -// and for as long as it exists in this form it will have many many problems far worse than -// just lack of trailing comma support. +// select! is too troublesome and unlikely to be stabilized // stringify! is N/A From d4b847504c2ecf32637486987ac299f91a3d1c54 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Feb 2018 17:40:46 +0100 Subject: [PATCH 13/42] incr.comp.: Store DepNode colors in a dense array instead of a hashmap. --- src/librustc/dep_graph/graph.rs | 148 ++++++++++++++++++++++--------- src/librustc/dep_graph/prev.rs | 5 ++ src/librustc/ty/maps/plumbing.rs | 6 +- 3 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 55ec8adb5fbf3..b77431e806a6d 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -74,7 +74,7 @@ struct DepGraphData { /// nodes and edges as well as all fingerprints of nodes that have them. previous: PreviousDepGraph, - colors: RefCell>, + colors: RefCell, /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we @@ -97,8 +97,10 @@ impl DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. + let prev_graph_node_count = prev_graph.node_count(); + let fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, - (prev_graph.node_count() * 115) / 100); + (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Rc::new(DepGraphData { previous_work_products: RefCell::new(FxHashMap()), @@ -106,7 +108,7 @@ impl DepGraph { dep_node_debug: RefCell::new(FxHashMap()), current: RefCell::new(CurrentDepGraph::new()), previous: prev_graph, - colors: RefCell::new(FxHashMap()), + colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)), loaded_from_cache: RefCell::new(FxHashMap()), })), fingerprints: Rc::new(RefCell::new(fingerprints)), @@ -213,8 +215,6 @@ impl DepGraph { R: HashStable, { if let Some(ref data) = self.data { - debug_assert!(!data.colors.borrow().contains_key(&key)); - push(&data.current, key); if cfg!(debug_assertions) { profq_msg(ProfileQueriesMsg::TaskBegin(key.clone())) @@ -254,19 +254,21 @@ impl DepGraph { } // Determine the color of the new DepNode. - { - let prev_fingerprint = data.previous.fingerprint_of(&key); + if let Some(prev_index) = data.previous.node_to_index_opt(&key) { + let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - let color = if Some(current_fingerprint) == prev_fingerprint { + let color = if current_fingerprint == prev_fingerprint { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }; - let old_value = data.colors.borrow_mut().insert(key, color); - debug_assert!(old_value.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_index).is_none(), "DepGraph::with_task() - Duplicate DepNodeColor \ insertion for {:?}", key); + + colors.insert(prev_index, color); } (result, dep_node_index) @@ -281,9 +283,11 @@ impl DepGraph { let mut fingerprints = self.fingerprints.borrow_mut(); let dep_node_index = DepNodeIndex::new(fingerprints.len()); fingerprints.push(fingerprint); + debug_assert!(fingerprints[dep_node_index] == fingerprint, "DepGraph::with_task() - Assigned fingerprint to \ unexpected index for {:?}", key); + (result, dep_node_index) } else { (task(cx, arg), DepNodeIndex::INVALID) @@ -356,6 +360,15 @@ impl DepGraph { .unwrap() } + #[inline] + pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool { + if let Some(ref data) = self.data { + data.current.borrow_mut().node_to_node_index.contains_key(dep_node) + } else { + false + } + } + #[inline] pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { match self.fingerprints.borrow().get(dep_node_index) { @@ -495,7 +508,17 @@ impl DepGraph { } pub fn node_color(&self, dep_node: &DepNode) -> Option { - self.data.as_ref().and_then(|data| data.colors.borrow().get(dep_node).cloned()) + if let Some(ref data) = self.data { + if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { + return data.colors.borrow().get(prev_index) + } else { + // This is a node that did not exist in the previous compilation + // session, so we consider it to be red. + return Some(DepNodeColor::Red) + } + } + + None } pub fn try_mark_green<'tcx>(&self, @@ -505,7 +528,6 @@ impl DepGraph { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); - debug_assert!(!data.colors.borrow().contains_key(dep_node)); debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); if dep_node.kind.is_input() { @@ -535,19 +557,22 @@ impl DepGraph { } }; + debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); + let mut current_deps = Vec::new(); for &dep_dep_node_index in prev_deps { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); - let dep_dep_node_color = data.colors.borrow().get(dep_dep_node).cloned(); match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. debug!("try_mark_green({:?}) --- found dependency {:?} to \ - be immediately green", dep_node, dep_dep_node); + be immediately green", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); current_deps.push(node_index); } Some(DepNodeColor::Red) => { @@ -556,10 +581,14 @@ impl DepGraph { // mark the DepNode as green and also don't need to bother // with checking any of the other dependencies. debug!("try_mark_green({:?}) - END - dependency {:?} was \ - immediately red", dep_node, dep_dep_node); + immediately red", + dep_node, + data.previous.index_to_node(dep_dep_node_index)); return None } None => { + let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); + // We don't know the state of this dependency. If it isn't // an input node, let's try to mark it green recursively. if !dep_dep_node.kind.is_input() { @@ -601,10 +630,8 @@ impl DepGraph { debug!("try_mark_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors - .borrow() - .get(dep_dep_node) - .cloned(); + let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); + match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { debug!("try_mark_green({:?}) --- managed to \ @@ -681,26 +708,21 @@ impl DepGraph { } // ... and finally storing a "Green" entry in the color map. - let old_color = data.colors - .borrow_mut() - .insert(*dep_node, DepNodeColor::Green(dep_node_index)); - debug_assert!(old_color.is_none(), + let mut colors = data.colors.borrow_mut(); + debug_assert!(colors.get(prev_dep_node_index).is_none(), "DepGraph::try_mark_green() - Duplicate DepNodeColor \ insertion for {:?}", dep_node); + colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } - // Used in various assertions - pub fn is_green(&self, dep_node_index: DepNodeIndex) -> bool { - let dep_node = self.data.as_ref().unwrap().current.borrow().nodes[dep_node_index]; - self.data.as_ref().unwrap().colors.borrow().get(&dep_node).map(|&color| { - match color { - DepNodeColor::Red => false, - DepNodeColor::Green(_) => true, - } - }).unwrap_or(false) + // Returns true if the given node has been marked as green during the + // current compilation session. Used in various assertions + pub fn is_green(&self, dep_node: &DepNode) -> bool { + self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) } // This method loads all on-disk cacheable query results into memory, so @@ -714,20 +736,25 @@ impl DepGraph { pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { let green_nodes: Vec = { let data = self.data.as_ref().unwrap(); - data.colors.borrow().iter().filter_map(|(dep_node, color)| match color { - DepNodeColor::Green(_) => { - if dep_node.cache_on_disk(tcx) { - Some(*dep_node) - } else { + let colors = data.colors.borrow(); + colors.values.indices().filter_map(|prev_index| { + match colors.get(prev_index) { + Some(DepNodeColor::Green(_)) => { + let dep_node = data.previous.index_to_node(prev_index); + if dep_node.cache_on_disk(tcx) { + Some(dep_node) + } else { + None + } + } + None | + Some(DepNodeColor::Red) => { + // We can skip red nodes because a node can only be marked + // as red if the query result was recomputed and thus is + // already in memory. None } } - DepNodeColor::Red => { - // We can skip red nodes because a node can only be marked - // as red if the query result was recomputed and thus is - // already in memory. - None - } }).collect() }; @@ -1052,3 +1079,36 @@ enum OpenTask { node: DepNode, }, } + +// A data structure that stores Option values as a contiguous +// array, using one u32 per entry. +struct DepNodeColorMap { + values: IndexVec, +} + +const COMPRESSED_NONE: u32 = 0; +const COMPRESSED_RED: u32 = 1; +const COMPRESSED_FIRST_GREEN: u32 = 2; + +impl DepNodeColorMap { + fn new(size: usize) -> DepNodeColorMap { + DepNodeColorMap { + values: IndexVec::from_elem_n(COMPRESSED_NONE, size) + } + } + + fn get(&self, index: SerializedDepNodeIndex) -> Option { + match self.values[index] { + COMPRESSED_NONE => None, + COMPRESSED_RED => Some(DepNodeColor::Red), + value => Some(DepNodeColor::Green(DepNodeIndex(value - COMPRESSED_FIRST_GREEN))) + } + } + + fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) { + self.values[index] = match color { + DepNodeColor::Red => COMPRESSED_RED, + DepNodeColor::Green(index) => index.0 + COMPRESSED_FIRST_GREEN, + } + } +} diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 50e1ee88a4614..504b60e763e23 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -49,6 +49,11 @@ impl PreviousDepGraph { self.index[dep_node] } + #[inline] + pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { + self.index.get(dep_node).cloned() + } + #[inline] pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option { self.index diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..956348edcce65 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { Some(dep_node_index) => { - debug_assert!(self.dep_graph.is_green(dep_node_index)); + debug_assert!(self.dep_graph.is_green(&dep_node)); self.dep_graph.read_index(dep_node_index); Some(dep_node_index) } @@ -390,7 +390,7 @@ macro_rules! define_maps { dep_node: &DepNode) -> Result<$V, CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.is_green(dep_node_index)); + debug_assert!(tcx.dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache let result = if Self::cache_on_disk(key) && @@ -478,7 +478,7 @@ macro_rules! define_maps { span: Span, dep_node: DepNode) -> Result<($V, DepNodeIndex), CycleError<'a, $tcx>> { - debug_assert!(tcx.dep_graph.node_color(&dep_node).is_none()); + debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node)); profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); let res = tcx.cycle_check(span, Query::$name(key), || { From 9e9c55f8fd064335cadc28bd9a0152538dcc9fa0 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 14 Feb 2018 10:22:12 -0800 Subject: [PATCH 14/42] Update E0657 stderr to match changed test --- src/test/ui/error-codes/E0657.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/error-codes/E0657.stderr b/src/test/ui/error-codes/E0657.stderr index d3b53d37a30a0..e039d645fa6db 100644 --- a/src/test/ui/error-codes/E0657.stderr +++ b/src/test/ui/error-codes/E0657.stderr @@ -1,14 +1,14 @@ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:20:32 + --> $DIR/E0657.rs:20:31 | -20 | -> impl for<'a> Id> - | ^^ +20 | -> Box Id>> + | ^^ error[E0657]: `impl Trait` can only capture lifetimes bound at the fn or impl level - --> $DIR/E0657.rs:29:36 + --> $DIR/E0657.rs:29:35 | -29 | -> impl for<'a> Id> - | ^^ +29 | -> Box Id>> + | ^^ error: aborting due to 2 previous errors From f787bddcff700a139a0acdc815b4e5b0d641fad9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Feb 2018 16:11:02 +0100 Subject: [PATCH 15/42] Turn features() into a query. --- src/librustc/dep_graph/dep_node.rs | 10 +-- src/librustc/hir/lowering.rs | 6 +- src/librustc/ich/impls_syntax.rs | 19 ++++++ src/librustc/infer/error_reporting/mod.rs | 4 +- src/librustc/middle/stability.rs | 14 ++-- src/librustc/session/mod.rs | 66 ++++++------------- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc/ty/context.rs | 64 ++++++++++++++++-- src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 8 +++ src/librustc/ty/maps/plumbing.rs | 1 + src/librustc/ty/mod.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/_match.rs | 4 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_driver/driver.rs | 10 +-- src/librustc_incremental/assert_dep_graph.rs | 2 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_metadata/native_libs.rs | 4 +- src/librustc_mir/borrow_check/mod.rs | 10 +-- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/matches/simplify.rs | 2 +- .../transform/clean_end_regions.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/util/borrowck_errors.rs | 2 +- src/librustc_plugin/load.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 6 +- src/librustc_resolve/macros.rs | 4 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_trans_utils/symbol_names_test.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 6 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 17 +++-- src/libsyntax/ext/tt/quoted.rs | 15 ++--- src/libsyntax/feature_gate.rs | 7 ++ 47 files changed, 202 insertions(+), 135 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..d1734e214d561 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -436,6 +436,9 @@ impl DepKind { } define_dep_nodes!( <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + // Represents the `Krate` as a whole (the `hir::Krate` value) (as // distinct from the krate module). This is basically a hash of // the entire krate, so if you read from `Krate` (e.g., by calling @@ -605,8 +608,8 @@ define_dep_nodes!( <'tcx> [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - [input] HasCloneClosures(CrateNum), - [input] HasCopyClosures(CrateNum), + [] HasCloneClosures(CrateNum), + [] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a @@ -630,8 +633,6 @@ define_dep_nodes!( <'tcx> [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [anon] NormalizeTy, - // We use this for most things when incr. comp. is turned off. - [] Null, [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -642,6 +643,7 @@ define_dep_nodes!( <'tcx> [] GetSymbolExportLevel(DefId), + [input] Features, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 55dcb16c3c95f..974ee99efabbe 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -550,7 +550,7 @@ impl<'a> LoweringContext<'a> { { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); - self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes; + self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes; assert!(self.in_band_ty_params.is_empty()); @@ -957,7 +957,7 @@ impl<'a> LoweringContext<'a> { let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features.borrow().conservative_impl_trait; + let has_feature = self.sess.features_untracked().conservative_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait", t.span, GateIssue::Language, @@ -981,7 +981,7 @@ impl<'a> LoweringContext<'a> { }, lifetimes) }, ImplTraitContext::Universal(def_id) => { - let has_feature = self.sess.features.borrow().universal_impl_trait; + let has_feature = self.sess.features_untracked().universal_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "universal_impl_trait", t.span, GateIssue::Language, diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c31a5c9d86d77..f935cbfcde992 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -17,6 +17,7 @@ use std::hash as std_hash; use std::mem; use syntax::ast; +use syntax::feature_gate; use syntax::parse::token; use syntax::symbol::InternedString; use syntax::tokenstream; @@ -460,3 +461,21 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, (pos.0 - filemap_start.0, width as u32) } + + + +impl<'gcx> HashStable> for feature_gate::Features { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_stable_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 03fc40b2e39fc..ae740707da5d6 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -262,11 +262,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { will_later_be_reported_by_nll: bool) { debug!("report_region_errors(): {} errors to start", errors.len()); - if will_later_be_reported_by_nll && self.tcx.sess.nll() { + if will_later_be_reported_by_nll && self.tcx.nll() { // With `#![feature(nll)]`, we want to present a nice user // experience, so don't even mention the errors from the // AST checker. - if self.tcx.sess.features.borrow().nll { + if self.tcx.features().nll { return; } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e80ea16f565ab..16c33d6bd837d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, visit_children: F) where F: FnOnce(&mut Self) { - if self.tcx.sess.features.borrow().staged_api { + if self.tcx.features().staged_api { // This crate explicitly wants staged API. debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { @@ -398,7 +398,7 @@ impl<'a, 'tcx> Index<'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || - tcx.sess.features.borrow().staged_api; + tcx.features().staged_api; let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); let mut index = Index { @@ -408,7 +408,7 @@ impl<'a, 'tcx> Index<'tcx> { active_features: FxHashSet(), }; - let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; + let ref active_lib_features = tcx.features().declared_lib_features; // Put the active features into a map for quick lookup index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); @@ -677,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => { + hir::ItemUnion(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); @@ -721,8 +721,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let sess = &tcx.sess; - let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability().staged_api[&LOCAL_CRATE] { @@ -736,12 +734,12 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { krate.visit_all_item_likes(&mut missing.as_deep_visitor()); } - let ref declared_lib_features = sess.features.borrow().declared_lib_features; + let ref declared_lib_features = tcx.features().declared_lib_features; let mut remaining_lib_features: FxHashMap = declared_lib_features.clone().into_iter().collect(); remaining_lib_features.remove(&Symbol::intern("proc_macro")); - for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features { + for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features { let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str()) .expect("unexpectedly couldn't find version feature was stabilized"); tcx.lint_node(lint::builtin::STABLE_FEATURES, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9d7a9acc3d533..bcffce80911f7 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -19,7 +19,7 @@ use lint; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch}; +use session::config::{DebugInfoLevel, OutputType, Epoch}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -91,7 +91,8 @@ pub struct Session { /// multiple crates with the same name to coexist. See the /// trans::back::symbol_names module for more information. pub crate_disambiguator: RefCell>, - pub features: RefCell, + + features: RefCell>, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. @@ -192,6 +193,7 @@ impl Session { None => bug!("accessing disambiguator before initialization"), } } + pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -443,16 +445,22 @@ impl Session { self.opts.debugging_opts.print_llvm_passes } - /// If true, we should use NLL-style region checking instead of - /// lexical style. - pub fn nll(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.nll + /// Get the features enabled for the current compilation session. Do not use + /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents + /// dependency tracking. Use tcx.features() instead. + #[inline] + pub fn features_untracked(&self) -> cell::Ref { + let features = self.features.borrow(); + + if features.is_none() { + bug!("Access to Session::features before it is initialized"); + } + + cell::Ref::map(features, |r| r.as_ref().unwrap()) } - /// If true, we should use the MIR-based borrowck (we may *also* use - /// the AST-based borrowck). - pub fn use_mir(&self) -> bool { - self.borrowck_mode().use_mir() + pub fn init_features(&self, features: feature_gate::Features) { + *(self.features.borrow_mut()) = Some(features); } /// If true, we should gather causal information during NLL @@ -462,42 +470,6 @@ impl Session { self.opts.debugging_opts.nll_dump_cause } - /// If true, we should enable two-phase borrows checks. This is - /// done with either `-Ztwo-phase-borrows` or with - /// `#![feature(nll)]`. - pub fn two_phase_borrows(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.two_phase_borrows - } - - /// What mode(s) of borrowck should we run? AST? MIR? both? - /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { - match self.opts.borrowck_mode { - mode @ BorrowckMode::Mir | - mode @ BorrowckMode::Compare => mode, - - mode @ BorrowckMode::Ast => { - if self.nll() { - BorrowckMode::Mir - } else { - mode - } - } - - } - } - - /// Should we emit EndRegion MIR statements? These are consumed by - /// MIR borrowck, but not when NLL is used. They are also consumed - /// by the validation stuff. - pub fn emit_end_regions(&self) -> bool { - // FIXME(#46875) -- we should not emit end regions when NLL is enabled, - // but for now we can't stop doing so because it causes false positives - self.opts.debugging_opts.emit_end_regions || - self.opts.debugging_opts.mir_emit_validate > 0 || - self.use_mir() - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -1009,7 +981,7 @@ pub fn build_session_(sopts: config::Options, crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FxHashMap()), crate_disambiguator: RefCell::new(None), - features: RefCell::new(feature_gate::Features::new()), + features: RefCell::new(None), recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index afe29cc0e7baf..1d0b40f44c05d 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -162,7 +162,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.sess.features.borrow().specialization && + if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..d01bfcefbb7f1 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::OutputFilenames; +use session::config::{BorrowckMode, OutputFilenames}; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -71,6 +71,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; @@ -1251,6 +1252,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.stability_index(LOCAL_CRATE) } + pub fn features(self) -> Rc { + self.features_query(LOCAL_CRATE) + } + pub fn crates(self) -> Rc> { self.all_crate_nums(LOCAL_CRATE) } @@ -1362,6 +1367,53 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) } + /// If true, we should use NLL-style region checking instead of + /// lexical style. + pub fn nll(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.nll + } + + /// If true, we should use the MIR-based borrowck (we may *also* use + /// the AST-based borrowck). + pub fn use_mir(self) -> bool { + self.borrowck_mode().use_mir() + } + + /// If true, we should enable two-phase borrows checks. This is + /// done with either `-Ztwo-phase-borrows` or with + /// `#![feature(nll)]`. + pub fn two_phase_borrows(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows + } + + /// What mode(s) of borrowck should we run? AST? MIR? both? + /// (Also considers the `#![feature(nll)]` setting.) + pub fn borrowck_mode(&self) -> BorrowckMode { + match self.sess.opts.borrowck_mode { + mode @ BorrowckMode::Mir | + mode @ BorrowckMode::Compare => mode, + + mode @ BorrowckMode::Ast => { + if self.nll() { + BorrowckMode::Mir + } else { + mode + } + } + + } + } + + /// Should we emit EndRegion MIR statements? These are consumed by + /// MIR borrowck, but not when NLL is used. They are also consumed + /// by the validation stuff. + pub fn emit_end_regions(self) -> bool { + // FIXME(#46875) -- we should not emit end regions when NLL is enabled, + // but for now we can't stop doing so because it causes false positives + self.sess.opts.debugging_opts.emit_end_regions || + self.sess.opts.debugging_opts.mir_emit_validate > 0 || + self.use_mir() + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -2020,7 +2072,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.sess.features.borrow().never_type { + if self.features().never_type { self.types.never } else { self.intern_tup(&[], true) @@ -2395,13 +2447,17 @@ pub fn provide(providers: &mut ty::maps::Providers) { }; providers.has_copy_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().copy_closures + tcx.features().copy_closures }; providers.has_clone_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().clone_closures + tcx.features().clone_closures }; providers.fully_normalize_monormophic_ty = |tcx, ty| { tcx.fully_normalize_associated_types_in(&ty) }; + providers.features_query = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Rc::new(tcx.sess.features_untracked().clone()) + }; } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f26..c91b30440e5e3 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -593,6 +593,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'t } } +impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up enabled feature gates") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 85fca68187fe6..887b51113b502 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -52,6 +52,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; +use syntax::feature_gate; use syntax::symbol::Symbol; #[macro_use] @@ -369,12 +370,19 @@ define_maps! { <'tcx> // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) -> usize, + + [] fn features_query: features_node(CrateNum) -> Rc, } ////////////////////////////////////////////////////////////////////// // These functions are little shims used to find the dep-node for a // given query when there is not a *direct* mapping: + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::EraseRegionsTy { ty } } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 0ab6ee1a54a9b..ffc51c28f0b63 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -923,6 +923,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } + DepKind::Features => { force!(features_query, LOCAL_CRATE); } } true diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9fc8..07d886edb2059 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2270,7 +2270,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { - if !self.sess.features.borrow().overlapping_marker_traits { + if !self.features().overlapping_marker_traits { return false; } let trait1_is_empty = self.impl_trait_ref(def_id1) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 738c0d82ee1b5..d07686960d0b7 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -275,7 +275,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.tcx.sess.borrowck_mode()) { + if !o.should_emit_errors(self.tcx.borrowck_mode()) { self.tcx.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index a7c382eba5091..4db460f43c508 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -227,7 +227,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index ae53ed0e1140d..6f7143c185cb3 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14bae..2a571fa82643b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -398,7 +398,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }).collect::, _>>()?)))) } hir::ExprIndex(ref arr, ref idx) => { - if !tcx.sess.features.borrow().const_indexing { + if !tcx.features().const_indexing { signal!(e, IndexOpFeatureGated); } let arr = cx.eval(arr)?; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f344624666a6c..9d358c439db6b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -648,7 +648,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test); // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; + sess.init_features(features); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -688,7 +688,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); time(time_passes, "plugin registration", || { - if sess.features.borrow().rustc_diagnostic_macros { + if sess.features_untracked().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); registry.register_macro("__register_diagnostic", @@ -738,7 +738,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, crate_loader, &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; - syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -769,7 +769,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, .filter(|p| env::join_paths(iter::once(p)).is_ok())) .unwrap()); } - let features = sess.features.borrow(); + let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), recursion_limit: sess.recursion_limit.get(), @@ -874,7 +874,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.track_errors(|| { syntax::feature_gate::check_crate(&krate, &sess.parse_sess, - &sess.features.borrow(), + &sess.features_untracked(), &attributes, sess.opts.unstable_features); }) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 5976b80d90f87..17a6176b79e95 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -69,7 +69,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c3e283535ec82..e114606a63115 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -219,7 +219,7 @@ impl Assertion { pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index de55710bdf3d0..ea136475dba4f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1355,7 +1355,7 @@ impl UnreachablePub { // visibility is token at start of declaration (can be macro // variable rather than literal `pub`) let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); - let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + let replacement = if cx.tcx.features().crate_visibility_modifier { "crate" } else { "pub(crate)" diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 439533fae49d9..6ab3172c4fefa 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.sess.features.borrow().fn_must_use { + if cx.tcx.features().fn_must_use { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { match callee.node { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index c0ce32cc97068..2504f8dc251f9 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { None => self.tcx.sess.err(msg), } } - if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg { + if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "link_cfg", span.unwrap(), @@ -154,7 +154,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { "is feature gated"); } if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.sess.features.borrow().static_nobundle { + !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "static_nobundle", span.unwrap(), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c4df7349391e2..622cf04c71a9e 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -72,7 +72,7 @@ fn mir_borrowck<'a, 'tcx>( let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.use_mir() { + if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() { return None; } @@ -101,7 +101,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // contain non-lexical lifetimes. It will have a lifetime tied // to the inference context. let mut mir: Mir<'tcx> = input_mir.clone(); - let free_regions = if !tcx.sess.nll() { + let free_regions = if !tcx.nll() { None } else { let mir = &mut mir; @@ -204,7 +204,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( ); (Some(Rc::new(regioncx)), opt_closure_req) } else { - assert!(!tcx.sess.nll()); + assert!(!tcx.nll()); (None, None) }; let flow_inits = flow_inits; // remove mut @@ -712,7 +712,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// allowed to be split into separate Reservation and /// Activation phases. fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool { - self.tcx.sess.two_phase_borrows() && + self.tcx.two_phase_borrows() && (kind.allows_two_phase_borrow() || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } @@ -1187,7 +1187,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { span: Span, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { - if !self.tcx.sess.two_phase_borrows() { + if !self.tcx.two_phase_borrows() { return; } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 932aad0bb1d84..1ed8289d44184 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, region_scope: region::Scope) { - if tcx.sess.emit_end_regions() { + if tcx.emit_end_regions() { if let region::ScopeData::CallSite(_) = region_scope.data() { // The CallSite scope (aka the root scope) is sort of weird, in that it is // supposed to "separate" the "interior" and "exterior" of a closure. Being diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b16d7ed236509..abea55835466f 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().sess.features.borrow().never_type && + self.hir.tcx().features().never_type && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs index 7986313aa8134..6e8985d99d287 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -42,7 +42,7 @@ impl MirPass for CleanEndRegions { tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if !tcx.sess.emit_end_regions() { return; } + if !tcx.emit_end_regions() { return; } let mut gather = GatherBorrowedRegions { seen_regions: FxHashSet() diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2b9ee223b01a4..bb2dc9a7494f9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -904,7 +904,7 @@ This does not pose a problem by itself because they can't be accessed directly." if self.mode != Mode::Fn && // feature-gate is not enabled, - !self.tcx.sess.features.borrow() + !self.tcx.features() .declared_lib_features .iter() .any(|&(ref sym, _)| sym == feature_name) && diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 4a7ee397aec00..89242ca32bcbf 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -514,7 +514,7 @@ impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.sess.borrowck_mode()) { + if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a46b85d93cbb8..bf59165a9c461 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -52,7 +52,7 @@ pub fn load_plugins(sess: &Session, // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without // the feature enabled will result in an error later... - if sess.features.borrow().plugin { + if sess.features_untracked().plugin { for attr in &krate.attrs { if !attr.check_name("plugin") { continue; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c55bf395d71b3..7377adba6c14b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -590,7 +590,7 @@ impl<'a> Resolver<'a> { }; let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2da4bfedd3a17..ec0239272a677 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1523,7 +1523,7 @@ impl<'a> Resolver<'a> { invocations.insert(Mark::root(), arenas.alloc_invocation_data(InvocationData::root(graph_root))); - let features = session.features.borrow(); + let features = session.features_untracked(); let mut macro_defs = FxHashMap(); macro_defs.insert(Mark::root(), root_def_id); @@ -2994,7 +2994,7 @@ impl<'a> Resolver<'a> { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features.borrow().i128_type { + if !self.session.features_untracked().i128_type { emit_feature_err(&self.session.parse_sess, "i128_type", span, GateIssue::Language, "128-bit type is unstable"); @@ -3085,7 +3085,7 @@ impl<'a> Resolver<'a> { let prev_name = path[0].node.name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && - self.session.features.borrow().extern_absolute_paths { + self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); let crate_root = diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 080ef3252a633..69078d40045b6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -744,7 +744,7 @@ impl<'a> Resolver<'a> { let def_id = self.definitions.local_def_id(item.id); let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), item)); self.macro_map.insert(def_id, ext); @@ -838,7 +838,7 @@ impl<'a> Resolver<'a> { } fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) { - if !self.session.features.borrow().custom_derive { + if !self.session.features_untracked().custom_derive { let sess = &self.session.parse_sess; let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE; emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8cb25f449b667..d60638c0ee7ec 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -609,7 +609,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() || module_path[0].node.name == keywords::Extern.name()) { let is_extern = module_path[0].node.name == keywords::Extern.name() || - self.session.features.borrow().extern_absolute_paths; + self.session.features_untracked().extern_absolute_paths; match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs index 5d7d4f3055bad..267c8d2bd03c8 100644 --- a/src/librustc_trans_utils/symbol_names_test.rs +++ b/src/librustc_trans_utils/symbol_names_test.rs @@ -28,7 +28,7 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1139ea5fbd364..b94917ae04dc8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -417,7 +417,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); - if !self.tcx().sess.features.borrow().unboxed_closures && + if !self.tcx().features().unboxed_closures && trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index bf253a88d27c2..bb6ed89433562 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; if pat_adjustments.len() > 0 { - if tcx.sess.features.borrow().match_default_bindings { + if tcx.features().match_default_bindings { debug!("default binding mode is now {:?}", def_bm); self.inh.tables.borrow_mut() .pat_adjustments_mut() diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 47e4b0272bed4..3a153bafe8f50 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -585,7 +585,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "unsized_tuple_coercion", self.cause.span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e8c3966f23f08..f3850da0ba557 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // possible that there will be multiple applicable methods. if !is_suggestion.0 { if reached_raw_pointer - && !self.tcx.sess.features.borrow().arbitrary_self_types { + && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 epoch // (see https://github.com/rust-lang/rust/issues/46906) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 165b499cc62aa..73e24ff5252df 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1089,7 +1089,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.sess.features.borrow().termination_trait { + if fcx.tcx.features().termination_trait { // If the termination trait language item is activated, check that the main return type // implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { @@ -1600,7 +1600,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let repr_type_ty = def.repr.discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.sess.features.borrow().repr128 { + if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, "repr128", sp, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3668fc46ddc27..e2d640fd67e6b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -471,7 +471,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); - if !fcx.tcx.sess.features.borrow().arbitrary_self_types { + if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f65d627781f0f..d3de31d630a97 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -74,7 +74,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } - if tcx.sess.features.borrow().unboxed_closures { + if tcx.features().unboxed_closures { // the feature gate allows all Fn traits return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c2240..8234dc95c7996 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -711,7 +711,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); - if paren_sugar && !tcx.sess.features.borrow().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ @@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if !allow_defaults && p.default.is_some() { - if !tcx.sess.features.borrow().default_type_parameter_fallback { + if !tcx.features().default_type_parameter_fallback { tcx.lint_node( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, p.id, @@ -1674,7 +1674,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic - && !tcx.sess.features.borrow().simd_ffi { + && !tcx.features().simd_ffi { let check = |ast_ty: &hir::Ty, ty: Ty| { if ty.is_simd() { tcx.sess.struct_span_err(ast_ty.span, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bd7e200d620e6..01ceb8eb29151 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -207,7 +207,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let actual = tcx.fn_sig(main_def_id); let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.sess.features.borrow().termination_trait { + && tcx.features().termination_trait { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 087d88419bc84..b1dd3db9d861d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -665,7 +665,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { nested: F) { let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs); if let Some(ref cfg) = attrs.cfg { - if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) { + if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 5254c751e6b62..f8c95ae17bf31 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -26,7 +26,6 @@ use parse::token::Token::*; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; -use std::cell::RefCell; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::rc::Rc; @@ -183,7 +182,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -295,7 +294,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) } fn check_lhs_nt_follows(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the @@ -352,7 +351,7 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { } fn check_matcher(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); @@ -600,7 +599,7 @@ impl TokenSet { // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, matcher: &[quoted::TokenTree], @@ -868,7 +867,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result, + features: &Features, attrs: &[ast::Attribute], tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); @@ -883,7 +882,7 @@ fn has_legal_fragment_specifier(sess: &ParseSess, } fn is_legal_fragment_specifier(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], frag_name: &str, frag_span: Span) -> bool { @@ -891,7 +890,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, "lifetime" => { - if !features.borrow().macro_lifetime_matcher && + if !features.macro_lifetime_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; emit_feature_err(sess, @@ -903,7 +902,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, true }, "vis" => { - if !features.borrow().macro_vis_matcher && + if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_VIS_MATCHER; emit_feature_err(sess, diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 982b60b81e47e..c6484e9a7706a 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -17,7 +17,6 @@ use symbol::keywords; use syntax_pos::{BytePos, Span, DUMMY_SP}; use tokenstream; -use std::cell::RefCell; use std::iter::Peekable; use std::rc::Rc; @@ -183,7 +182,7 @@ pub fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> Vec { // Will contain the final collection of `self::TokenTree` @@ -251,7 +250,7 @@ fn parse_tree( trees: &mut Peekable, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> TokenTree where @@ -382,7 +381,7 @@ fn parse_sep_and_kleene_op( input: &mut Peekable, span: Span, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> (Option, KleeneOp) where @@ -415,7 +414,7 @@ where match parse_kleene_op(input, span) { // #2 is a KleeneOp (this is the only valid option) :) Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -438,7 +437,7 @@ where Err(span) => span, } } else { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -460,7 +459,7 @@ where Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -487,7 +486,7 @@ where Err(span) => span, }; - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { sess.span_diagnostic diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ea916d5168c33..8369520d0d6e5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -62,6 +62,7 @@ macro_rules! declare_features { &[$((stringify!($feature), $ver, $issue, set!($feature))),+]; /// A set of features to be used by later passes. + #[derive(Clone)] pub struct Features { /// `#![feature]` attrs for stable language features, for error reporting pub declared_stable_lang_features: Vec<(Symbol, Span)>, @@ -78,6 +79,12 @@ macro_rules! declare_features { $($feature: false),+ } } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } } }; From c0517a38aced792365af440e9140d91518b9bb45 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Feb 2018 16:26:56 +0100 Subject: [PATCH 16/42] incr.comp.: Add regression test for detecting feature gate changes. --- src/test/incremental/feature_gate.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/incremental/feature_gate.rs diff --git a/src/test/incremental/feature_gate.rs b/src/test/incremental/feature_gate.rs new file mode 100644 index 0000000000000..de2f9ab52f60b --- /dev/null +++ b/src/test/incremental/feature_gate.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test makes sure that we detect changed feature gates. + +// revisions:rpass1 cfail2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![cfg_attr(rpass1, feature(nll))] + +fn main() { + let mut v = vec![1]; + v.push(v[0]); + //[cfail2]~^ ERROR cannot borrow +} From fe0260fbf892d5b49e79ee310b5e198c72c3d576 Mon Sep 17 00:00:00 2001 From: Federico Poli Date: Thu, 15 Feb 2018 15:04:43 +0100 Subject: [PATCH 17/42] mir: Gather move at SwitchInt, Assert terminators Previously, "_1" was not marked as "definitely uninitialized" after a "switchInt(move _1)" terminator. Related discussion: https://internals.rust-lang.org/t/why-is-2-definitely-initialized-after-switchint-move-2/6760 --- src/librustc_mir/dataflow/move_paths/builder.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 635d99e7737a9..d6f419f6cfb41 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -353,9 +353,12 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { self.gather_move(&Place::Local(RETURN_PLACE)); } - TerminatorKind::Assert { .. } | - TerminatorKind::SwitchInt { .. } => { - // branching terminators - these don't move anything + TerminatorKind::Assert { ref cond, .. } => { + self.gather_operand(cond); + } + + TerminatorKind::SwitchInt { ref discr, .. } => { + self.gather_operand(discr); } TerminatorKind::Yield { ref value, .. } => { From d691c463f6248e20e0dbf57745fee07a5b1eb5a8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Feb 2018 15:53:26 +0100 Subject: [PATCH 18/42] Fix procedural_mbe_matching test case after libsyntax change. --- src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 9ebc438ad5a00..fd8f7b9e384f3 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -41,7 +41,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(), true, cx.parse_sess, - &RefCell::new(Features::new()), + &Features::new(), &[]); let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) { Success(map) => map, From b9fa2dac25786e67d8332dfa3fe7524ba4c196b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 15 Feb 2018 14:42:22 -0800 Subject: [PATCH 19/42] Avoid ICE in arg mistmatch error for tuple variants --- src/librustc/traits/error_reporting.rs | 15 ++++++++++++++- src/test/ui/issue-47706.rs | 15 +++++++++++++++ src/test/ui/issue-47706.stderr | 21 +++++++++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a290839425ebe..43a3269fa52d5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -756,7 +756,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }).collect(), ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))], }; - if found.len()== expected.len() { + if found.len() == expected.len() { self.report_closure_arg_mismatch(span, found_span, found_trait_ref, @@ -870,6 +870,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) }).collect::>()) } + hir::map::NodeVariant(&hir::Variant { + span, + node: hir::Variant_ { + data: hir::VariantData::Tuple(ref fields, _), + .. + }, + .. + }) => { + (self.tcx.sess.codemap().def_span(span), + fields.iter().map(|field| { + ArgKind::Arg(format!("{}", field.name), "_".to_string()) + }).collect::>()) + } _ => panic!("non-FnLike node found: {:?}", node), } } diff --git a/src/test/ui/issue-47706.rs b/src/test/ui/issue-47706.rs index 24a0f66f5b1c4..9c521dd647963 100644 --- a/src/test/ui/issue-47706.rs +++ b/src/test/ui/issue-47706.rs @@ -22,3 +22,18 @@ impl Foo { } //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593] } + +enum Qux { + Bar(i32), +} + +fn foo(f: F) +where + F: Fn(), +{ +} + +fn main() { + foo(Qux::Bar); +} +//~^^ ERROR function is expected to take 0 arguments, but it takes 1 argument [E0593] diff --git a/src/test/ui/issue-47706.stderr b/src/test/ui/issue-47706.stderr index 0916dc64292e3..e197c09062d1c 100644 --- a/src/test/ui/issue-47706.stderr +++ b/src/test/ui/issue-47706.stderr @@ -1,5 +1,3 @@ -error[E0601]: main function not found - error[E0593]: function is expected to take 1 argument, but it takes 2 arguments --> $DIR/issue-47706.rs:21:18 | @@ -9,5 +7,24 @@ error[E0593]: function is expected to take 1 argument, but it takes 2 arguments 21 | self.foo.map(Foo::new) | ^^^ expected function that takes 1 argument +error[E0593]: function is expected to take 0 arguments, but it takes 1 argument + --> $DIR/issue-47706.rs:37:5 + | +27 | Bar(i32), + | -------- takes 1 argument +... +37 | foo(Qux::Bar); + | ^^^ expected function that takes 0 arguments + | +note: required by `foo` + --> $DIR/issue-47706.rs:30:1 + | +30 | / fn foo(f: F) +31 | | where +32 | | F: Fn(), +33 | | { +34 | | } + | |_^ + error: aborting due to 2 previous errors From 10fbdb832b2ad5807b89a005f9d4bccaec231fb1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 16 Feb 2018 16:45:37 +1300 Subject: [PATCH 20/42] save-analysis: power through bracket mis-counts Closes #47981 This is pretty unsatisfying since it is working around a span bug. However, I can't track down the span bug and it could be in the parser, proc macro expansion, the user macro, or Syn (or any other library that can manipulate spans). Given that user code can cause this error, I think we need to be more robust here. --- src/librustc_save_analysis/span_utils.rs | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 25e81e6f326e1..d5a58c08cbe5a 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -115,7 +115,7 @@ impl<'a> SpanUtils<'a> { // We keep track of the following two counts - the depth of nesting of // angle brackets, and the depth of nesting of square brackets. For the // angle bracket count, we only count tokens which occur outside of any - // square brackets (i.e. bracket_count == 0). The intutition here is + // square brackets (i.e. bracket_count == 0). The intuition here is // that we want to count angle brackets in the type, but not any which // could be in expression context (because these could mean 'less than', // etc.). @@ -151,18 +151,20 @@ impl<'a> SpanUtils<'a> { } prev = next; } - if angle_count != 0 || bracket_count != 0 { - let loc = self.sess.codemap().lookup_char_pos(span.lo()); - span_bug!( - span, - "Mis-counted brackets when breaking path? Parsing '{}' \ - in {}, line {}", - self.snippet(span), - loc.file.name, - loc.line - ); + #[cfg(debug_assertions)] { + if angle_count != 0 || bracket_count != 0 { + let loc = self.sess.codemap().lookup_char_pos(span.lo()); + span_bug!( + span, + "Mis-counted brackets when breaking path? Parsing '{}' \ + in {}, line {}", + self.snippet(span), + loc.file.name, + loc.line + ); + } } - if result.is_none() && prev.tok.is_ident() && angle_count == 0 { + if result.is_none() && prev.tok.is_ident() { return Some(prev.sp); } result From 42df8c56cc6f1b94a9c0e8e55462dff57d95e4ac Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Sat, 17 Feb 2018 22:31:14 -0500 Subject: [PATCH 21/42] unused_unsafe: don't label irrelevant fns --- src/librustc_mir/transform/check_unsafety.rs | 7 +++- src/test/compile-fail/issue-48131.rs | 39 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-48131.rs diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index bbc7803b84d8e..3524255e03772 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -386,10 +386,13 @@ fn is_enclosed(tcx: TyCtxt, if used_unsafe.contains(&parent_id) { Some(("block".to_string(), parent_id)) } else if let Some(hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _), + node: hir::ItemFn(_, fn_unsafety, _, _, _, _), .. })) = tcx.hir.find(parent_id) { - Some(("fn".to_string(), parent_id)) + match fn_unsafety { + hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), + hir::Unsafety::Normal => None, + } } else { is_enclosed(tcx, used_unsafe, parent_id) } diff --git a/src/test/compile-fail/issue-48131.rs b/src/test/compile-fail/issue-48131.rs new file mode 100644 index 0000000000000..9eb567a5d3eb0 --- /dev/null +++ b/src/test/compile-fail/issue-48131.rs @@ -0,0 +1,39 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This note is annotated because the purpose of the test +// is to ensure that certain other notes are not generated. +#![deny(unused_unsafe)] //~ NOTE + +// (test that no note is generated on this unsafe fn) +pub unsafe fn a() { + fn inner() { + unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` + //~^ NOTE + } + + inner() +} + +pub fn b() { + // (test that no note is generated on this unsafe block) + unsafe { + fn inner() { + unsafe { /* unnecessary */ } //~ ERROR unnecessary `unsafe` + //~^ NOTE + } + + let () = ::std::mem::uninitialized(); + + inner() + } +} + +fn main() {} From d5ed655a0824b2d525e6fad4f3b23f77432ebf98 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 12:41:10 +0100 Subject: [PATCH 22/42] Use DefId instead of NodeId while generating debuginfo for statics. --- src/librustc_trans/consts.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 19 +++++++++---------- src/librustc_trans/debuginfo/mod.rs | 6 +++--- src/librustc_trans/debuginfo/namespace.rs | 11 ----------- src/librustc_trans/debuginfo/utils.rs | 4 +--- 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index d5b33d837c5bd..82e59bf4f5d16 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -304,7 +304,7 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } } - debuginfo::create_global_var_metadata(cx, id, g); + debuginfo::create_global_var_metadata(cx, def_id, g); if attr::contains_name(attrs, "thread_local") { llvm::set_thread_local_mode(g, cx.tls_model); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 62ba91840d95e..2c430d03c968e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -14,7 +14,7 @@ use self::EnumDiscriminantInfo::*; use super::utils::{debug_context, DIB, span_start, get_namespace_for_item, create_DIArray, is_node_local_to_unit}; -use super::namespace::mangled_name_of_item; +use super::namespace::mangled_name_of_instance; use super::type_names::compute_debuginfo_type_name; use super::{CrateDebugContext}; use abi; @@ -1634,19 +1634,18 @@ fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, /// /// Adds the created metadata nodes directly to the crate's IR. pub fn create_global_var_metadata(cx: &CodegenCx, - node_id: ast::NodeId, + def_id: DefId, global: ValueRef) { if cx.dbg_cx.is_none() { return; } let tcx = cx.tcx; - let node_def_id = tcx.hir.local_def_id(node_id); - let no_mangle = attr::contains_name(&tcx.get_attrs(node_def_id), "no_mangle"); + let no_mangle = attr::contains_name(&tcx.get_attrs(def_id), "no_mangle"); // We may want to remove the namespace scope if we're in an extern block, see: // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 - let var_scope = get_namespace_for_item(cx, node_def_id); - let span = cx.tcx.def_span(node_def_id); + let var_scope = get_namespace_for_item(cx, def_id); + let span = cx.tcx.def_span(def_id); let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { let loc = span_start(cx, span); @@ -1655,15 +1654,15 @@ pub fn create_global_var_metadata(cx: &CodegenCx, (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) }; - let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = Instance::mono(cx.tcx, node_def_id).ty(cx.tcx); + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = tcx.item_name(node_def_id).to_string(); + let var_name = tcx.item_name(def_id).to_string(); let var_name = CString::new(var_name).unwrap(); let linkage_name = if no_mangle { None } else { - let linkage_name = mangled_name_of_item(cx, node_id); + let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); Some(CString::new(linkage_name.to_string()).unwrap()) }; diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 9071eb776d529..16279f31836a9 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -254,14 +254,14 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let linkage_name = mangled_name_of_instance(cx, instance); let scope_line = span_start(cx, span).line; - - let local_id = cx.tcx.hir.as_local_node_id(instance.def_id()); - let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id)); + let is_local_to_unit = is_node_local_to_unit(cx, def_id); let function_name = CString::new(name).unwrap(); let linkage_name = CString::new(linkage_name.to_string()).unwrap(); let mut flags = DIFlags::FlagPrototyped; + + let local_id = cx.tcx.hir.as_local_node_id(def_id); match *cx.sess().entry_fn.borrow() { Some((id, _)) => { if local_id == Some(id) { diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 46067a4330396..891bf649c388a 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -14,7 +14,6 @@ use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context}; use monomorphize::Instance; use rustc::ty; -use syntax::ast; use llvm; use llvm::debuginfo::DIScope; @@ -33,16 +32,6 @@ pub fn mangled_name_of_instance<'a, 'tcx>( tcx.symbol_name(instance) } -pub fn mangled_name_of_item<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - node_id: ast::NodeId, -) -> ty::SymbolName { - let tcx = cx.tcx; - let node_def_id = tcx.hir.local_def_id(node_id); - let instance = Instance::mono(tcx, node_def_id); - tcx.symbol_name(instance) -} - pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) { return scope; diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index c571b84b8e9ed..9559cd4d9ea2d 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -21,9 +21,8 @@ use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; use common::{CodegenCx}; use syntax_pos::{self, Span}; -use syntax::ast; -pub fn is_node_local_to_unit(cx: &CodegenCx, node_id: ast::NodeId) -> bool +pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool { // The is_local_to_unit flag indicates whether a function is local to the // current compilation unit (i.e. if it is *static* in the C-sense). The @@ -33,7 +32,6 @@ pub fn is_node_local_to_unit(cx: &CodegenCx, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - let def_id = cx.tcx.hir.local_def_id(node_id); !cx.tcx.is_exported_symbol(def_id) } From 15ff0adcde77776e2947d147a756d4289aa42e59 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 13:29:22 +0100 Subject: [PATCH 23/42] Use DefId instead of NodeId in MonoItem::Static. --- src/librustc/mir/mono.rs | 7 +++-- src/librustc_mir/monomorphize/collector.rs | 12 ++++---- src/librustc_mir/monomorphize/item.rs | 16 +++++------ src/librustc_mir/monomorphize/partitioning.rs | 16 +++++++++-- src/librustc_trans/consts.rs | 26 ++++++++--------- src/librustc_trans/trans_item.rs | 28 ++++++++++++++----- 6 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 49e5c0dc21f9e..7f8f2e9b90603 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::DefId; use syntax::ast::NodeId; use syntax::symbol::InternedString; use ty::{Instance, TyCtxt}; @@ -21,7 +22,7 @@ use std::hash::Hash; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum MonoItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId), + Static(DefId), GlobalAsm(NodeId), } @@ -50,7 +51,9 @@ impl<'tcx> HashStable> for MonoItem<'tcx> { MonoItem::Fn(ref instance) => { instance.hash_stable(hcx, hasher); } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + def_id.hash_stable(hcx, hasher); + } MonoItem::GlobalAsm(node_id) => { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { node_id.hash_stable(hcx, hasher); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index a80dfaef0dab1..eb4ba21489c3d 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -368,8 +368,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let recursion_depth_reset; match starting_point { - MonoItem::Static(node_id) => { - let def_id = tcx.hir.local_def_id(node_id); + MonoItem::Static(def_id) => { let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally @@ -652,8 +651,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let tcx = self.tcx; let instance = Instance::mono(tcx, static_.def_id); if should_monomorphize_locally(tcx, &instance) { - let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap(); - self.output.push(MonoItem::Static(node_id)); + self.output.push(MonoItem::Static(static_.def_id)); } self.super_static(static_, context, location); @@ -946,10 +944,10 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { self.output.push(MonoItem::GlobalAsm(item.id)); } hir::ItemStatic(..) => { + let def_id = self.tcx.hir.local_def_id(item.id); debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.tcx, - self.tcx.hir.local_def_id(item.id))); - self.output.push(MonoItem::Static(item.id)); + def_id_to_string(self.tcx, def_id)); + self.output.push(MonoItem::Static(def_id)); } hir::ItemConst(..) => { // const items only generate mono items if they are diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index a5078187a57e3..549919a2c8919 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -97,8 +97,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { match *self.as_mono_item() { MonoItem::Fn(instance) => tcx.symbol_name(instance), - MonoItem::Static(node_id) => { - let def_id = tcx.hir.local_def_id(node_id); + MonoItem::Static(def_id) => { tcx.symbol_name(Instance::mono(tcx, def_id)) } MonoItem::GlobalAsm(node_id) => { @@ -159,7 +158,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self.as_mono_item() { MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(node_id) => tcx.hir.local_def_id(node_id), + MonoItem::Static(def_id) => def_id, MonoItem::GlobalAsm(..) => return None, }; @@ -209,7 +208,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { debug!("is_instantiable({:?})", self); let (def_id, substs) = match *self.as_mono_item() { MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs), - MonoItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()), + MonoItem::Static(def_id) => (def_id, Substs::empty()), // global asm never has predicates MonoItem::GlobalAsm(..) => return true }; @@ -218,14 +217,11 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { } fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { - let hir_map = &tcx.hir; - return match *self.as_mono_item() { MonoItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance) }, - MonoItem::Static(node_id) => { - let def_id = hir_map.local_def_id(node_id); + MonoItem::Static(def_id) => { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, @@ -251,7 +247,9 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + tcx.hir.as_local_node_id(def_id) + } MonoItem::GlobalAsm(node_id) => { Some(node_id) } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index e9471cdb4f949..2b558e71483c6 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -180,7 +180,9 @@ pub trait CodegenUnitExt<'tcx> { } } } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + tcx.hir.as_local_node_id(def_id) + } MonoItem::GlobalAsm(node_id) => { Some(node_id) } @@ -382,7 +384,15 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; (Linkage::External, visibility) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => { + let visibility = if tcx.is_exported_symbol(def_id) { + can_be_internalized = false; + default_visibility(def_id) + } else { + Visibility::Hidden + }; + (Linkage::External, visibility) + } MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_exported_symbol(def_id) { @@ -643,7 +653,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Some(def_id) } - MonoItem::Static(node_id) | + MonoItem::Static(def_id) => Some(def_id), MonoItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 82e59bf4f5d16..f9f185dfa5161 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -16,7 +16,7 @@ use rustc::hir::map as hir_map; use rustc::middle::const_val::ConstEvalErr; use debuginfo; use base; -use monomorphize::{MonoItem, MonoItemExt}; +use monomorphize::MonoItem; use common::{CodegenCx, val_ty}; use declare; use monomorphize::Instance; @@ -110,7 +110,17 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { return g; } + let defined_in_current_codegen_unit = cx.codegen_unit + .items() + .contains_key(&MonoItem::Static(def_id)); + assert!(!defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id); + let ty = instance.ty(cx.tcx); + let sym = cx.tcx.symbol_name(instance); + let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { let llty = cx.layout_of(ty).llvm_type(cx); @@ -118,13 +128,6 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { - let sym = MonoItem::Static(id).symbol_name(cx.tcx); - - let defined_in_current_codegen_unit = cx.codegen_unit - .items() - .contains_key(&MonoItem::Static(id)); - assert!(!defined_in_current_codegen_unit); - if declare::get_declared_value(cx, &sym[..]).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } @@ -143,7 +146,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = cx.tcx.symbol_name(instance); + let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -203,8 +206,6 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { g } else { - let sym = cx.tcx.symbol_name(instance); - // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global let g = declare::declare_global(cx, &sym, cx.layout_of(ty).llvm_type(cx)); @@ -246,11 +247,10 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, m: hir::Mutability, - id: ast::NodeId, + def_id: DefId, attrs: &[ast::Attribute]) -> Result> { unsafe { - let def_id = cx.tcx.hir.local_def_id(id); let g = get_static(cx, def_id); let v = ::mir::trans_static_initializer(cx, def_id)?; diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5eb6679fe252c..2751e32925931 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -24,10 +24,10 @@ use llvm; use monomorphize::Instance; use type_of::LayoutLlvmExt; use rustc::hir; +use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::TypeFoldable; use rustc::ty::layout::LayoutOf; -use syntax::ast; use syntax::attr; use std::fmt; @@ -44,11 +44,18 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { cx.codegen_unit.name()); match *self.as_mono_item() { - MonoItem::Static(node_id) => { + MonoItem::Static(def_id) => { let tcx = cx.tcx; + let node_id = match tcx.hir.as_local_node_id(def_id) { + Some(node_id) => node_id, + None => { + bug!("MonoItemExt::define() called for non-local \ + static `{:?}`.", def_id) + } + }; let item = tcx.hir.expect_item(node_id); if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&cx, m, item.id, &item.attrs) { + match consts::trans_static(&cx, m, def_id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { err.report(tcx, item.span, "static"); @@ -91,8 +98,8 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { debug!("symbol {}", &symbol_name); match *self.as_mono_item() { - MonoItem::Static(node_id) => { - predefine_static(cx, node_id, linkage, visibility, &symbol_name); + MonoItem::Static(def_id) => { + predefine_static(cx, def_id, linkage, visibility, &symbol_name); } MonoItem::Fn(instance) => { predefine_fn(cx, instance, linkage, visibility, &symbol_name); @@ -126,11 +133,18 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - node_id: ast::NodeId, + def_id: DefId, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - let def_id = cx.tcx.hir.local_def_id(node_id); + let node_id = match cx.tcx.hir.as_local_node_id(def_id) { + Some(node_id) => node_id, + None => { + bug!("MonoItemExt::predefine() called for non-local static `{:?}`.", + def_id) + } + }; + let instance = Instance::mono(cx.tcx, def_id); let ty = instance.ty(cx.tcx); let llty = cx.layout_of(ty).llvm_type(cx); From 8ff633cc3b85933e76c84b43d2c19250c397e9cb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:46:40 +0100 Subject: [PATCH 24/42] Implement describe_def query for LOCAL_CRATE --- src/librustc/hir/map/mod.rs | 98 +++++++++++++++++++++++++++++++++++ src/librustc/hir/mod.rs | 6 +++ src/librustc_driver/driver.rs | 1 + 3 files changed, 105 insertions(+) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b6b3e8955351c..3799bdada888e 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -22,6 +22,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; +use syntax::ext::base::MacroKind; use syntax_pos::Span; use hir::*; @@ -32,6 +33,7 @@ use util::nodemap::{DefIdMap, FxHashMap}; use arena::TypedArena; use std::cell::RefCell; use std::io; +use ty::TyCtxt; pub mod blocks; mod collector; @@ -39,6 +41,7 @@ mod def_collector; pub mod definitions; mod hir_id_validator; + pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; @@ -373,6 +376,92 @@ impl<'hir> Map<'hir> { self.definitions.as_local_node_id(def_id.to_def_id()).unwrap() } + pub fn describe_def(&self, node_id: NodeId) -> Option { + let node = if let Some(node) = self.find(node_id) { + node + } else { + return None + }; + + match node { + NodeItem(item) => { + let def_id = || { + self.local_def_id(item.id) + }; + + match item.node { + ItemStatic(_, m, _) => Some(Def::Static(def_id(), + m == MutMutable)), + ItemConst(..) => Some(Def::Const(def_id())), + ItemFn(..) => Some(Def::Fn(def_id())), + ItemMod(..) => Some(Def::Mod(def_id())), + ItemGlobalAsm(..) => Some(Def::GlobalAsm(def_id())), + ItemTy(..) => Some(Def::TyAlias(def_id())), + ItemEnum(..) => Some(Def::Enum(def_id())), + ItemStruct(..) => Some(Def::Struct(def_id())), + ItemUnion(..) => Some(Def::Union(def_id())), + ItemTrait(..) => Some(Def::Trait(def_id())), + ItemTraitAlias(..) => { + bug!("trait aliases are not yet implemented (see issue #41517)") + }, + ItemExternCrate(_) | + ItemUse(..) | + ItemForeignMod(..) | + ItemImpl(..) => None, + } + } + NodeForeignItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + ForeignItemFn(..) => Some(Def::Fn(def_id)), + ForeignItemStatic(_, m) => Some(Def::Static(def_id, m)), + ForeignItemType => Some(Def::TyForeign(def_id)), + } + } + NodeTraitItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + TraitItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), + TraitItemKind::Method(..) => Some(Def::Method(def_id)), + TraitItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), + } + } + NodeImplItem(item) => { + let def_id = self.local_def_id(item.id); + match item.node { + ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)), + ImplItemKind::Method(..) => Some(Def::Method(def_id)), + ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)), + } + } + NodeVariant(variant) => { + let def_id = self.local_def_id(variant.node.data.id()); + Some(Def::Variant(def_id)) + } + NodeField(_) | + NodeExpr(_) | + NodeStmt(_) | + NodeTy(_) | + NodeTraitRef(_) | + NodePat(_) | + NodeBinding(_) | + NodeStructCtor(_) | + NodeLifetime(_) | + NodeVisibility(_) | + NodeBlock(_) => None, + NodeLocal(local) => { + Some(Def::Local(local.id)) + } + NodeMacroDef(macro_def) => { + Some(Def::Macro(self.local_def_id(macro_def.id), + MacroKind::Bang)) + } + NodeTyParam(param) => { + Some(Def::TyParam(self.local_def_id(param.id))) + } + } + } + fn entry_count(&self) -> usize { self.map.len() } @@ -1275,3 +1364,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } } } + +pub fn describe_def(tcx: TyCtxt, def_id: DefId) -> Option { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.describe_def(node_id) + } else { + bug!("Calling local describe_def query provider for upstream DefId: {:?}", + def_id) + } +} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bc03f7ead8187..0fa1b95d8e777 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -43,6 +43,7 @@ use syntax::tokenstream::TokenStream; use syntax::util::ThinVec; use syntax::util::parser::ExprPrecedence; use ty::AdtKind; +use ty::maps::Providers; use rustc_data_structures::indexed_vec; @@ -2204,3 +2205,8 @@ pub type TraitMap = NodeMap>; // Map from the NodeId of a glob import to a list of items which are actually // imported. pub type GlobMap = NodeMap>; + + +pub fn provide(providers: &mut Providers) { + providers.describe_def = map::describe_def; +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..d283e13c95823 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -929,6 +929,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, } pub fn default_provide(providers: &mut ty::maps::Providers) { + hir::provide(providers); borrowck::provide(providers); mir::provide(providers); reachable::provide(providers); From 1be7f966e03f41eb299c184a3c0ad98018fb8fc4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:47:59 +0100 Subject: [PATCH 25/42] Rename is_translated_fn query to is_translated_item and make it support statics. --- src/librustc/dep_graph/dep_node.rs | 2 +- src/librustc/ty/maps/mod.rs | 2 +- src/librustc/ty/maps/plumbing.rs | 2 +- src/librustc_trans/base.rs | 5 +++-- src/librustc_trans/callee.rs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 4034055d04155..aa678ba788a5b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -625,7 +625,7 @@ define_dep_nodes!( <'tcx> [eval_always] CollectAndPartitionTranslationItems, [] ExportName(DefId), [] ContainsExternIndicator(DefId), - [] IsTranslatedFunction(DefId), + [] IsTranslatedItem(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 21ffe6b895e72..be1d255afa191 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -349,7 +349,7 @@ define_maps! { <'tcx> [] fn export_name: ExportName(DefId) -> Option, [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel, - [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, + [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, [] fn output_filenames: output_filenames_node(CrateNum) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index f02c7cbd0ea3e..146b3c859e933 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -929,7 +929,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ContainsExternIndicator => { force!(contains_extern_indicator, def_id!()); } - DepKind::IsTranslatedFunction => { force!(is_translated_function, def_id!()); } + DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); } DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 466a86e7ea558..c0785f5393716 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1004,6 +1004,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { match *trans_item { MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), _ => None, } }).collect(); @@ -1107,7 +1108,7 @@ impl CrateInfo { } } -fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool { +fn is_translated_item(tcx: TyCtxt, id: DefId) -> bool { let (all_trans_items, _) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); all_trans_items.contains(&id) @@ -1222,7 +1223,7 @@ pub fn provide(providers: &mut Providers) { providers.collect_and_partition_translation_items = collect_and_partition_translation_items; - providers.is_translated_function = is_translated_function; + providers.is_translated_item = is_translated_item; providers.codegen_unit = |tcx, name| { let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index c3d5e08c73e7e..8c40aa6a2acba 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -149,7 +149,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if cx.tcx.is_translated_function(instance_def_id) { + if cx.tcx.is_translated_item(instance_def_id) { if instance_def_id.is_local() { if !cx.tcx.is_exported_symbol(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); From 89b3ef3e8eae1a9cf119888341509e10fd7e1b9a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 19 Feb 2018 16:49:20 +0100 Subject: [PATCH 26/42] Allow for instantiating statics from upstream crates. --- src/librustc_trans/consts.rs | 15 ++++++++---- src/librustc_trans/trans_item.rs | 40 +++++++++++++------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index f9f185dfa5161..1608c4a87bf5c 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -226,8 +226,15 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { // statically in the final application, we always mark such symbols as 'dllimport'. // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to // make things work. - unsafe { - llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_translated_item query. + if !cx.tcx.is_translated_item(def_id) { + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } } } g @@ -246,8 +253,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { } pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - m: hir::Mutability, def_id: DefId, + is_mutable: bool, attrs: &[ast::Attribute]) -> Result> { unsafe { @@ -298,7 +305,7 @@ pub fn trans_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. - if m != hir::MutMutable { + if !is_mutable { if cx.type_is_freeze(ty) { llvm::LLVMSetGlobalConstant(g, llvm::True); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2751e32925931..91c1097fc7f8a 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -24,6 +24,7 @@ use llvm; use monomorphize::Instance; use type_of::LayoutLlvmExt; use rustc::hir; +use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::TypeFoldable; @@ -46,24 +47,23 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { match *self.as_mono_item() { MonoItem::Static(def_id) => { let tcx = cx.tcx; - let node_id = match tcx.hir.as_local_node_id(def_id) { - Some(node_id) => node_id, + let is_mutable = match tcx.describe_def(def_id) { + Some(Def::Static(_, is_mutable)) => is_mutable, + Some(other) => { + bug!("Expected Def::Static, found {:?}", other) + } None => { - bug!("MonoItemExt::define() called for non-local \ - static `{:?}`.", def_id) + bug!("Expected Def::Static for {:?}, found nothing", def_id) + } + }; + let attrs = tcx.get_attrs(def_id); + + match consts::trans_static(&cx, def_id, is_mutable, &attrs) { + Ok(_) => { /* Cool, everything's alright. */ }, + Err(err) => { + err.report(tcx, tcx.def_span(def_id), "static"); } }; - let item = tcx.hir.expect_item(node_id); - if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&cx, m, def_id, &item.attrs) { - Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => { - err.report(tcx, item.span, "static"); - } - }; - } else { - span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") - } } MonoItem::GlobalAsm(node_id) => { let item = cx.tcx.hir.expect_item(node_id); @@ -137,20 +137,12 @@ fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) { - let node_id = match cx.tcx.hir.as_local_node_id(def_id) { - Some(node_id) => node_id, - None => { - bug!("MonoItemExt::predefine() called for non-local static `{:?}`.", - def_id) - } - }; - let instance = Instance::mono(cx.tcx, def_id); let ty = instance.ty(cx.tcx); let llty = cx.layout_of(ty).llvm_type(cx); let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| { - cx.sess().span_fatal(cx.tcx.hir.span(node_id), + cx.sess().span_fatal(cx.tcx.def_span(def_id), &format!("symbol `{}` is already defined", symbol_name)) }); From 1aad320974786f3abbe6e82a9d96d5594238046b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 19 Feb 2018 10:07:45 -0800 Subject: [PATCH 27/42] When encountering invalid token after `unsafe`, mention `{` --- src/libsyntax/parse/parser.rs | 2 ++ src/test/ui/unsafe-block-without-braces.rs | 16 ++++++++++++++++ src/test/ui/unsafe-block-without-braces.stderr | 10 ++++++++++ 3 files changed, 28 insertions(+) create mode 100644 src/test/ui/unsafe-block-without-braces.rs create mode 100644 src/test/ui/unsafe-block-without-braces.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac582627f88fd..fed7d25811aab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6469,6 +6469,8 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { // UNSAFE FUNCTION ITEM self.bump(); // `unsafe` + // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic + self.check(&token::OpenDelim(token::Brace)); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi()?.unwrap_or(Abi::C) } else { diff --git a/src/test/ui/unsafe-block-without-braces.rs b/src/test/ui/unsafe-block-without-braces.rs new file mode 100644 index 0000000000000..b6fb3ec5c44cf --- /dev/null +++ b/src/test/ui/unsafe-block-without-braces.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + unsafe //{ + std::mem::transmute::(1.0); + //} +} +//~^^^ ERROR expected one of `extern`, `fn`, or `{`, found `std` diff --git a/src/test/ui/unsafe-block-without-braces.stderr b/src/test/ui/unsafe-block-without-braces.stderr new file mode 100644 index 0000000000000..fc6ddba382395 --- /dev/null +++ b/src/test/ui/unsafe-block-without-braces.stderr @@ -0,0 +1,10 @@ +error: expected one of `extern`, `fn`, or `{`, found `std` + --> $DIR/unsafe-block-without-braces.rs:13:9 + | +12 | unsafe //{ + | - expected one of `extern`, `fn`, or `{` here +13 | std::mem::transmute::(1.0); + | ^^^ unexpected token + +error: aborting due to previous error + From 713b05f0726b7ee4c45728c01ddb0c40d8ccf0f3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 21 Feb 2018 19:20:09 +0200 Subject: [PATCH 28/42] rustc_data_structures: add missing #[inline]. --- src/librustc_data_structures/bitslice.rs | 3 +++ src/librustc_data_structures/indexed_vec.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 7665bfd5b1117..2678861be0634 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -24,6 +24,7 @@ pub trait BitSlice { impl BitSlice for [Word] { /// Clears bit at `idx` to 0; returns true iff this changed `self.` + #[inline] fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", @@ -37,6 +38,7 @@ impl BitSlice for [Word] { } /// Sets bit at `idx` to 1; returns true iff this changed `self.` + #[inline] fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", @@ -50,6 +52,7 @@ impl BitSlice for [Word] { } /// Extracts value of bit at `idx` in `self`. + #[inline] fn get_bit(&self, idx: usize) -> bool { let words = self; let BitLookup { word, bit_mask, .. } = bit_lookup(idx); diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index b11ca107af7dd..14626f9d5a0fd 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -29,12 +29,16 @@ pub trait Idx: Copy + 'static + Eq + Debug { } impl Idx for usize { + #[inline] fn new(idx: usize) -> Self { idx } + #[inline] fn index(self) -> usize { self } } impl Idx for u32 { + #[inline] fn new(idx: usize) -> Self { assert!(idx <= u32::MAX as usize); idx as u32 } + #[inline] fn index(self) -> usize { self as usize } } @@ -73,11 +77,13 @@ macro_rules! newtype_index { pub struct $type($($pub)* u32); impl Idx for $type { + #[inline] fn new(value: usize) -> Self { assert!(value < ($max) as usize); $type(value as u32) } + #[inline] fn index(self) -> usize { self.0 as usize } From 1eab1b19a39f54a825c9107086f0c1752b81224d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 8 Feb 2018 17:16:39 -0500 Subject: [PATCH 29/42] support unit tests with return values that implement `Terminaton` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend `Termination` trait with a method to determine what happens with a unit test. This commit incorporates work by Bastian Kรถcher . --- src/librustc_driver/driver.rs | 3 +- src/libstd/termination.rs | 7 + src/libsyntax/lib.rs | 1 + src/libsyntax/test.rs | 170 +++++++++++++----- .../run-pass/termination-trait-in-test.rs | 28 +++ 5 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/test/run-pass/termination-trait-in-test.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..e4600f25ea70c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -816,7 +816,8 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, &mut resolver, sess.opts.test, krate, - sess.diagnostic()) + sess.diagnostic(), + &sess.features.borrow()) }); // If we're actually rustdoc then there's no need to actually compile diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index dc7fa53aab632..f02fad009d8a5 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -37,6 +37,13 @@ pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; + + /// Invoked when unit tests terminate. Should panic if the unit + /// test is considered a failure. By default, invokes `report()` + /// and checks for a `0` result. + fn assert_unit_test_successful(self) where Self: Sized { + assert_eq!(self.report(), 0); + } } #[unstable(feature = "termination_trait", issue = "43301")] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9181cca215c84..53ff3ccd48ad9 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -105,6 +105,7 @@ pub mod syntax { pub use ext; pub use parse; pub use ast; + pub use tokenstream; } pub mod abi; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e73550d0719a4..094de6868a500 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -32,6 +32,7 @@ use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; +use feature_gate::Features; use util::move_map::MoveMap; use fold; use parse::{token, ParseSess}; @@ -63,6 +64,7 @@ struct TestCtxt<'a> { reexport_test_harness_main: Option, is_libtest: bool, ctxt: SyntaxContext, + features: &'a Features, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -74,7 +76,8 @@ pub fn modify_for_testing(sess: &ParseSess, resolver: &mut Resolver, should_test: bool, krate: ast::Crate, - span_diagnostic: &errors::Handler) -> ast::Crate { + span_diagnostic: &errors::Handler, + features: &Features) -> ast::Crate { // Check for #[reexport_test_harness_main = "some_name"] which // creates a `use some_name = __test::main;`. This needs to be // unconditional, so that the attribute is still marked as used in @@ -84,7 +87,8 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic) + generate_test_harness(sess, resolver, reexport_test_harness_main, + krate, span_diagnostic, features) } else { krate } @@ -265,16 +269,20 @@ fn generate_test_harness(sess: &ParseSess, resolver: &mut Resolver, reexport_test_harness_main: Option, krate: ast::Crate, - sd: &errors::Handler) -> ast::Crate { + sd: &errors::Handler, + features: &Features) -> ast::Crate { // Remove the entry points let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); let mark = Mark::fresh(Mark::root()); + let mut econfig = ExpansionConfig::default("test".to_string()); + econfig.features = Some(features); + let cx = TestCtxt { span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), + ext_cx: ExtCtxt::new(sess, econfig, resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main, @@ -282,6 +290,7 @@ fn generate_test_harness(sess: &ParseSess, is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false), toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), + features, }; mark.set_expn_info(ExpnInfo { @@ -318,71 +327,105 @@ enum HasTestSignature { fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_test_attr = attr::contains_name(&i.attrs, "test"); - fn has_test_signature(i: &ast::Item) -> HasTestSignature { + fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false - }; - if decl.inputs.is_empty() - && no_output - && !generics.is_parameterized() { - Yes - } else { - No + ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + + no_output && !generics.is_parameterized() + }; + + if decl.inputs.is_empty() && output_matches { + Yes + } else { + No + } } - } - _ => NotEvenAFunction, + _ => NotEvenAFunction, } } - if has_test_attr { + let has_test_signature = if has_test_attr { let diag = cx.span_diagnostic; - match has_test_signature(i) { - Yes => {}, - No => diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"), - NotEvenAFunction => diag.span_err(i.span, - "only functions may be used as tests"), + match has_test_signature(cx, i) { + Yes => true, + No => { + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as tests can not have any arguments"); + } else { + diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"); + } + false + }, + NotEvenAFunction => { + diag.span_err(i.span, "only functions may be used as tests"); + false + }, } - } + } else { + false + }; - has_test_attr && has_test_signature(i) == Yes + has_test_attr && has_test_signature } fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_bench_attr = attr::contains_name(&i.attrs, "bench"); - fn has_test_signature(i: &ast::Item) -> bool { + fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { let input_cnt = decl.inputs.len(); - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false + + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + let tparm_cnt = generics.params.iter() + .filter(|param| param.is_type_param()) + .count(); + + no_output && tparm_cnt == 0 }; - let tparm_cnt = generics.params.iter() - .filter(|param| param.is_type_param()) - .count(); // NB: inadequate check, but we're running // well before resolve, can't get too deep. - input_cnt == 1 - && no_output && tparm_cnt == 0 + input_cnt == 1 && output_matches } _ => false } } - if has_bench_attr && !has_test_signature(i) { + let has_bench_signature = has_bench_signature(cx, i); + + if has_bench_attr && !has_bench_signature { let diag = cx.span_diagnostic; - diag.span_err(i.span, "functions used as benches must have signature \ - `fn(&mut Bencher) -> ()`"); + + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> impl Termination`"); + } else { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> ()`"); + } } - has_bench_attr && has_test_signature(i) + has_bench_attr && has_bench_signature } fn is_ignored(i: &ast::Item) -> bool { @@ -700,9 +743,52 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // If termination feature is enabled, create a wrapper that invokes the fn + // like this: + // + // fn wrapper() { + // assert_eq!(0, real_function().report()); + // } + // + // and then put a reference to `wrapper` into the test descriptor. Otherwise, + // just put a direct reference to `real_function`. + let fn_expr = { + let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + if cx.features.termination_trait { + // ::std::Termination::assert_unit_test_successful + let assert_unit_test_successful = ecx.path_global( + span, + vec![ + ecx.ident_of("std"), + ecx.ident_of("Termination"), + ecx.ident_of("assert_unit_test_successful"), + ], + ); + // || {..} + ecx.lambda( + span, + vec![], + // ::std::Termination::assert_unit_test_successful(..) + ecx.expr_call( + span, + ecx.expr_path(assert_unit_test_successful), + vec![ + // $base_fn_expr() + ecx.expr_call( + span, + base_fn_expr, + vec![], + ) + ], + ), + ) + } else { + base_fn_expr + } + }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; + // self::test::$variant_name($fn_expr) let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]); diff --git a/src/test/run-pass/termination-trait-in-test.rs b/src/test/run-pass/termination-trait-in-test.rs new file mode 100644 index 0000000000000..e67e0de5c318b --- /dev/null +++ b/src/test/run-pass/termination-trait-in-test.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(termination_trait)] + +use std::num::ParseIntError; + +#[test] +fn is_a_num() -> Result<(), ParseIntError> { + let _: u32 = "22".parse()?; + Ok(()) +} + +#[test] +#[should_panic] +fn not_a_num() -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} From 0625d4c282a9fa2a5ba3c6448017898baccfcf9a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 11 Feb 2018 09:28:47 -0500 Subject: [PATCH 30/42] begin crate-relative paths with `crate` --- src/libsyntax/ext/build.rs | 10 +++------ src/libsyntax/test.rs | 9 +++++--- .../rfc-2126-extern-absolute-paths/test.rs | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2e6de96d65a6d..57978ca9c80a5 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -319,14 +319,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { types: Vec>, bindings: Vec ) -> ast::Path { - use syntax::parse::token; - let last_identifier = idents.pop().unwrap(); let mut segments: Vec = Vec::new(); - if global && - !idents.first().map_or(false, |&ident| token::Ident(ident).is_path_segment_keyword()) { - segments.push(ast::PathSegment::crate_root(span)); - } segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, span))); let parameters = if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { @@ -335,7 +329,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> { None }; segments.push(ast::PathSegment { identifier: last_identifier, span, parameters }); - ast::Path { span, segments } + let path = ast::Path { span, segments }; + + if global { path.default_to_global() } else { path } } /// Constructs a qualified path. diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 094de6868a500..6cbb7ab393fae 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -733,9 +733,12 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { field("should_panic", fail_expr), field("allow_fail", allow_fail_expr)]); - - let mut visible_path = match cx.toplevel_reexport { - Some(id) => vec![id], + let mut visible_path = vec![]; + if cx.features.extern_absolute_paths { + visible_path.push(keywords::Crate.ident()); + } + match cx.toplevel_reexport { + Some(id) => visible_path.push(id), None => { let diag = cx.span_diagnostic; diag.bug("expected to find top-level re-export name, but found None"); diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs new file mode 100644 index 0000000000000..796f652d6b57b --- /dev/null +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `#[test]` works with extern-absolute-paths enabled. +// +// Regression test for #47075. + +// compile-flags: --test + +#![feature(extern_absolute_paths)] + +#[test] +fn test() { +} From e446f706a89e3d5c26c01318bd70904d492ab8b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 10:06:12 -0500 Subject: [PATCH 31/42] put the "unit test" logic into libtest Also make `std::termination` module public and rename feature. The lib feature needs a different name from the language feature. --- src/libstd/lib.rs | 5 +- src/libstd/termination.rs | 23 ++++--- src/libsyntax/test.rs | 60 ++++++++----------- src/libtest/lib.rs | 9 +++ .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 6 files changed, 47 insertions(+), 54 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3c9004cdd19bc..b247d121648f6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -501,11 +501,10 @@ mod memchr; // The runtime entry point and a few unstable public functions used by the // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -mod termination; +// The trait to support returning arbitrary types in the main function #[unstable(feature = "termination_trait", issue = "43301")] -pub use self::termination::Termination; +pub mod termination; // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index f02fad009d8a5..203870766a9ab 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Defines the meaning of the return value from `main`, and hence +//! controls what happens in a Rust program after `main` returns. + use fmt::Debug; + #[cfg(target_arch = "wasm32")] mod exit { pub const SUCCESS: i32 = 0; @@ -30,28 +34,21 @@ mod exit { /// The default implementations are returning `libc::EXIT_SUCCESS` to indicate /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = "`main` can only return types that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; - - /// Invoked when unit tests terminate. Should panic if the unit - /// test is considered a failure. By default, invokes `report()` - /// and checks for a `0` result. - fn assert_unit_test_successful(self) where Self: Sized { - assert_eq!(self.report(), 0); - } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for () { fn report(self) -> i32 { exit::SUCCESS } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for Result { fn report(self) -> i32 { match self { @@ -64,19 +61,19 @@ impl Termination for Result { } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ! { fn report(self) -> i32 { unreachable!(); } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for bool { fn report(self) -> i32 { if self { exit::SUCCESS } else { exit::FAILURE } } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for i32 { fn report(self) -> i32 { self diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6cbb7ab393fae..b48713fcf7aa1 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -746,48 +746,36 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - // If termination feature is enabled, create a wrapper that invokes the fn - // like this: + // Rather than directly give the test function to the test + // harness, we create a wrapper like this: // - // fn wrapper() { - // assert_eq!(0, real_function().report()); - // } + // || test::assert_test_result(real_function()) // - // and then put a reference to `wrapper` into the test descriptor. Otherwise, - // just put a direct reference to `real_function`. + // this will coerce into a fn pointer that is specialized to the + // actual return type of `real_function` (Typically `()`, but not always). let fn_expr = { - let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); - if cx.features.termination_trait { - // ::std::Termination::assert_unit_test_successful - let assert_unit_test_successful = ecx.path_global( + // construct `real_function()` (this will be inserted into the overall expr) + let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // construct path `test::assert_test_result` + let assert_test_result = test_path("assert_test_result"); + // construct `|| {..}` + ecx.lambda( + span, + vec![], + // construct `assert_test_result(..)` + ecx.expr_call( span, + ecx.expr_path(assert_test_result), vec![ - ecx.ident_of("std"), - ecx.ident_of("Termination"), - ecx.ident_of("assert_unit_test_successful"), + // construct `real_function()` + ecx.expr_call( + span, + real_function_expr, + vec![], + ) ], - ); - // || {..} - ecx.lambda( - span, - vec![], - // ::std::Termination::assert_unit_test_successful(..) - ecx.expr_call( - span, - ecx.expr_path(assert_unit_test_successful), - vec![ - // $base_fn_expr() - ecx.expr_call( - span, - base_fn_expr, - vec![], - ) - ], - ), - ) - } else { - base_fn_expr - } + ), + ) }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9ea5f39b71fee..932952d649bdf 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -40,6 +40,7 @@ #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] +#![feature(termination_trait_lib)] extern crate getopts; extern crate term; @@ -69,6 +70,7 @@ use std::iter::repeat; use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; +use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; @@ -322,6 +324,13 @@ pub fn test_main_static(tests: &[TestDescAndFn]) { test_main(&args, owned_tests, Options::new()) } +/// Invoked when unit tests terminate. Should panic if the unit +/// test is considered a failure. By default, invokes `report()` +/// and checks for a `0` result. +pub fn assert_test_result(result: T) { + assert_eq!(result.report(), 0); +} + #[derive(Copy, Clone, Debug)] pub enum ColorConfig { AutoColor, diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index a63162cf73d1c..2da518519521f 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index 788c38c55be0a..fac60d6d39971 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied ReturnType {} } From 5f1e78f19ad40c6265a200b41c772c321b8b08cd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 17:36:55 -0500 Subject: [PATCH 32/42] move Termination trait to std::process --- src/libstd/lib.rs | 4 - src/libstd/process.rs | 67 +++++++++++++++ src/libstd/rt.rs | 2 +- src/libstd/termination.rs | 81 ------------------- src/libtest/lib.rs | 2 +- .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 7 files changed, 71 insertions(+), 89 deletions(-) delete mode 100644 src/libstd/termination.rs diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b247d121648f6..bdda741633692 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -502,10 +502,6 @@ mod memchr; // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -#[unstable(feature = "termination_trait", issue = "43301")] -pub mod termination; - // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9b2f815b71383..e25599b8bd871 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1392,6 +1392,73 @@ pub fn id() -> u32 { ::sys::os::getpid() } +#[cfg(target_arch = "wasm32")] +mod exit { + pub const SUCCESS: i32 = 0; + pub const FAILURE: i32 = 1; +} +#[cfg(not(target_arch = "wasm32"))] +mod exit { + use libc; + pub const SUCCESS: i32 = libc::EXIT_SUCCESS; + pub const FAILURE: i32 = libc::EXIT_FAILURE; +} + +/// A trait for implementing arbitrary return types in the `main` function. +/// +/// The c-main function only supports to return integers as return type. +/// So, every type implementing the `Termination` trait has to be converted +/// to an integer. +/// +/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate +/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. +#[cfg_attr(not(test), lang = "termination")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[rustc_on_unimplemented = + "`main` can only return types that implement {Termination}, not `{Self}`"] +pub trait Termination { + /// Is called to get the representation of the value as status code. + /// This status code is returned to the operating system. + fn report(self) -> i32; +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for () { + fn report(self) -> i32 { exit::SUCCESS } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for Result { + fn report(self) -> i32 { + match self { + Ok(val) => val.report(), + Err(err) => { + eprintln!("Error: {:?}", err); + exit::FAILURE + } + } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for ! { + fn report(self) -> i32 { unreachable!(); } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for bool { + fn report(self) -> i32 { + if self { exit::SUCCESS } else { exit::FAILURE } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for i32 { + fn report(self) -> i32 { + self + } +} + #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { use io::prelude::*; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9dbaf784f89e0..e1392762a59dc 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -68,7 +68,7 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), #[cfg(not(test))] #[lang = "start"] -fn lang_start +fn lang_start (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { lang_start_internal(&move || main().report(), argc, argv) diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs deleted file mode 100644 index 203870766a9ab..0000000000000 --- a/src/libstd/termination.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Defines the meaning of the return value from `main`, and hence -//! controls what happens in a Rust program after `main` returns. - -use fmt::Debug; - -#[cfg(target_arch = "wasm32")] -mod exit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod exit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The c-main function only supports to return integers as return type. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -#[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - fn report(self) -> i32; -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for () { - fn report(self) -> i32 { exit::SUCCESS } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result { - fn report(self) -> i32 { - match self { - Ok(val) => val.report(), - Err(err) => { - eprintln!("Error: {:?}", err); - exit::FAILURE - } - } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for ! { - fn report(self) -> i32 { unreachable!(); } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for bool { - fn report(self) -> i32 { - if self { exit::SUCCESS } else { exit::FAILURE } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for i32 { - fn report(self) -> i32 { - self - } -} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 932952d649bdf..06a23cd8818ee 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -68,9 +68,9 @@ use std::io::prelude::*; use std::io; use std::iter::repeat; use std::path::PathBuf; +use std::process::Termination; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; -use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 2da518519521f..93e2561adf753 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index fac60d6d39971..e87e0ceebf1b1 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied ReturnType {} } From 8f35141fbad39b94b071186e2d8259694bd4960d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 18:26:01 -0500 Subject: [PATCH 33/42] remove tokenstream --- src/libsyntax/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 53ff3ccd48ad9..9181cca215c84 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -105,7 +105,6 @@ pub mod syntax { pub use ext; pub use parse; pub use ast; - pub use tokenstream; } pub mod abi; From 067c2e3d0393311ac3dc9d8abb8750fd2fd5dd11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:09:10 -0500 Subject: [PATCH 34/42] handle `#[bench]` functions better --- src/libsyntax/test.rs | 62 ++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index b48713fcf7aa1..1b48901d4ebec 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -747,9 +747,10 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { visible_path.extend(path); // Rather than directly give the test function to the test - // harness, we create a wrapper like this: + // harness, we create a wrapper like one of the following: // - // || test::assert_test_result(real_function()) + // || test::assert_test_result(real_function()) // for test + // |b| test::assert_test_result(real_function(b)) // for bench // // this will coerce into a fn pointer that is specialized to the // actual return type of `real_function` (Typically `()`, but not always). @@ -758,24 +759,47 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path)); // construct path `test::assert_test_result` let assert_test_result = test_path("assert_test_result"); - // construct `|| {..}` - ecx.lambda( - span, - vec![], - // construct `assert_test_result(..)` - ecx.expr_call( + if test.bench { + // construct `|b| {..}` + let b_ident = Ident::with_empty_ctxt(Symbol::gensym("b")); + let b_expr = ecx.expr_ident(span, b_ident); + ecx.lambda( span, - ecx.expr_path(assert_test_result), - vec![ - // construct `real_function()` - ecx.expr_call( - span, - real_function_expr, - vec![], - ) - ], - ), - ) + vec![b_ident], + // construct `assert_test_result(..)` + ecx.expr_call( + span, + ecx.expr_path(assert_test_result), + vec![ + // construct `real_function(b)` + ecx.expr_call( + span, + real_function_expr, + vec![b_expr], + ) + ], + ), + ) + } else { + // construct `|| {..}` + ecx.lambda( + span, + vec![], + // construct `assert_test_result(..)` + ecx.expr_call( + span, + ecx.expr_path(assert_test_result), + vec![ + // construct `real_function()` + ecx.expr_call( + span, + real_function_expr, + vec![], + ) + ], + ), + ) + } }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; From e0ed88df3d33637ef8a41d3655cd20587f566048 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:10:36 -0500 Subject: [PATCH 35/42] add test for `fn main() -> !` --- .../termination-trait-for-never.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs new file mode 100644 index 0000000000000..c1dd44a91765e --- /dev/null +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +// error-pattern:oh, dear + +fn main() -> ! { + panic!("oh, dear"); +} From a0562ec369629abc0b365c95b77e67aec232bd85 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:16:06 -0500 Subject: [PATCH 36/42] delete this test file: it also appears as src/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs --- ...termination-trait-for-result-box-error_ok.rs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/test/run-pass/termination-trait-for-result-box-error_ok.rs diff --git a/src/test/run-pass/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/termination-trait-for-result-box-error_ok.rs deleted file mode 100644 index 269ac451cf4d8..0000000000000 --- a/src/test/run-pass/termination-trait-for-result-box-error_ok.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -use std::io::Error; - -fn main() -> Result<(), Box> { - Ok(()) -} From 0a5f4aebb170a7ac758176d5eaf5e88ed71accbc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 20:16:30 -0500 Subject: [PATCH 37/42] move test to the proper directory and test #[bench] --- .../termination-trait-in-test.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) rename src/test/run-pass/{ => rfc-1937-termination-trait}/termination-trait-in-test.rs (72%) diff --git a/src/test/run-pass/termination-trait-in-test.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs similarity index 72% rename from src/test/run-pass/termination-trait-in-test.rs rename to src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs index e67e0de5c318b..494500d522abe 100644 --- a/src/test/run-pass/termination-trait-in-test.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -11,8 +11,11 @@ // compile-flags: --test #![feature(termination_trait)] +#![feature(test)] +extern crate test; use std::num::ParseIntError; +use test::Bencher; #[test] fn is_a_num() -> Result<(), ParseIntError> { @@ -26,3 +29,15 @@ fn not_a_num() -> Result<(), ParseIntError> { let _: u32 = "abc".parse()?; Ok(()) } + +#[bench] +fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + Ok(()) +} + +#[bench] +#[should_panic] +fn test_a_neg_bench(_: &mut Bencher) -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} From 068e3832cd9c3c9ac43128e1056a8d8b05fe1406 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 07:34:00 -0500 Subject: [PATCH 38/42] update test -- we now give a slightly different error --- src/test/compile-fail/issue-12997-2.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 85d91bb2db202..8d3df68577bab 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,6 +15,3 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected type `for<'r> fn(&'r mut __test::test::Bencher)` -//~| found type `fn(isize) {bar}` -//~| expected mutable reference, found isize From 10f7c110928ee7d3db7fef15fd7dce776b17e161 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 10:11:06 -0500 Subject: [PATCH 39/42] re-export `assert_test_result` for use when testing libtest itself --- src/libtest/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 06a23cd8818ee..82077bc4cd482 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -83,8 +83,8 @@ const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in qu pub mod test { pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, - DynTestName, DynTestFn, run_test, test_main, test_main_static, filter_tests, - parse_opts, StaticBenchFn, ShouldPanic, Options}; + DynTestName, DynTestFn, assert_test_result, run_test, test_main, test_main_static, + filter_tests, parse_opts, StaticBenchFn, ShouldPanic, Options}; } pub mod stats; From 380e388a868ff694c4200d58f75e298416da743b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 7 Feb 2018 17:26:40 -0500 Subject: [PATCH 40/42] do not run MIR type checker twice --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 7ca8d0bdd500b..eafb12fab9645 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1585,6 +1585,10 @@ impl MirPass for TypeckMir { let id = tcx.hir.as_local_node_id(def_id).unwrap(); debug!("run_pass: {:?}", def_id); + if tcx.sess.nll() { + return; + } + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. From 2370b6052972377b67444e9146cdaf37fc36d85f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 18:46:02 -0500 Subject: [PATCH 41/42] update tests and reference files The type checker invokes the borrow checker for closures it finds, so removing the NLL type checker affects ordering of errors somewhat. --- .../borrowck/two-phase-nonrecv-autoref.rs | 12 +- .../projection-no-regions-closure.stderr | 94 ++++---- .../projection-one-region-closure.stderr | 102 ++++---- ...tion-one-region-trait-bound-closure.stderr | 126 +++++----- ...e-region-trait-bound-static-closure.stderr | 108 ++++----- ...tion-two-region-trait-bound-closure.stderr | 228 +++++++++--------- ...ram-closure-approximate-lower-bound.stderr | 28 +-- ...-closure-outlives-from-where-clause.stderr | 126 +++++----- 8 files changed, 410 insertions(+), 414 deletions(-) diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs index 795d45a776db5..c425ed554a6f8 100644 --- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs @@ -105,14 +105,10 @@ fn overloaded_call_traits() { //[lxl]~^^^ ERROR use of moved value: `*f` //[nll]~^^^^ ERROR cannot move a value of type //[nll]~^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^^ ERROR cannot move a value of type - //[nll]~^^^^^^^^ ERROR use of moved value: `*f` - //[g2p]~^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^^^^^^^^ ERROR use of moved value: `*f` + //[nll]~^^^^^^ ERROR use of moved value: `*f` + //[g2p]~^^^^^^^ ERROR cannot move a value of type + //[g2p]~^^^^^^^^ ERROR cannot move a value of type + //[g2p]~^^^^^^^^^ ERROR use of moved value: `*f` } twice_ten_sm(&mut |x| x + 1); diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index b2e98b7c2f6a4..30669dc4c2f8c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -25,53 +25,6 @@ note: External requirements = note: number of external vids: 3 = note: where ::Item: '_#2r -note: External requirements - --> $DIR/projection-no-regions-closure.rs:46:23 - | -46 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 3 - = note: where ::Item: '_#2r - -note: External requirements - --> $DIR/projection-no-regions-closure.rs:54:23 - | -54 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 4 - = note: where ::Item: '_#3r - -note: External requirements - --> $DIR/projection-no-regions-closure.rs:65:23 - | -65 | with_signature(x, |mut y| Box::new(y.next())) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box - ] - = note: number of external vids: 4 - = note: where ::Item: '_#3r - error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:36:23 | @@ -97,6 +50,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:46:23 + | +46 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 3 + = note: where ::Item: '_#2r + note: No external requirements --> $DIR/projection-no-regions-closure.rs:42:1 | @@ -113,6 +81,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:54:23 + | +54 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:54:23 | @@ -139,6 +123,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-no-regions-closure.rs:65:23 + | +65 | with_signature(x, |mut y| Box::new(y.next())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box + ] + = note: number of external vids: 4 + = note: where ::Item: '_#3r + note: No external requirements --> $DIR/projection-no-regions-closure.rs:60:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index bfe408342a868..946c1a8f37235 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -32,57 +32,6 @@ note: External requirements = note: where T: '_#2r = note: where '_#1r: '_#2r -note: External requirements - --> $DIR/projection-one-region-closure.rs:68:29 - | -68 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-closure.rs:90:29 - | -90 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-closure.rs:103:29 - | -103 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r - error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:56:29 | @@ -114,6 +63,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:68:29 + | +68 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:68:29 | @@ -146,6 +112,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:90:29 + | +90 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:90:29 | @@ -178,6 +161,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + = note: where '_#2r: '_#3r + note: No external requirements --> $DIR/projection-one-region-closure.rs:97:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 6cb54170d7a90..b26fa96fe6389 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -31,69 +31,6 @@ note: External requirements = note: number of external vids: 3 = note: where '_#1r: '_#2r -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 - | -59 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 - | -80 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 - | -91 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where '_#2r: '_#3r - -note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 - | -103 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where '_#1r: '_#2r - error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` --> $DIR/projection-one-region-trait-bound-closure.rs:48:20 | @@ -117,6 +54,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 + | +59 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:59:20 | @@ -141,6 +94,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 + | +80 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` --> $DIR/projection-one-region-trait-bound-closure.rs:80:20 | @@ -165,6 +134,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 + | +91 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where '_#2r: '_#3r + note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:86:1 | @@ -183,6 +168,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 + | +103 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where '_#1r: '_#2r + note: No external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:95:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 986676d28d920..98b033b6a0672 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -12,40 +12,28 @@ note: No external requirements ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 - | -56 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 | -75 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) +44 | | where +45 | | T: Anything<'b>, +46 | | { +47 | | with_signature(cell, t, |cell, t| require(cell, t)); +48 | | } + | |_^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + T ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 | -84 | with_signature(cell, t, |cell, t| require(cell, t)); +56 | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -53,35 +41,6 @@ note: No external requirements extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) ] -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 - | -96 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - -note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 - | -43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) -44 | | where -45 | | T: Anything<'b>, -46 | | { -47 | | with_signature(cell, t, |cell, t| require(cell, t)); -48 | | } - | |_^ - | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ - '_#1r, - T - ] - note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1 | @@ -100,6 +59,20 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + | +75 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1 | @@ -118,6 +91,20 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + | +84 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1 | @@ -136,6 +123,19 @@ note: No external requirements T ] +note: No external requirements + --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 + | +96 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + note: No external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1 | diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 21487899d3ba6..78775ce94addd 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -38,120 +38,6 @@ note: External requirements = note: number of external vids: 4 = note: where >::AssocType: '_#3r -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 - | -60 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 - | -81 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 - | -92 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 - | -101 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - '_#3r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) - ] - = note: number of external vids: 5 - = note: where >::AssocType: '_#4r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 - | -109 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where >::AssocType: '_#2r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 - | -120 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where >::AssocType: '_#3r - -note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 - | -132 | with_signature(cell, t, |cell, t| require(cell, t)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where >::AssocType: '_#2r - error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 | @@ -178,6 +64,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + | +60 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 | @@ -205,6 +108,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + | +81 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + error[E0309]: the associated type `>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 | @@ -232,6 +152,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 + | +92 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:87:1 | @@ -251,6 +188,23 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 + | +101 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + '_#3r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + ] + = note: number of external vids: 5 + = note: where >::AssocType: '_#4r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:96:1 | @@ -270,6 +224,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 + | +109 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` --> $DIR/projection-two-region-trait-bound-closure.rs:109:20 | @@ -293,6 +262,22 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 + | +120 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where >::AssocType: '_#3r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:115:1 | @@ -311,6 +296,21 @@ note: No external requirements T ] +note: External requirements + --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 + | +132 | with_signature(cell, t, |cell, t| require(cell, t)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where >::AssocType: '_#2r + note: No external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:124:1 | diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 023b58c927d86..f68a76c3d0de5 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -30,20 +30,6 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 - | -43 | twice(cell, value, |a, b| invoke(a, b)); - | ^^^^^^^^^^^^^^^^^^^ - | - = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ - T, - i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T)) - ] - = note: number of external vids: 2 - = note: where T: '_#1r - note: No external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1 | @@ -60,6 +46,20 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + | +43 | twice(cell, value, |a, b| invoke(a, b)); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ + T, + i16, + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T)) + ] + = note: number of external vids: 2 + = note: where T: '_#1r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 | diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 2dd13810ae48a..ed4d4b1e68f7f 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -31,69 +31,6 @@ note: External requirements = note: number of external vids: 2 = note: where T: '_#1r -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 - | -55 | with_signature(a, b, |x, y| { - | __________________________^ -56 | | // Key point of this test: -57 | | // -58 | | // The *closure* is being type-checked with all of its free -... | -67 | | require(&x, &y) -68 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where T: '_#2r - -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 - | -76 | with_signature(a, b, |x, y| { - | __________________________^ -77 | | //~^ ERROR the parameter type `T` may not live long enough -78 | | // See `correct_region` -79 | | require(&x, &y) -80 | | //~^ WARNING not reporting region error due to -Znll -81 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) - ] - = note: number of external vids: 3 - = note: where T: '_#2r - -note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 - | -90 | with_signature(a, b, |x, y| { - | __________________________^ -91 | | // See `correct_region` -92 | | require(&x, &y) -93 | | }) - | |_____^ - | - = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ - '_#1r, - '_#2r, - T, - i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) - ] - = note: number of external vids: 4 - = note: where T: '_#3r - error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 | @@ -125,6 +62,28 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 + | +55 | with_signature(a, b, |x, y| { + | __________________________^ +56 | | // Key point of this test: +57 | | // +58 | | // The *closure* is being type-checked with all of its free +... | +67 | | require(&x, &y) +68 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + note: No external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1 | @@ -142,6 +101,27 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + | +76 | with_signature(a, b, |x, y| { + | __________________________^ +77 | | //~^ ERROR the parameter type `T` may not live long enough +78 | | // See `correct_region` +79 | | require(&x, &y) +80 | | //~^ WARNING not reporting region error due to -Znll +81 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + ] + = note: number of external vids: 3 + = note: where T: '_#2r + error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 | @@ -173,6 +153,26 @@ note: No external requirements T ] +note: External requirements + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 + | +90 | with_signature(a, b, |x, y| { + | __________________________^ +91 | | // See `correct_region` +92 | | require(&x, &y) +93 | | }) + | |_____^ + | + = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + '_#1r, + '_#2r, + T, + i32, + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + ] + = note: number of external vids: 4 + = note: where T: '_#3r + note: No external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1 | From bcd996857e42a383c79ea9ae84994d3ad932ac4a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 23 Feb 2018 10:42:12 -0500 Subject: [PATCH 42/42] explain why we don't need to run type-checker when NLL is enabled --- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index eafb12fab9645..d57b8e78f18a9 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1585,6 +1585,8 @@ impl MirPass for TypeckMir { let id = tcx.hir.as_local_node_id(def_id).unwrap(); debug!("run_pass: {:?}", def_id); + // When NLL is enabled, the borrow checker runs the typeck + // itself, so we don't need this MIR pass anymore. if tcx.sess.nll() { return; }