From bee92b5327c437a4fbc471ee15627850264d5428 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 12 Apr 2019 22:03:41 +0300 Subject: [PATCH 01/32] Make deprecation lint `ambiguous_associated_items` deny-by-default --- src/librustc/lint/builtin.rs | 2 +- src/test/ui/type-alias-enum-variants-priority.rs | 1 - src/test/ui/type-alias-enum-variants-priority.stderr | 12 ++++-------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index cbdeda7b90206..79c11c444da57 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -382,7 +382,7 @@ declare_lint! { declare_lint! { pub AMBIGUOUS_ASSOCIATED_ITEMS, - Warn, + Deny, "ambiguous associated items" } diff --git a/src/test/ui/type-alias-enum-variants-priority.rs b/src/test/ui/type-alias-enum-variants-priority.rs index db1da2b12e256..82cd21b09d3e7 100644 --- a/src/test/ui/type-alias-enum-variants-priority.rs +++ b/src/test/ui/type-alias-enum-variants-priority.rs @@ -1,5 +1,4 @@ #![feature(type_alias_enum_variants)] -#![deny(ambiguous_associated_items)] enum E { V diff --git a/src/test/ui/type-alias-enum-variants-priority.stderr b/src/test/ui/type-alias-enum-variants-priority.stderr index dcf7dc77ed5ea..b8271807b835d 100644 --- a/src/test/ui/type-alias-enum-variants-priority.stderr +++ b/src/test/ui/type-alias-enum-variants-priority.stderr @@ -1,23 +1,19 @@ error: ambiguous associated item - --> $DIR/type-alias-enum-variants-priority.rs:15:15 + --> $DIR/type-alias-enum-variants-priority.rs:14:15 | LL | fn f() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | -note: lint level defined here - --> $DIR/type-alias-enum-variants-priority.rs:2:9 - | -LL | #![deny(ambiguous_associated_items)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[deny(ambiguous_associated_items)] on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57644 note: `V` could refer to variant defined here - --> $DIR/type-alias-enum-variants-priority.rs:5:5 + --> $DIR/type-alias-enum-variants-priority.rs:4:5 | LL | V | ^ note: `V` could also refer to associated type defined here - --> $DIR/type-alias-enum-variants-priority.rs:9:5 + --> $DIR/type-alias-enum-variants-priority.rs:8:5 | LL | type V; | ^^^^^^^ From a912664113394fdf3a7c26a93504ebfe54a66e5c Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Tue, 23 Apr 2019 17:39:26 -0400 Subject: [PATCH 02/32] report fatal errors during doctest parsing --- src/librustdoc/test.rs | 23 ++++++++++++++---- .../rustdoc-ui/failed-doctest-output.stdout | 4 ++-- src/test/rustdoc-ui/unparseable-doc-test.rs | 10 ++++++++ .../rustdoc-ui/unparseable-doc-test.stdout | 24 +++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc-ui/unparseable-doc-test.rs create mode 100644 src/test/rustdoc-ui/unparseable-doc-test.stdout diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index abf74158c938e..8064c3ebb8a52 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -166,9 +166,18 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, maybe_sysroot: Option, linker: Option, edition: Edition, persist_doctests: Option) { - // The test harness wants its own `main` and top-level functions, so - // never wrap the test in `fn main() { ... }`. - let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts); + let (test, line_offset) = match panic::catch_unwind(|| { + make_test(test, Some(cratename), as_test_harness, opts) + }) { + Ok((test, line_offset)) => (test, line_offset), + Err(cause) if cause.is::() => { + // If the parser used by `make_test` panicked due to a fatal error, pass the test code + // through unchanged. The error will be reported during compilation. + (test.to_owned(), 0) + }, + Err(cause) => panic::resume_unwind(cause), + }; + // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. let path = match filename { @@ -337,7 +346,13 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } } -/// Makes the test file. Also returns the number of lines before the code begins +/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of +/// lines before the test code begins. +/// +/// # Panics +/// +/// This function uses the compiler's parser internally. The parser will panic if it encounters a +/// fatal error while parsing the test. pub fn make_test(s: &str, cratename: Option<&str>, dont_insert_main: bool, diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index c9f59405ce012..7b1cd70273140 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -15,7 +15,7 @@ error[E0425]: cannot find value `no` in this scope error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:310:13 +thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:319:13 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. ---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- @@ -24,7 +24,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. -', src/librustdoc/test.rs:332:17 +', src/librustdoc/test.rs:341:17 failures: diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs new file mode 100644 index 0000000000000..18d6b32bf4037 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.rs @@ -0,0 +1,10 @@ +// compile-flags: --test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// failure-status: 101 +// rustc-env: RUST_BACKTRACE=0 + +/// ```rust +/// let x = 7; +/// "unterminated +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout new file mode 100644 index 0000000000000..7048ef2c58977 --- /dev/null +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/unparseable-doc-test.rs - foo (line 6) ... FAILED + +failures: + +---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ---- +error: unterminated double quote string + --> $DIR/unparseable-doc-test.rs:8:1 + | +2 | "unterminated + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +thread '$DIR/unparseable-doc-test.rs - foo (line 6)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:319:13 +note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. + + +failures: + $DIR/unparseable-doc-test.rs - foo (line 6) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out + From 0e7e9382fa1a6e50c976cd74ca420d7cb10591fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 18:12:57 -0700 Subject: [PATCH 03/32] Do not suggest incorrect syntax on pattern borrow error --- src/librustc_typeck/check/_match.rs | 25 ++++++++++++++----- src/test/ui/destructure-trait-ref.stderr | 2 -- .../ui/mismatched_types/issue-38371.stderr | 1 - 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f3cabced34dfc..715b82183a761 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -378,12 +378,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `fn foo(foo: &u32)` if let Some(mut err) = err { if let PatKind::Binding(..) = inner.node { - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) - { - err.help(&format!("did you mean `{}: &{}`?", - &snippet[1..], - expected)); + let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); + let parent = tcx.hir().get_by_hir_id(parent_id); + match parent { + hir::Node::Item(_) | + hir::Node::ForeignItem(_) | + hir::Node::TraitItem(_) | + hir::Node::ImplItem(_) => { // this pat is an argument + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(pat.span) + { // FIXME: turn into structured suggestion, will need + // a span that also includes the the type. + err.help(&format!( + "did you mean `{}: &{}`?", + &snippet[1..], + expected, + )); + } + } + _ => {} // don't provide the suggestion from above #55175 } } err.emit(); diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 34dd213e2b390..7f389299afba8 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -24,7 +24,6 @@ LL | let &&x = &1isize as &T; | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:36:11 @@ -34,7 +33,6 @@ LL | let &&&x = &(&1isize as &T); | = note: expected type `dyn T` found type `&_` - = help: did you mean `x: &dyn T`? error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:41:13 diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 236f742db3f71..30da48ba4a8ad 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -16,7 +16,6 @@ LL | fn agh(&&bar: &u32) { | = note: expected type `u32` found type `&_` - = help: did you mean `bar: &u32`? error[E0308]: mismatched types --> $DIR/issue-38371.rs:21:8 From 742b48dc39768fbafd5a072b4ee1dbcd207d12f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:02:54 -0700 Subject: [PATCH 04/32] Be more specific in the suggestion filtering --- src/librustc_typeck/check/_match.rs | 52 ++++++++++++++++--- src/test/ui/destructure-trait-ref.stderr | 10 +++- .../ui/mismatched_types/issue-38371.stderr | 5 +- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 715b82183a761..53d1ac7b02496 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -380,23 +380,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let PatKind::Binding(..) = inner.node { let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); let parent = tcx.hir().get_by_hir_id(parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); match parent { - hir::Node::Item(_) | - hir::Node::ForeignItem(_) | - hir::Node::TraitItem(_) | - hir::Node::ImplItem(_) => { // this pat is an argument + hir::Node::Item(hir::Item { + node: hir::ItemKind::Fn(..), .. + }) | + hir::Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(..), .. + }) | + hir::Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(..), .. + }) | + hir::Node::ImplItem(hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. + }) => { // this pat is likely an argument if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(pat.span) + .span_to_snippet(inner.span) { // FIXME: turn into structured suggestion, will need - // a span that also includes the the type. + // a span that also includes the the arg's type. err.help(&format!( "did you mean `{}: &{}`?", - &snippet[1..], + snippet, expected, )); } } - _ => {} // don't provide the suggestion from above #55175 + hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Match(..), .. + }) => { // rely on match ergonomics + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(inner.span) + { + err.span_suggestion( + pat.span, + "you can rely on match ergonomics and remove \ + the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + hir::Node::Pat(_) => { // nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map() + .span_to_snippet(inner.span) + { + err.span_suggestion( + pat.span, + "you can probaly remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 } } err.emit(); diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 7f389299afba8..47ecadfd01afb 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -20,7 +20,10 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:31:10 | LL | let &&x = &1isize as &T; - | ^^ expected trait T, found reference + | ^^ + | | + | expected trait T, found reference + | help: you can probaly remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` @@ -29,7 +32,10 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:36:11 | LL | let &&&x = &(&1isize as &T); - | ^^ expected trait T, found reference + | ^^ + | | + | expected trait T, found reference + | help: you can probaly remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 30da48ba4a8ad..833b8998c338a 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -12,7 +12,10 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:18:9 | LL | fn agh(&&bar: &u32) { - | ^^^^ expected u32, found reference + | ^^^^ + | | + | expected u32, found reference + | help: you can probaly remove the explicit borrow: `bar` | = note: expected type `u32` found type `&_` From ff6867338792042b13d401d7c2c3f0aee8d04e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:16:35 -0700 Subject: [PATCH 05/32] add tests --- src/test/ui/suggestions/match-ergonomics.rs | 40 ++++++++++++++++++ .../ui/suggestions/match-ergonomics.stderr | 41 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/test/ui/suggestions/match-ergonomics.rs create mode 100644 src/test/ui/suggestions/match-ergonomics.stderr diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs new file mode 100644 index 0000000000000..d75f8363cd221 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.rs @@ -0,0 +1,40 @@ +fn main() { + let x = vec![1i32]; + match &x[..] { + [&v] => {}, //~ ERROR mismatched types + _ => {}, + } + match x { + [&v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + match &x[..] { + [v] => {}, + _ => {}, + } + match &x[..] { + &[v] => {}, + _ => {}, + } + match x { + [v] => {}, //~ ERROR expected an array or slice + _ => {}, + } + let y = 1i32; + match &y { + &v => {}, + _ => {}, + } + match y { + &v => {}, //~ ERROR mismatched types + _ => {}, + } + match &y { + v => {}, + _ => {}, + } + match y { + v => {}, + _ => {}, + } +} diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr new file mode 100644 index 0000000000000..4239089b7cec7 --- /dev/null +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -0,0 +1,41 @@ +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:4:10 + | +LL | [&v] => {}, + | ^^ + | | + | expected i32, found reference + | help: you can probaly remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:8:9 + | +LL | [&v] => {}, + | ^^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0529]: expected an array or slice, found `std::vec::Vec` + --> $DIR/match-ergonomics.rs:20:9 + | +LL | [v] => {}, + | ^^^ pattern cannot match with input type `std::vec::Vec` + +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:29:9 + | +LL | &v => {}, + | ^^ expected i32, found reference + | + = note: expected type `i32` + found type `&_` +help: you can rely on match ergonomics and remove the explicit borrow + | +LL | v => {}, + | ^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0529. +For more information about an error, try `rustc --explain E0308`. From 693eea5784fc58e9d9a8cade7a5b2afa2f3dbd3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 19:56:50 -0700 Subject: [PATCH 06/32] review comments --- src/librustc_typeck/check/_match.rs | 116 +++++++++--------- src/test/ui/destructure-trait-ref.stderr | 4 +- .../ui/mismatched_types/issue-38371.stderr | 2 +- .../ui/suggestions/match-ergonomics.stderr | 2 +- 4 files changed, 60 insertions(+), 64 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 53d1ac7b02496..124afc5491e89 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,8 +1,8 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs}; use crate::check::coercion::CoerceMany; use crate::util::nodemap::FxHashMap; -use errors::Applicability; -use rustc::hir::{self, PatKind}; +use errors::{Applicability, DiagnosticBuilder}; +use rustc::hir::{self, PatKind, Pat}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer; @@ -377,64 +377,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - if let PatKind::Binding(..) = inner.node { - let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); - let parent = tcx.hir().get_by_hir_id(parent_id); - debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); - match parent { - hir::Node::Item(hir::Item { - node: hir::ItemKind::Fn(..), .. - }) | - hir::Node::ForeignItem(hir::ForeignItem { - node: hir::ForeignItemKind::Fn(..), .. - }) | - hir::Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(..), .. - }) | - hir::Node::ImplItem(hir::ImplItem { - node: hir::ImplItemKind::Method(..), .. - }) => { // this pat is likely an argument - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { // FIXME: turn into structured suggestion, will need - // a span that also includes the the arg's type. - err.help(&format!( - "did you mean `{}: &{}`?", - snippet, - expected, - )); - } - } - hir::Node::Expr(hir::Expr { - node: hir::ExprKind::Match(..), .. - }) => { // rely on match ergonomics - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { - err.span_suggestion( - pat.span, - "you can rely on match ergonomics and remove \ - the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } - hir::Node::Pat(_) => { // nested `&&pat` - if let Ok(snippet) = tcx.sess.source_map() - .span_to_snippet(inner.span) - { - err.span_suggestion( - pat.span, - "you can probaly remove the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } - _ => {} // don't provide suggestions in other cases #55175 - } - } + self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); err.emit(); } (rptr_ty, inner_ty) @@ -566,6 +509,59 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping. } + fn borrow_pat_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + pat: &Pat, + inner: &Pat, + expected: &Ty<'tcx>, + ) { + let tcx = self.tcx; + if let PatKind::Binding(..) = inner.node { + let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); + let parent = tcx.hir().get_by_hir_id(parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); + match parent { + hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) | + hir::Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(..), .. + }) | + hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) | + hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { + // this pat is likely an argument + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + // FIXME: turn into structured suggestion, will need a span that also + // includes the the arg's type. + err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); + } + } + hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) => { + // rely on match ergonomics + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can rely on match ergonomics and remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + hir::Node::Pat(_) => { + // nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can probably remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 + } + } + } + pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { if let PatKind::Binding(..) = inner.node { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 47ecadfd01afb..bc3013b78b38c 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -23,7 +23,7 @@ LL | let &&x = &1isize as &T; | ^^ | | | expected trait T, found reference - | help: you can probaly remove the explicit borrow: `x` + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` @@ -35,7 +35,7 @@ LL | let &&&x = &(&1isize as &T); | ^^ | | | expected trait T, found reference - | help: you can probaly remove the explicit borrow: `x` + | help: you can probably remove the explicit borrow: `x` | = note: expected type `dyn T` found type `&_` diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 833b8998c338a..a9347926bda0a 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -15,7 +15,7 @@ LL | fn agh(&&bar: &u32) { | ^^^^ | | | expected u32, found reference - | help: you can probaly remove the explicit borrow: `bar` + | help: you can probably remove the explicit borrow: `bar` | = note: expected type `u32` found type `&_` diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 4239089b7cec7..a064e2485ffe8 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -5,7 +5,7 @@ LL | [&v] => {}, | ^^ | | | expected i32, found reference - | help: you can probaly remove the explicit borrow: `v` + | help: you can probably remove the explicit borrow: `v` | = note: expected type `i32` found type `&_` From 14ca95066579f4ec3761fa171e9c9c6d7bd80ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 20:50:04 -0700 Subject: [PATCH 07/32] Fix style --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 124afc5491e89..88168a6950be4 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -514,7 +514,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err: &mut DiagnosticBuilder<'_>, pat: &Pat, inner: &Pat, - expected: &Ty<'tcx>, + expected: Ty<'tcx>, ) { let tcx = self.tcx; if let PatKind::Binding(..) = inner.node { From 6068478d56a05ab1aa4d9ad87046e1d5d47afd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 29 Apr 2019 20:58:29 -0700 Subject: [PATCH 08/32] Add if let test --- src/test/ui/suggestions/match-ergonomics.rs | 1 + src/test/ui/suggestions/match-ergonomics.stderr | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/ui/suggestions/match-ergonomics.rs b/src/test/ui/suggestions/match-ergonomics.rs index d75f8363cd221..c4fc01469bf65 100644 --- a/src/test/ui/suggestions/match-ergonomics.rs +++ b/src/test/ui/suggestions/match-ergonomics.rs @@ -37,4 +37,5 @@ fn main() { v => {}, _ => {}, } + if let [&v] = &x[..] {} //~ ERROR mismatched types } diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index a064e2485ffe8..9915eeb34fac1 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -35,7 +35,19 @@ help: you can rely on match ergonomics and remove the explicit borrow LL | v => {}, | ^ -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/match-ergonomics.rs:40:13 + | +LL | if let [&v] = &x[..] {} + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` + | + = note: expected type `i32` + found type `&_` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0529. For more information about an error, try `rustc --explain E0308`. From bf4d0adf2395a260b024586e105f2e109222201c Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 17:27:53 +0900 Subject: [PATCH 09/32] Rename to RUSTC_LOG --- src/bootstrap/native.rs | 2 +- src/librustc/infer/mod.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/test/run-make-fulldeps/libs-through-symlinks/Makefile | 2 +- src/test/run-pass/issues/issue-18075.rs | 2 +- src/test/run-pass/logging-only-prints-once.rs | 2 +- src/test/run-pass/logging_before_rt_started.rs | 2 +- src/test/run-pass/rustc-rust-log.rs | 2 +- src/test/run-pass/threads-sendsync/spawning-with-debug.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 96aed7293450c..285f9458c44b6 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -436,7 +436,7 @@ fn configure_cmake(builder: &Builder<'_>, } if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=warn"); + cfg.env("RUSTC_LOG", "sccache=warn"); } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e9b80c56e0c5c..3e5d6247e2b10 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -694,7 +694,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// potentially leaving "dangling type variables" behind. /// In such cases, an assertion will fail when attempting to /// register obligations, within a snapshot. Very useful, much - /// better than grovelling through megabytes of `RUST_LOG` output. + /// better than grovelling through megabytes of `RUSTC_LOG` output. /// /// HOWEVER, in some cases the flag is unhelpful. In particular, we /// sometimes create a "mini-fulfilment-cx" in which we enroll diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6a5accc8d7f05..5b42b049b5b18 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1163,7 +1163,7 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result Date: Tue, 30 Apr 2019 20:43:03 +0900 Subject: [PATCH 10/32] Add error for existential types --- src/librustc_passes/ast_validation.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 9dd8a7050fd28..a482f60897bed 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -679,6 +679,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "unions cannot have zero fields"); } } + ItemKind::Existential(ref bounds, _) => { + if !bounds.iter() + .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { + self.err_handler().span_err(item.span, "at least one trait must be specified"); + } + } _ => {} } From bb3549fce26355c79437d516b7afa4d4ddad924f Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 20:43:10 +0900 Subject: [PATCH 11/32] Fix tests --- .../existential-types-with-no-traits.rs | 14 ++++++++++++++ .../existential-types-with-no-traits.stderr | 14 ++++++++++++++ .../existential_types/generic_nondefining_use.rs | 2 ++ .../generic_nondefining_use.stderr | 10 ++++++++-- .../ui/existential_types/generic_not_used.rs | 1 + .../ui/existential_types/generic_not_used.stderr | 10 ++++++++-- .../generic_type_does_not_live_long_enough.rs | 1 + ...generic_type_does_not_live_long_enough.stderr | 8 +++++++- .../generic_underconstrained.rs | 1 + .../generic_underconstrained.stderr | 8 +++++++- .../generic_underconstrained2.rs | 2 ++ .../generic_underconstrained2.stderr | 16 ++++++++++++++-- .../ui/existential_types/unused_generic_param.rs | 5 ++--- .../unused_generic_param.stderr | 14 ++++++++++++++ 14 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/existential_types/existential-types-with-no-traits.rs create mode 100644 src/test/ui/existential_types/existential-types-with-no-traits.stderr create mode 100644 src/test/ui/existential_types/unused_generic_param.stderr diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.rs b/src/test/ui/existential_types/existential-types-with-no-traits.rs new file mode 100644 index 0000000000000..46339c73b1f1d --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.rs @@ -0,0 +1,14 @@ +#![feature(existential_type)] + +existential type Foo: 'static; +//~^ ERROR: at least one trait must be specified + +fn foo() -> Foo { + "foo" +} + +fn bar() -> impl 'static { //~ ERROR: at least one trait must be specified + "foo" +} + +fn main() {} diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr new file mode 100644 index 0000000000000..1464e8b48ebda --- /dev/null +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:3:1 + | +LL | existential type Foo: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/existential-types-with-no-traits.rs:10:13 + | +LL | fn bar() -> impl 'static { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/existential_types/generic_nondefining_use.rs b/src/test/ui/existential_types/generic_nondefining_use.rs index 75af5d9570ff2..ffc965aca47c9 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.rs +++ b/src/test/ui/existential_types/generic_nondefining_use.rs @@ -4,6 +4,8 @@ fn main() {} existential type Cmp: 'static; //~^ ERROR could not find defining uses +//~^^ ERROR: at least one trait must be specified + // not a defining use, because it doesn't define *all* possible generics fn cmp() -> Cmp { //~ ERROR defining existential type use does not fully define diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index ef579260f061c..7bde5f3ee5e69 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_nondefining_use.rs:5:1 + | +LL | existential type Cmp: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: defining existential type use does not fully define existential type - --> $DIR/generic_nondefining_use.rs:9:1 + --> $DIR/generic_nondefining_use.rs:11:1 | LL | / fn cmp() -> Cmp { LL | | 5u32 @@ -12,5 +18,5 @@ error: could not find defining uses LL | existential type Cmp: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/existential_types/generic_not_used.rs b/src/test/ui/existential_types/generic_not_used.rs index bfe7b8c4a1d53..054e6f5f2ade9 100644 --- a/src/test/ui/existential_types/generic_not_used.rs +++ b/src/test/ui/existential_types/generic_not_used.rs @@ -3,6 +3,7 @@ fn main() {} existential type WrongGeneric: 'static; +//~^ ERROR: at least one trait must be specified fn wrong_generic(_: U, v: V) -> WrongGeneric { //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index 1ae4ab65929f0..4bce35ea09dc3 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,5 +1,11 @@ +error: at least one trait must be specified + --> $DIR/generic_not_used.rs:5:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: type parameter `V` is part of concrete type but not used in parameter list for existential type - --> $DIR/generic_not_used.rs:7:73 + --> $DIR/generic_not_used.rs:8:73 | LL | fn wrong_generic(_: U, v: V) -> WrongGeneric { | _________________________________________________________________________^ @@ -8,5 +14,5 @@ LL | | v LL | | } | |_^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs index 02bb151ccb618..d9eedd6dca7c1 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.rs @@ -8,6 +8,7 @@ fn main() { existential type WrongGeneric: 'static; //~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { t diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index 002acc41553b6..1e4c49f3f316b 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 + | +LL | existential type WrongGeneric: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 | @@ -22,7 +28,7 @@ note: ...so that the type `T` will meet its required lifetime bounds LL | existential type WrongGeneric: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0310. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/existential_types/generic_underconstrained.rs b/src/test/ui/existential_types/generic_underconstrained.rs index 967faca067c1e..cc0db893c6aa7 100644 --- a/src/test/ui/existential_types/generic_underconstrained.rs +++ b/src/test/ui/existential_types/generic_underconstrained.rs @@ -4,6 +4,7 @@ fn main() {} trait Trait {} existential type Underconstrained: 'static; //~ ERROR the trait bound `T: Trait` +//~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index 8551a939e8ed8..d5e9ecc1abe77 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,3 +1,9 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained.rs:6:1 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 | @@ -7,6 +13,6 @@ LL | existential type Underconstrained: 'static; = help: consider adding a `where T: Trait` bound = note: the return type of a function must have a statically known size -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/generic_underconstrained2.rs b/src/test/ui/existential_types/generic_underconstrained2.rs index 98d9da832cfd3..c6263eacd53e3 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.rs +++ b/src/test/ui/existential_types/generic_underconstrained2.rs @@ -4,6 +4,7 @@ fn main() {} existential type Underconstrained: 'static; //~^ ERROR `U` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { @@ -12,6 +13,7 @@ fn underconstrained(_: U) -> Underconstrained { existential type Underconstrained2: 'static; //~^ ERROR `V` doesn't implement `std::fmt::Debug` +//~^^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index c7b6d6ade557c..df726dde42966 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,3 +1,15 @@ +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:5:1 + | +LL | existential type Underconstrained: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/generic_underconstrained2.rs:14:1 + | +LL | existential type Underconstrained2: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 | @@ -9,7 +21,7 @@ LL | existential type Underconstrained: 'static; = note: the return type of a function must have a statically known size error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:13:1 + --> $DIR/generic_underconstrained2.rs:14:1 | LL | existential type Underconstrained2: 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` @@ -18,6 +30,6 @@ LL | existential type Underconstrained2: 'static; = help: consider adding a `where V: std::fmt::Debug` bound = note: the return type of a function must have a statically known size -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/existential_types/unused_generic_param.rs b/src/test/ui/existential_types/unused_generic_param.rs index 7af6508788129..5455b39f4cbe2 100644 --- a/src/test/ui/existential_types/unused_generic_param.rs +++ b/src/test/ui/existential_types/unused_generic_param.rs @@ -1,18 +1,17 @@ -// compile-pass #![feature(existential_type)] fn main() { } -// test that unused generic parameters are ok existential type PartiallyDefined: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined(_: T) -> PartiallyDefined { 4u32 } -// test that unused generic parameters are ok existential type PartiallyDefined2: 'static; +//~^ ERROR: at least one trait must be specified fn partially_defined2(_: T) -> PartiallyDefined2 { 4u32 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr new file mode 100644 index 0000000000000..8c563e93ae55c --- /dev/null +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -0,0 +1,14 @@ +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:6:1 + | +LL | existential type PartiallyDefined: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: at least one trait must be specified + --> $DIR/unused_generic_param.rs:13:1 + | +LL | existential type PartiallyDefined2: 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From f56d2854436de7f0e00f5a76bf9dba4364ca4d31 Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 21:28:13 +0900 Subject: [PATCH 12/32] Use multispan --- src/librustc_passes/ast_validation.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index a482f60897bed..1f5a6d7914125 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -20,7 +20,7 @@ use syntax::ptr::P; use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; use errors::Applicability; use log::debug; @@ -682,7 +682,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Existential(ref bounds, _) => { if !bounds.iter() .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) { - self.err_handler().span_err(item.span, "at least one trait must be specified"); + let msp = MultiSpan::from_spans(bounds.iter() + .map(|bound| bound.span()).collect()); + self.err_handler().span_err(msp, "at least one trait must be specified"); } } _ => {} From db7f26566062b5444704aec669bbebbc2ff3a8d6 Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Tue, 30 Apr 2019 21:28:34 +0900 Subject: [PATCH 13/32] Fix spans --- .../existential-types-with-no-traits.stderr | 4 ++-- .../ui/existential_types/generic_nondefining_use.stderr | 4 ++-- src/test/ui/existential_types/generic_not_used.stderr | 4 ++-- .../generic_type_does_not_live_long_enough.stderr | 4 ++-- .../ui/existential_types/generic_underconstrained.stderr | 4 ++-- .../ui/existential_types/generic_underconstrained2.stderr | 8 ++++---- src/test/ui/existential_types/unused_generic_param.stderr | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/test/ui/existential_types/existential-types-with-no-traits.stderr b/src/test/ui/existential_types/existential-types-with-no-traits.stderr index 1464e8b48ebda..4b2fbc79d3bc2 100644 --- a/src/test/ui/existential_types/existential-types-with-no-traits.stderr +++ b/src/test/ui/existential_types/existential-types-with-no-traits.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/existential-types-with-no-traits.rs:3:1 + --> $DIR/existential-types-with-no-traits.rs:3:23 | LL | existential type Foo: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified --> $DIR/existential-types-with-no-traits.rs:10:13 diff --git a/src/test/ui/existential_types/generic_nondefining_use.stderr b/src/test/ui/existential_types/generic_nondefining_use.stderr index 7bde5f3ee5e69..d205d44c68c71 100644 --- a/src/test/ui/existential_types/generic_nondefining_use.stderr +++ b/src/test/ui/existential_types/generic_nondefining_use.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_nondefining_use.rs:5:1 + --> $DIR/generic_nondefining_use.rs:5:26 | LL | existential type Cmp: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: defining existential type use does not fully define existential type --> $DIR/generic_nondefining_use.rs:11:1 diff --git a/src/test/ui/existential_types/generic_not_used.stderr b/src/test/ui/existential_types/generic_not_used.stderr index 4bce35ea09dc3..d243233992b02 100644 --- a/src/test/ui/existential_types/generic_not_used.stderr +++ b/src/test/ui/existential_types/generic_not_used.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_not_used.rs:5:1 + --> $DIR/generic_not_used.rs:5:44 | LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: type parameter `V` is part of concrete type but not used in parameter list for existential type --> $DIR/generic_not_used.rs:8:73 diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr index 1e4c49f3f316b..2f76eea4460bd 100644 --- a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:9:35 | LL | existential type WrongGeneric: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0308]: mismatched types --> $DIR/generic_type_does_not_live_long_enough.rs:6:18 diff --git a/src/test/ui/existential_types/generic_underconstrained.stderr b/src/test/ui/existential_types/generic_underconstrained.stderr index d5e9ecc1abe77..35083a53eb343 100644 --- a/src/test/ui/existential_types/generic_underconstrained.stderr +++ b/src/test/ui/existential_types/generic_underconstrained.stderr @@ -1,8 +1,8 @@ error: at least one trait must be specified - --> $DIR/generic_underconstrained.rs:6:1 + --> $DIR/generic_underconstrained.rs:6:46 | LL | existential type Underconstrained: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/generic_underconstrained.rs:6:1 diff --git a/src/test/ui/existential_types/generic_underconstrained2.stderr b/src/test/ui/existential_types/generic_underconstrained2.stderr index df726dde42966..6ff783f33b96f 100644 --- a/src/test/ui/existential_types/generic_underconstrained2.stderr +++ b/src/test/ui/existential_types/generic_underconstrained2.stderr @@ -1,14 +1,14 @@ error: at least one trait must be specified - --> $DIR/generic_underconstrained2.rs:5:1 + --> $DIR/generic_underconstrained2.rs:5:56 | LL | existential type Underconstrained: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified - --> $DIR/generic_underconstrained2.rs:14:1 + --> $DIR/generic_underconstrained2.rs:14:57 | LL | existential type Underconstrained2: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error[E0277]: `U` doesn't implement `std::fmt::Debug` --> $DIR/generic_underconstrained2.rs:5:1 diff --git a/src/test/ui/existential_types/unused_generic_param.stderr b/src/test/ui/existential_types/unused_generic_param.stderr index 8c563e93ae55c..9d628d069d36c 100644 --- a/src/test/ui/existential_types/unused_generic_param.stderr +++ b/src/test/ui/existential_types/unused_generic_param.stderr @@ -1,14 +1,14 @@ error: at least one trait must be specified - --> $DIR/unused_generic_param.rs:6:1 + --> $DIR/unused_generic_param.rs:6:39 | LL | existential type PartiallyDefined: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: at least one trait must be specified - --> $DIR/unused_generic_param.rs:13:1 + --> $DIR/unused_generic_param.rs:13:40 | LL | existential type PartiallyDefined2: 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ error: aborting due to 2 previous errors From 748d978c648711d04cd3f3f06722e13c488e017a Mon Sep 17 00:00:00 2001 From: Yuki OKUSHI Date: Wed, 1 May 2019 00:36:51 +0900 Subject: [PATCH 14/32] Fix run-pass test --- src/test/run-pass/existential_type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/existential_type.rs b/src/test/run-pass/existential_type.rs index dfb195ec83062..b36435cf113f1 100644 --- a/src/test/run-pass/existential_type.rs +++ b/src/test/run-pass/existential_type.rs @@ -68,14 +68,14 @@ fn my_other_iter(u: U) -> MyOtherIter { } trait Trait {} -existential type GenericBound<'a, T: Trait>: 'a; +existential type GenericBound<'a, T: Trait>: Sized + 'a; fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> { t } mod pass_through { - pub existential type Passthrough: 'static; + pub existential type Passthrough: Sized + 'static; fn define_passthrough(t: T) -> Passthrough { t From ed08c6a985d0f69d2eac33e09440112c880c9fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 30 Apr 2019 10:59:30 -0700 Subject: [PATCH 15/32] review comments: change wording --- src/librustc_typeck/check/_match.rs | 14 ++------------ src/test/ui/suggestions/match-ergonomics.stderr | 9 ++++----- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 88168a6950be4..f5aa2e6ea5cea 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -535,19 +535,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); } } - hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) => { - // rely on match ergonomics - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { - err.span_suggestion( - pat.span, - "you can rely on match ergonomics and remove the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } + hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) | hir::Node::Pat(_) => { - // nested `&&pat` + // rely on match ergonomics or it might be nested `&&pat` if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { err.span_suggestion( pat.span, diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 9915eeb34fac1..b7497be6ceb36 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -26,14 +26,13 @@ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 | LL | &v => {}, - | ^^ expected i32, found reference + | ^^ + | | + | expected i32, found reference + | help: you can probably remove the explicit borrow: `v` | = note: expected type `i32` found type `&_` -help: you can rely on match ergonomics and remove the explicit borrow - | -LL | v => {}, - | ^ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:40:13 From 24fddb15e86a46e6057c8c0f2f0fb18844f50049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 1 May 2019 14:57:24 -0700 Subject: [PATCH 16/32] Resolve match arm ty when arms diverge --- src/librustc/infer/error_reporting/mod.rs | 2 +- src/test/ui/match/match-type-err-first-arm.rs | 24 ++++++++----- .../ui/match/match-type-err-first-arm.stderr | 35 ++++++++++++++----- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index c20a08fc5aea6..95b566d4a1b69 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -644,7 +644,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for sp in prior_arms { err.span_label(*sp, format!( "this is found to be of type `{}`", - last_ty, + self.resolve_type_vars_if_possible(&last_ty), )); } } else if let Some(sp) = prior_arms.last() { diff --git a/src/test/ui/match/match-type-err-first-arm.rs b/src/test/ui/match/match-type-err-first-arm.rs index b4b84ef8f1cec..8dfbf1019e9a4 100644 --- a/src/test/ui/match/match-type-err-first-arm.rs +++ b/src/test/ui/match/match-type-err-first-arm.rs @@ -3,8 +3,7 @@ fn main() { let _ = test_func2(1); } -fn test_func1(n: i32) -> i32 { - //~^ NOTE expected `i32` because of return type +fn test_func1(n: i32) -> i32 { //~ NOTE expected `i32` because of return type match n { 12 => 'b', //~^ ERROR mismatched types @@ -14,10 +13,8 @@ fn test_func1(n: i32) -> i32 { } fn test_func2(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types - 12 => 'b', - //~^ NOTE this is found to be of type `char` + let x = match n { //~ NOTE `match` arms have incompatible types + 12 => 'b', //~ NOTE this is found to be of type `char` _ => 42, //~^ ERROR match arms have incompatible types //~| NOTE expected char, found integer @@ -27,8 +24,7 @@ fn test_func2(n: i32) -> i32 { } fn test_func3(n: i32) -> i32 { - let x = match n { - //~^ NOTE `match` arms have incompatible types + let x = match n { //~ NOTE `match` arms have incompatible types 1 => 'b', 2 => 'b', 3 => 'b', @@ -43,3 +39,15 @@ fn test_func3(n: i32) -> i32 { }; x } + +fn test_func4() { + match Some(0u32) { //~ NOTE `match` arms have incompatible types + Some(x) => { + x //~ NOTE this is found to be of type `u32` + }, + None => {} + //~^ ERROR match arms have incompatible types + //~| NOTE expected u32, found () + //~| NOTE expected type `u32` + }; +} diff --git a/src/test/ui/match/match-type-err-first-arm.stderr b/src/test/ui/match/match-type-err-first-arm.stderr index a318e6cffb937..e0553fca683a5 100644 --- a/src/test/ui/match/match-type-err-first-arm.stderr +++ b/src/test/ui/match/match-type-err-first-arm.stderr @@ -1,24 +1,23 @@ error[E0308]: mismatched types - --> $DIR/match-type-err-first-arm.rs:9:15 + --> $DIR/match-type-err-first-arm.rs:8:15 | LL | fn test_func1(n: i32) -> i32 { | --- expected `i32` because of return type -... +LL | match n { LL | 12 => 'b', | ^^^ expected i32, found char error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:21:14 + --> $DIR/match-type-err-first-arm.rs:18:14 | LL | let x = match n { | _____________- -LL | | LL | | 12 => 'b', | | --- this is found to be of type `char` -LL | | LL | | _ => 42, | | ^^ expected char, found integer -... | +LL | | +LL | | LL | | LL | | }; | |_____- `match` arms have incompatible types @@ -27,13 +26,13 @@ LL | | }; found type `{integer}` error[E0308]: match arms have incompatible types - --> $DIR/match-type-err-first-arm.rs:39:14 + --> $DIR/match-type-err-first-arm.rs:35:14 | LL | let x = match n { | _____________- -LL | | LL | | 1 => 'b', LL | | 2 => 'b', +LL | | 3 => 'b', ... | LL | | 6 => 'b', | | --- this and all prior arms are found to be of type `char` @@ -48,6 +47,24 @@ LL | | }; = note: expected type `char` found type `{integer}` -error: aborting due to 3 previous errors +error[E0308]: match arms have incompatible types + --> $DIR/match-type-err-first-arm.rs:48:17 + | +LL | / match Some(0u32) { +LL | | Some(x) => { +LL | | x + | | - this is found to be of type `u32` +LL | | }, +LL | | None => {} + | | ^^ expected u32, found () +... | +LL | | +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `u32` + found type `()` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From c6e13bc20b5664ba9a8bd4152412bcc497e4f041 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 29 Apr 2019 17:45:22 -0700 Subject: [PATCH 17/32] Disallow non-explicit elided lifetimes in async fn --- src/librustc/error_codes.rs | 5 +- src/librustc/hir/lowering.rs | 68 ++++++++++++---- src/librustc/lint/builtin.rs | 80 ++++++++++++------- src/test/ui/async-fn-path-elision.rs | 16 ++++ src/test/ui/async-fn-path-elision.stderr | 8 ++ .../path-elided.rs | 2 +- .../path-elided.stderr | 5 +- .../trait-elided.rs | 2 +- .../trait-elided.stderr | 5 +- src/test/ui/issues/issue-10412.rs | 3 +- src/test/ui/issues/issue-10412.stderr | 21 +++-- 11 files changed, 150 insertions(+), 65 deletions(-) create mode 100644 src/test/ui/async-fn-path-elision.rs create mode 100644 src/test/ui/async-fn-path-elision.stderr diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 7f68b35d014cb..fd089fc688e32 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -362,10 +362,6 @@ struct Foo1 { x: &bool } // ^ expected lifetime parameter struct Foo2<'a> { x: &'a bool } // correct -impl Foo2 {} - // ^^^^ expected lifetime parameter -impl<'a> Foo2<'a> {} // correct - struct Bar1 { x: Foo2 } // ^^^^ expected lifetime parameter struct Bar2<'a> { x: Foo2<'a> } // correct @@ -2208,4 +2204,5 @@ register_diagnostics! { E0710, // an unknown tool name found in scoped lint E0711, // a feature has been declared with conflicting stability attributes // E0702, // replaced with a generic attribute input check + E0726, // non-explicit (not `'_`) elided lifetime in unsupported position } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index df455a725c5ba..0587b978105d7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2110,15 +2110,49 @@ impl<'a> LoweringContext<'a> { .expect("already checked that type args or bindings exist"); (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion)) }; - self.sess.buffer_lint_with_diagnostic( - ELIDED_LIFETIMES_IN_PATHS, - CRATE_NODE_ID, - path_span, - "hidden lifetime parameters in types are deprecated", - builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths( - expected_lifetimes, path_span, incl_angl_brckt, insertion_span, suggestion - ) - ); + match self.anonymous_lifetime_mode { + // In create-parameter mode we error here because we don't want to support + // deprecated impl elision in new features like impl elision and `async fn`, + // both of which work using the `CreateParameter` mode: + // + // impl Foo for std::cell::Ref // note lack of '_ + // async fn foo(_: std::cell::Ref) { ... } + AnonymousLifetimeMode::CreateParameter => { + let mut err = struct_span_err!( + self.sess, + path_span, + E0726, + "implicit elided lifetime not allowed here" + ); + crate::lint::builtin::add_elided_lifetime_in_path_suggestion( + &self.sess, + &mut err, + expected_lifetimes, + path_span, + incl_angl_brckt, + insertion_span, + suggestion, + ); + err.emit(); + } + AnonymousLifetimeMode::PassThrough | + AnonymousLifetimeMode::ReportError | + AnonymousLifetimeMode::Replace(_) => { + self.sess.buffer_lint_with_diagnostic( + ELIDED_LIFETIMES_IN_PATHS, + CRATE_NODE_ID, + path_span, + "hidden lifetime parameters in types are deprecated", + builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths( + expected_lifetimes, + path_span, + incl_angl_brckt, + insertion_span, + suggestion, + ) + ); + } + } } } @@ -5298,13 +5332,15 @@ impl<'a> LoweringContext<'a> { fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime { match self.anonymous_lifetime_mode { - // N.B., We intentionally ignore the create-parameter mode here - // and instead "pass through" to resolve-lifetimes, which will then - // report an error. This is because we don't want to support - // impl elision for deprecated forms like - // - // impl Foo for std::cell::Ref // note lack of '_ - AnonymousLifetimeMode::CreateParameter | + AnonymousLifetimeMode::CreateParameter => { + // We should have emitted E0726 when processing this path above + self.sess.delay_span_bug( + span, + "expected 'implicit elided lifetime not allowed' error", + ); + let id = self.sess.next_node_id(); + self.new_named_lifetime(id, span, hir::LifetimeName::Error) + } // This is the normal case. AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 28a2a1eaf6b49..a9481cb32a16b 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -477,6 +477,48 @@ pub enum BuiltinLintDiagnostics { RedundantImport(Vec<(Span, bool)>, ast::Ident), } +pub(crate) fn add_elided_lifetime_in_path_suggestion( + sess: &Session, + db: &mut DiagnosticBuilder<'_>, + n: usize, + path_span: Span, + incl_angl_brckt: bool, + insertion_span: Span, + anon_lts: String, +) { + let (replace_span, suggestion) = if incl_angl_brckt { + (insertion_span, anon_lts) + } else { + // When possible, prefer a suggestion that replaces the whole + // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` + // at a point (which makes for an ugly/confusing label) + if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { + // But our spans can get out of whack due to macros; if the place we think + // we want to insert `'_` isn't even within the path expression's span, we + // should bail out of making any suggestion rather than panicking on a + // subtract-with-overflow or string-slice-out-out-bounds (!) + // FIXME: can we do better? + if insertion_span.lo().0 < path_span.lo().0 { + return; + } + let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; + if insertion_index > snippet.len() { + return; + } + let (before, after) = snippet.split_at(insertion_index); + (path_span, format!("{}{}{}", before, anon_lts, after)) + } else { + (insertion_span, anon_lts) + } + }; + db.span_suggestion( + replace_span, + &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), + suggestion, + Applicability::MachineApplicable + ); +} + impl BuiltinLintDiagnostics { pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder<'_>) { match self { @@ -521,36 +563,14 @@ impl BuiltinLintDiagnostics { BuiltinLintDiagnostics::ElidedLifetimesInPaths( n, path_span, incl_angl_brckt, insertion_span, anon_lts ) => { - let (replace_span, suggestion) = if incl_angl_brckt { - (insertion_span, anon_lts) - } else { - // When possible, prefer a suggestion that replaces the whole - // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` - // at a point (which makes for an ugly/confusing label) - if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { - // But our spans can get out of whack due to macros; if the place we think - // we want to insert `'_` isn't even within the path expression's span, we - // should bail out of making any suggestion rather than panicking on a - // subtract-with-overflow or string-slice-out-out-bounds (!) - // FIXME: can we do better? - if insertion_span.lo().0 < path_span.lo().0 { - return; - } - let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; - if insertion_index > snippet.len() { - return; - } - let (before, after) = snippet.split_at(insertion_index); - (path_span, format!("{}{}{}", before, anon_lts, after)) - } else { - (insertion_span, anon_lts) - } - }; - db.span_suggestion( - replace_span, - &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), - suggestion, - Applicability::MachineApplicable + add_elided_lifetime_in_path_suggestion( + sess, + db, + n, + path_span, + incl_angl_brckt, + insertion_span, + anon_lts, ); } BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { diff --git a/src/test/ui/async-fn-path-elision.rs b/src/test/ui/async-fn-path-elision.rs new file mode 100644 index 0000000000000..8db7631ef4108 --- /dev/null +++ b/src/test/ui/async-fn-path-elision.rs @@ -0,0 +1,16 @@ +// edition:2018 + +#![feature(async_await, await_macro)] +#![allow(dead_code)] + +struct HasLifetime<'a>(&'a bool); + +async fn error(lt: HasLifetime) { //~ ERROR implicit elided lifetime not allowed here + if *lt.0 {} +} + +fn no_error(lt: HasLifetime) { + if *lt.0 {} +} + +fn main() {} diff --git a/src/test/ui/async-fn-path-elision.stderr b/src/test/ui/async-fn-path-elision.stderr new file mode 100644 index 0000000000000..3b311baba01de --- /dev/null +++ b/src/test/ui/async-fn-path-elision.stderr @@ -0,0 +1,8 @@ +error[E0726]: implicit elided lifetime not allowed here + --> $DIR/async-fn-path-elision.rs:8:20 + | +LL | async fn error(lt: HasLifetime) { + | ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + +error: aborting due to previous error + diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.rs b/src/test/ui/impl-header-lifetime-elision/path-elided.rs index 6532b0aebe74a..40a52efc7f9fc 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.rs +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.rs @@ -5,7 +5,7 @@ trait MyTrait { } struct Foo<'a> { x: &'a u32 } impl MyTrait for Foo { - //~^ ERROR missing lifetime specifier + //~^ ERROR implicit elided lifetime not allowed here } fn main() {} diff --git a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr index c9287ffba96d3..6500a2a55f667 100644 --- a/src/test/ui/impl-header-lifetime-elision/path-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/path-elided.stderr @@ -1,9 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/path-elided.rs:7:18 | LL | impl MyTrait for Foo { - | ^^^ expected lifetime parameter + | ^^^- help: indicate the anonymous lifetime: `<'_>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs index 3979eda740a82..102d259b0c87a 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.rs +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.rs @@ -3,7 +3,7 @@ trait MyTrait<'a> { } impl MyTrait for u32 { - //~^ ERROR missing lifetime specifier + //~^ ERROR implicit elided lifetime not allowed here } fn main() {} diff --git a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr index b742db1c75c19..ad97cb0abd623 100644 --- a/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr +++ b/src/test/ui/impl-header-lifetime-elision/trait-elided.stderr @@ -1,9 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/trait-elided.rs:5:6 | LL | impl MyTrait for u32 { - | ^^^^^^^ expected lifetime parameter + | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/issues/issue-10412.rs b/src/test/ui/issues/issue-10412.rs index a0bc2fc2f3c79..020585136856b 100644 --- a/src/test/ui/issues/issue-10412.rs +++ b/src/test/ui/issues/issue-10412.rs @@ -5,7 +5,8 @@ trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names //~^ ERROR lifetimes cannot use keyword names - //~| ERROR missing lifetime specifier + //~| ERROR implicit elided lifetime not allowed here + //~| ERROR the size for values of type `str` cannot be known at compilation time fn serialize(val : &'self str) -> Vec { //~ ERROR lifetimes cannot use keyword names vec![1] } diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index 48920813ae10d..0793dd99b4d12 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -29,23 +29,32 @@ LL | impl<'self> Serializable for &'self str { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:9:25 + --> $DIR/issue-10412.rs:10:25 | LL | fn serialize(val : &'self str) -> Vec { | ^^^^^ error: lifetimes cannot use keyword names - --> $DIR/issue-10412.rs:12:37 + --> $DIR/issue-10412.rs:13:37 | LL | fn deserialize(repr: &[u8]) -> &'self str { | ^^^^^ -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/issue-10412.rs:6:13 | LL | impl<'self> Serializable for &'self str { - | ^^^^^^^^^^^^^^^^^ expected lifetime parameter + | ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>` -error: aborting due to 8 previous errors +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-10412.rs:6:13 + | +LL | impl<'self> Serializable for &'self str { + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + +error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0277`. From 6ef39e69eac42e1cc86ec8eeb1b85c6b3a8784fa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 2 May 2019 20:34:26 +1000 Subject: [PATCH 18/32] Avoid repeated interning of static strings. `file_metadata_raw` interns the strings `""` and `""` very frequently. This commit avoids that, which reduces the number of symbols interned significantly and reduces instruction counts by up to 0.5% on some workloads. --- .../debuginfo/metadata.rs | 22 +++++++++++-------- src/librustc_codegen_llvm/debuginfo/mod.rs | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 765992fd2b70e..0d67865d71708 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -784,26 +784,30 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, file_name, defining_crate); - let directory = if defining_crate == LOCAL_CRATE { - &cx.sess().working_dir.0 + let file_name = &file_name.to_string(); + let file_name_symbol = Symbol::intern(file_name); + if defining_crate == LOCAL_CRATE { + let directory = &cx.sess().working_dir.0.to_string_lossy(); + file_metadata_raw(cx, file_name, Some(file_name_symbol), + directory, Some(Symbol::intern(directory))) } else { // If the path comes from an upstream crate we assume it has been made // independent of the compiler's working directory one way or another. - Path::new("") - }; - - file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy()) + file_metadata_raw(cx, file_name, Some(file_name_symbol), "", None) + } } pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - file_metadata_raw(cx, "", "") + file_metadata_raw(cx, "", None, "", None) } fn file_metadata_raw(cx: &CodegenCx<'ll, '_>, file_name: &str, - directory: &str) + file_name_symbol: Option, + directory: &str, + directory_symbol: Option) -> &'ll DIFile { - let key = (Symbol::intern(file_name), Symbol::intern(directory)); + let key = (file_name_symbol, directory_symbol); if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { return *file_metadata; diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 2154ac9b1d259..f3070a03b4ed5 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -63,7 +63,7 @@ pub struct CrateDebugContext<'a, 'tcx> { llcontext: &'a llvm::Context, llmod: &'a llvm::Module, builder: &'a mut DIBuilder<'a>, - created_files: RefCell>, + created_files: RefCell, Option), &'a DIFile>>, created_enum_disr_types: RefCell>, type_map: RefCell>, From 16fe8ccce95a9df185404c881c029fb0507e4821 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 29 Apr 2019 18:32:35 -0400 Subject: [PATCH 19/32] Remove the `self.mir` field from `ConstPropagator` --- src/librustc_mir/transform/const_prop.rs | 124 +++++++++++++---------- src/test/ui/consts/const-err.stderr | 12 ++- 2 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 2465adf46cdf4..2d89f73a95f69 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,18 +1,19 @@ //! Propagates constants for early reporting of statically known //! assertion failures - use rustc::hir::def::Def; -use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local}; -use rustc::mir::{NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind}; -use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem}; +use rustc::mir::{ + Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local, + NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, + TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, + SourceScope, SourceScopeLocalData, LocalDecl, Promoted, +}; use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult}; -use rustc::ty::{self, Instance, Ty, TyCtxt}; -use syntax::source_map::{Span, DUMMY_SP}; +use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use syntax::source_map::DUMMY_SP; use rustc::ty::subst::InternalSubsts; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::ty::ParamEnv; use rustc::ty::layout::{ LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, @@ -62,21 +63,33 @@ impl MirPass for ConstProp { let mut optimization_finder = ConstPropagator::new(mir, tcx, source); optimization_finder.visit_mir(mir); + // put back the data we stole from `mir` + std::mem::replace( + &mut mir.source_scope_local_data, + optimization_finder.source_scope_local_data + ); + std::mem::replace( + &mut mir.promoted, + optimization_finder.promoted + ); + trace!("ConstProp done for {:?}", source.def_id()); } } -type Const<'tcx> = (OpTy<'tcx>, Span); +type Const<'tcx> = OpTy<'tcx>; /// Finds optimization opportunities on the MIR. struct ConstPropagator<'a, 'mir, 'tcx:'a+'mir> { ecx: InterpretCx<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>, - mir: &'mir Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, places: IndexVec>>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, + source_scope_local_data: ClearCrossCrate>, + local_decls: IndexVec>, + promoted: IndexVec>, } impl<'a, 'b, 'tcx> LayoutOf for ConstPropagator<'a, 'b, 'tcx> { @@ -104,20 +117,33 @@ impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'a, 'b, 'tcx> { impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn new( - mir: &'mir Mir<'tcx>, + mir: &mut Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'a, 'mir, 'tcx> { let param_env = tcx.param_env(source.def_id()); let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env); + let can_const_prop = CanConstProp::check(mir); + let source_scope_local_data = std::mem::replace( + &mut mir.source_scope_local_data, + ClearCrossCrate::Clear + ); + let promoted = std::mem::replace( + &mut mir.promoted, + IndexVec::new() + ); + ConstPropagator { ecx, - mir, tcx, source, param_env, - can_const_prop: CanConstProp::check(mir), + can_const_prop, places: IndexVec::from_elem(None, &mir.local_decls), + source_scope_local_data, + //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_mir()` needs it + local_decls: mir.local_decls.clone(), + promoted, } } @@ -130,7 +156,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, { self.ecx.tcx.span = source_info.span; - let lint_root = match self.mir.source_scope_local_data { + let lint_root = match self.source_scope_local_data { ClearCrossCrate::Set(ref ivs) => { //FIXME(#51314): remove this check if source_info.scope.index() >= ivs.len() { @@ -252,12 +278,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_constant( &mut self, c: &Constant<'tcx>, - source_info: SourceInfo, ) -> Option> { - self.ecx.tcx.span = source_info.span; + self.ecx.tcx.span = c.span; match self.ecx.eval_const_to_op(*c.literal, None) { Ok(op) => { - Some((op, c.span)) + Some(op) }, Err(error) => { let err = error_to_const_error(&self.ecx, error); @@ -273,11 +298,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Place::Projection(ref proj) => match proj.elem { ProjectionElem::Field(field, _) => { trace!("field proj on {:?}", proj.base); - let (base, span) = self.eval_place(&proj.base, source_info)?; + let base = self.eval_place(&proj.base, source_info)?; let res = self.use_ecx(source_info, |this| { this.ecx.operand_field(base, field.index() as u64) })?; - Some((res, span)) + Some(res) }, // We could get more projections by using e.g., `operand_projection`, // but we do not even have the stack frame set up properly so @@ -301,11 +326,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - let mir = &this.mir.promoted[promoted]; + let mir = &this.promoted[promoted]; eval_promoted(this.tcx, cid, mir, this.param_env) })?; trace!("evaluated promoted {:?} to {:?}", promoted, res); - Some((res.into(), source_info.span)) + Some(res.into()) }, _ => None, } @@ -313,7 +338,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { match *op { - Operand::Constant(ref c) => self.eval_constant(c, source_info), + Operand::Constant(ref c) => self.eval_constant(c), | Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place, source_info), } @@ -337,18 +362,18 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Rvalue::Discriminant(..) => None, Rvalue::Cast(kind, ref operand, _) => { - let (op, span) = self.eval_operand(operand, source_info)?; + let op = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { let dest = this.ecx.allocate(place_layout, MemoryKind::Stack); this.ecx.cast(op, kind, dest.into())?; - Ok((dest.into(), span)) + Ok(dest.into()) }) } // FIXME(oli-obk): evaluate static/constant slice lengths Rvalue::Len(_) => None, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(( + type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( ImmTy { imm: Immediate::Scalar( Scalar::Bits { @@ -357,9 +382,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { }.into() ), layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, - }.into(), - span, - ))) + }.into() + )) } Rvalue::UnaryOp(op, ref arg) => { let def_id = if self.tcx.is_closure(self.source.def_id()) { @@ -373,7 +397,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { return None; } - let (arg, _) = self.eval_operand(arg, source_info)?; + let arg = self.eval_operand(arg, source_info)?; let val = self.use_ecx(source_info, |this| { let prim = this.ecx.read_immediate(arg)?; match op { @@ -395,7 +419,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: Immediate::Scalar(val.into()), layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -413,20 +437,20 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(right.0) + this.ecx.read_immediate(right) })?; if op == BinOp::Shr || op == BinOp::Shl { - let left_ty = left.ty(self.mir, self.tcx); + let left_ty = left.ty(&self.local_decls, self.tcx); let left_bits = self .tcx .layout_of(self.param_env.and(left_ty)) .unwrap() .size .bits(); - let right_size = right.0.layout.size; + let right_size = right.layout.size; let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.mir.source_scope_local_data { + let source_scope_local_data = match self.source_scope_local_data { ClearCrossCrate::Set(ref data) => data, ClearCrossCrate::Clear => return None, }; @@ -446,7 +470,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { } let left = self.eval_operand(left, source_info)?; let l = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(left.0) + this.ecx.read_immediate(left) })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); let (val, overflow) = self.use_ecx(source_info, |this| { @@ -469,7 +493,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { imm: val, layout: place_layout, }; - Some((res.into(), span)) + Some(res.into()) }, } } @@ -544,8 +568,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { ) { trace!("visit_constant: {:?}", constant); self.super_constant(constant, location); - let source_info = *self.mir.source_info(location); - self.eval_constant(constant, source_info); + self.eval_constant(constant); } fn visit_statement( @@ -556,7 +579,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { trace!("visit_statement: {:?}", statement); if let StatementKind::Assign(ref place, ref rval) = statement.kind { let place_ty: Ty<'tcx> = place - .ty(&self.mir.local_decls, self.tcx) + .ty(&self.local_decls, self.tcx) .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { @@ -574,18 +597,18 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { self.super_statement(statement, location); } - fn visit_terminator_kind( + fn visit_terminator( &mut self, - kind: &TerminatorKind<'tcx>, + terminator: &Terminator<'tcx>, location: Location, ) { - self.super_terminator_kind(kind, location); - let source_info = *self.mir.source_info(location); - if let TerminatorKind::Assert { expected, msg, cond, .. } = kind { - if let Some(value) = self.eval_operand(cond, source_info) { + self.super_terminator(terminator, location); + let source_info = terminator.source_info;; + if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind { + if let Some(value) = self.eval_operand(&cond, source_info) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); - if expected != self.ecx.read_scalar(value.0).unwrap() { + if expected != self.ecx.read_scalar(value).unwrap() { // poison all places this operand references so that further code // doesn't use the invalid value match cond { @@ -600,12 +623,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { }, Operand::Constant(_) => {} } - let span = self.mir[location.block] - .terminator - .as_ref() - .unwrap() - .source_info - .span; + let span = terminator.source_info.span; let hir_id = self .tcx .hir() @@ -621,7 +639,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { let len = self .eval_operand(len, source_info) .expect("len must be const"); - let len = match self.ecx.read_scalar(len.0) { + let len = match self.ecx.read_scalar(len) { Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) => bits, @@ -630,7 +648,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { let index = self .eval_operand(index, source_info) .expect("index must be const"); - let index = match self.ecx.read_scalar(index.0) { + let index = match self.ecx.read_scalar(index) { Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) => bits, diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index 0ee9ecdef451d..429e2ae7600d6 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -13,11 +13,17 @@ LL | #![warn(const_err)] | ^^^^^^^^^ error[E0080]: erroneous constant used - --> $DIR/const-err.rs:14:15 + --> $DIR/const-err.rs:14:16 | LL | black_box((FOO, FOO)); - | ^^^^^^^^^^ referenced constant has errors + | ^^^ referenced constant has errors -error: aborting due to previous error +error[E0080]: erroneous constant used + --> $DIR/const-err.rs:14:21 + | +LL | black_box((FOO, FOO)); + | ^^^ referenced constant has errors + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. From cac07eba5355a4c29532b180e394333167e10c63 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 2 May 2019 08:48:08 -0400 Subject: [PATCH 20/32] Fix failing test --- src/test/ui/consts/const-err.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/consts/const-err.rs b/src/test/ui/consts/const-err.rs index 8cc3dc7f58744..7dfcda69058ac 100644 --- a/src/test/ui/consts/const-err.rs +++ b/src/test/ui/consts/const-err.rs @@ -13,4 +13,5 @@ const FOO: u8 = [5u8][1]; fn main() { black_box((FOO, FOO)); //~^ ERROR erroneous constant used + //~| ERROR erroneous constant } From 8b82f685a57d6a1a3567c2ca6e77efedbedefac2 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:01:46 +0300 Subject: [PATCH 21/32] Make find_attr_val a little bit more precise `find_attr_val(&line, "since")` returns `Some(", issue = ")` when `line` is set to the following line: ``` [unstable(feature = "checked_duration_since", issue = "58402")] ``` Make `find_attr_val` use regex that is a little bit more precise (requires `=` after key name). It still does not handle all cases (e.g., extra leading chars in key name, or escaped quotes in value), but is good enough for now. --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/features.rs | 19 +++++++++++++++---- src/tools/tidy/src/lib.rs | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd6a7a5604edf..79ef359bdac5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3565,6 +3565,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f7b491823f838..f5db2487618d6 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Alex Crichton "] [dependencies] +regex = "1" serde = "1.0.8" serde_derive = "1.0.8" serde_json = "1.0.2" diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 8239fd9dce0c1..f2b17c7471109 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -14,6 +14,8 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::path::Path; +use regex::{Regex, escape}; + #[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, @@ -151,10 +153,19 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - line.find(attr) - .and_then(|i| line[i..].find('"').map(|j| i + j + 1)) - .and_then(|i| line[i..].find('"').map(|j| (i, i + j))) - .map(|(i, j)| &line[i..j]) + let r = Regex::new(&format!(r#"{} *= *"([^"]*)""#, escape(attr))) + .expect("malformed regex for find_attr_val"); + r.captures(line) + .and_then(|c| c.get(1)) + .map(|m| m.as_str()) +} + +#[test] +fn test_find_attr_val() { + let s = r#"#[unstable(feature = "checked_duration_since", issue = "58402")]"#; + assert_eq!(find_attr_val(s, "feature"), Some("checked_duration_since")); + assert_eq!(find_attr_val(s, "issue"), Some("58402")); + assert_eq!(find_attr_val(s, "since"), None); } fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c4a1246ffdf55..30080452edc01 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -5,6 +5,7 @@ #![deny(rust_2018_idioms)] +extern crate regex; extern crate serde_json; #[macro_use] extern crate serde_derive; From b7f55ca238a70f6738b14f1fded0fb9a47957343 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:39:55 +0300 Subject: [PATCH 22/32] Assign group and parse since for Feature --- src/tools/tidy/src/features.rs | 62 +++++++++++++++++++----- src/tools/tidy/src/features/version.rs | 66 ++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 src/tools/tidy/src/features/version.rs diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index f2b17c7471109..fe2aa0fd70fe3 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -16,6 +16,12 @@ use std::path::Path; use regex::{Regex, escape}; +mod version; +use self::version::Version; + +const FEATURE_GROUP_START_PREFIX: &str = "// feature group start:"; +const FEATURE_GROUP_END_PREFIX: &str = "// feature group end"; + #[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, @@ -37,9 +43,10 @@ impl fmt::Display for Status { #[derive(Debug, Clone)] pub struct Feature { pub level: Status, - pub since: String, + pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, + pub group: Option, } pub type Features = HashMap; @@ -136,14 +143,16 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { name, "lang", feature.level, - feature.since)); + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string()))); } for (name, feature) in lib_features { lines.push(format!("{:<32} {:<8} {:<12} {:<8}", name, "lib", feature.level, - feature.since)); + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string()))); } lines.sort(); @@ -188,6 +197,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { // without one inside `// no tracking issue START` and `// no tracking issue END`. let mut next_feature_omits_tracking_issue = false; + let mut next_feature_group = None; + contents.lines().zip(1..) .filter_map(|(line, line_number)| { let line = line.trim(); @@ -205,6 +216,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => {} } + if line.starts_with(FEATURE_GROUP_START_PREFIX) { + let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); + next_feature_group = Some(group.to_owned()); + return None; + } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { + next_feature_group = None; + return None; + } + let mut parts = line.split(','); let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) { Some("active") => Status::Unstable, @@ -213,7 +233,20 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => return None, }; let name = parts.next().unwrap().trim(); - let since = parts.next().unwrap().trim().trim_matches('"'); + let since_str = parts.next().unwrap().trim().trim_matches('"'); + let since = match since_str.parse() { + Ok(since) => Some(since), + Err(err) => { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({})", + line_number, + since_str, + err, + ); + None + } + }; let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { @@ -233,9 +266,10 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { Some((name.to_owned(), Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, + group: next_feature_group.clone(), })) }) .collect() @@ -250,9 +284,10 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { // add it to the set of known library features so we can still generate docs. lib_features.insert("compiler_builtins_lib".to_owned(), Feature { level: Status::Unstable, - since: String::new(), + since: None, has_gate_test: false, tracking_issue: None, + group: None, }); map_lib_features(base_src_path, @@ -351,12 +386,13 @@ fn map_lib_features(base_src_path: &Path, }; let feature = Feature { level: Status::Unstable, - since: "None".to_owned(), + since: None, has_gate_test: false, // FIXME(#57563): #57563 is now used as a common tracking issue, // although we would like to have specific tracking issues for each // `rustc_const_unstable` in the future. tracking_issue: Some(57563), + group: None, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -372,20 +408,24 @@ fn map_lib_features(base_src_path: &Path, Some(name) => name, None => err!("malformed stability attribute"), }; - let since = match find_attr_val(line, "since") { - Some(name) => name, + let since = match find_attr_val(line, "since").map(|x| x.parse()) { + Some(Ok(since)) => Some(since), + Some(Err(_err)) => { + err!("malformed since attribute"); + }, None if level == Status::Stable => { err!("malformed stability attribute"); } - None => "None", + None => None, }; let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap()); let feature = Feature { level, - since: since.to_owned(), + since, has_gate_test: false, tracking_issue, + group: None, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs new file mode 100644 index 0000000000000..0bab1427be849 --- /dev/null +++ b/src/tools/tidy/src/features/version.rs @@ -0,0 +1,66 @@ +use std::str::FromStr; +use std::num::ParseIntError; +use std::fmt; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + parts: Vec, +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let x = self.parts.iter().map(|x| x.to_string()).collect::>().join("."); + f.pad(&x) + } +} + +impl FromStr for Version { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + let parts = s.split('.').map(|part| part.parse()).collect::>()?; + Ok(Version { parts }) + } +} + +#[cfg(test)] +mod test { + use super::Version; + + #[test] + fn test_try_from_invalid_version() { + assert!("".parse::().is_err()); + assert!("hello".parse::().is_err()); + assert!("1.32.hi".parse::().is_err()); + assert!("1.32..1".parse::().is_err()); + } + + #[test] + fn test_try_from_single() { + assert_eq!("1.32.0".parse(), Ok(Version { parts: vec![1, 32, 0] })); + assert_eq!("1.0.0".parse(), Ok(Version { parts: vec![1, 0, 0] })); + } + + #[test] + fn test_compare() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + assert!(v_1_0_0 < v_1_32_1); + assert!(v_1_0_0 < v_1_32); + assert!(v_1_32 < v_1_32_1); + } + + #[test] + fn test_to_string() { + let v_1_0_0 = "1.0.0".parse::().unwrap(); + let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_1 = "1.32.1".parse::().unwrap(); + + assert_eq!(v_1_0_0.to_string(), "1.0.0"); + assert_eq!(v_1_32.to_string(), "1.32"); + assert_eq!(v_1_32_1.to_string(), "1.32.1"); + assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 "); + assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1"); + } +} From d5ba6d4b3cef4f7f54295d3a475411cedf1254fb Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Mon, 29 Apr 2019 20:51:19 +0300 Subject: [PATCH 23/32] Ensure language features in group are sorted by since --- src/tools/tidy/src/features.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index fe2aa0fd70fe3..d014c43f3b3f2 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -7,6 +7,7 @@ //! * Library features have at most one stability level. //! * Library features have at most one `since` value. //! * All unstable lang features have tests to ensure they are actually unstable. +//! * Language features in a group are sorted by `since` value. use std::collections::HashMap; use std::fmt; @@ -198,6 +199,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { let mut next_feature_omits_tracking_issue = false; let mut next_feature_group = None; + let mut prev_since = None; contents.lines().zip(1..) .filter_map(|(line, line_number)| { @@ -219,9 +221,11 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { if line.starts_with(FEATURE_GROUP_START_PREFIX) { let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); next_feature_group = Some(group.to_owned()); + prev_since = None; return None; } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { next_feature_group = None; + prev_since = None; return None; } @@ -233,6 +237,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { _ => return None, }; let name = parts.next().unwrap().trim(); + let since_str = parts.next().unwrap().trim().trim_matches('"'); let since = match since_str.parse() { Ok(since) => Some(since), @@ -247,6 +252,18 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { None } }; + if next_feature_group.is_some() { + if prev_since > since { + tidy_error!( + bad, + "libsyntax/feature_gate.rs:{}: feature {} is not sorted by since", + line_number, + name, + ); + } + prev_since = since.clone(); + } + let issue_str = parts.next().unwrap().trim(); let tracking_issue = if issue_str.starts_with("None") { if level == Status::Unstable && !next_feature_omits_tracking_issue { From d54477e97415c8c4931533f98ebf2704cd60e9b4 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:01:01 +0300 Subject: [PATCH 24/32] Address review comments --- src/tools/tidy/src/features.rs | 57 +++++++++++++++++----------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d014c43f3b3f2..c7a109e050987 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -20,8 +20,8 @@ use regex::{Regex, escape}; mod version; use self::version::Version; -const FEATURE_GROUP_START_PREFIX: &str = "// feature group start:"; -const FEATURE_GROUP_END_PREFIX: &str = "// feature group end"; +const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start:"; +const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; #[derive(Debug, PartialEq, Clone)] pub enum Status { @@ -47,7 +47,6 @@ pub struct Feature { pub since: Option, pub has_gate_test: bool, pub tracking_issue: Option, - pub group: Option, } pub type Features = HashMap; @@ -139,22 +138,8 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } let mut lines = Vec::new(); - for (name, feature) in features.iter() { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lang", - feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string()))); - } - for (name, feature) in lib_features { - lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, - "lib", - feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string()))); - } + lines.extend(format_features(&features, "lang")); + lines.extend(format_features(&lib_features, "lib")); lines.sort(); for line in lines { @@ -162,8 +147,19 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } } +fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { + features.iter().map(move |(name, feature)| { + format!("{:<32} {:<8} {:<12} {:<8}", + name, + family, + feature.level, + feature.since.as_ref().map_or("None".to_owned(), + |since| since.to_string())) + }) +} + fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - let r = Regex::new(&format!(r#"{} *= *"([^"]*)""#, escape(attr))) + let r = Regex::new(&format!(r#"{}\s*=\s*"([^"]*)""#, escape(attr))) .expect("malformed regex for find_attr_val"); r.captures(line) .and_then(|c| c.get(1)) @@ -219,6 +215,15 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } if line.starts_with(FEATURE_GROUP_START_PREFIX) { + if next_feature_group.is_some() { + tidy_error!( + bad, + // ignore-tidy-linelength + "libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one", + line_number, + ); + } + let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); next_feature_group = Some(group.to_owned()); prev_since = None; @@ -286,7 +291,6 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { since, has_gate_test: false, tracking_issue, - group: next_feature_group.clone(), })) }) .collect() @@ -304,7 +308,6 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { since: None, has_gate_test: false, tracking_issue: None, - group: None, }); map_lib_features(base_src_path, @@ -399,7 +402,7 @@ fn map_lib_features(base_src_path: &Path, // `const fn` features are handled specially. let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; let feature = Feature { level: Status::Unstable, @@ -409,7 +412,6 @@ fn map_lib_features(base_src_path: &Path, // although we would like to have specific tracking issues for each // `rustc_const_unstable` in the future. tracking_issue: Some(57563), - group: None, }; mf(Ok((feature_name, feature)), file, i + 1); continue; @@ -423,15 +425,15 @@ fn map_lib_features(base_src_path: &Path, }; let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => err!("malformed stability attribute"), + None => err!("malformed stability attribute: missing `feature` key"), }; let since = match find_attr_val(line, "since").map(|x| x.parse()) { Some(Ok(since)) => Some(since), Some(Err(_err)) => { - err!("malformed since attribute"); + err!("malformed stability attribute: can't parse `since` key"); }, None if level == Status::Stable => { - err!("malformed stability attribute"); + err!("malformed stability attribute: missing the `since` key"); } None => None, }; @@ -442,7 +444,6 @@ fn map_lib_features(base_src_path: &Path, since, has_gate_test: false, tracking_issue, - group: None, }; if line.contains(']') { mf(Ok((feature_name, feature)), file, i + 1); From 90d3fa223d82cee5430c71d117b6be2922a256b3 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:15:00 +0300 Subject: [PATCH 25/32] Make tidy::version::Version a [u32; 3] --- src/libstd/sys/redox/ext/net.rs | 82 +++++++++++++------------- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/features/version.rs | 38 ++++++++---- 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 096d0681959cd..b3ef5f3064c16 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -1,4 +1,4 @@ -#![stable(feature = "unix_socket_redox", since = "1.29")] +#![stable(feature = "unix_socket_redox", since = "1.29.0")] //! Unix-specific networking functionality @@ -27,7 +27,7 @@ use crate::sys::{cvt, fd::FileDesc, syscall}; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` #[derive(Clone)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct SocketAddr(()); impl SocketAddr { @@ -55,7 +55,7 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn as_pathname(&self) -> Option<&Path> { None } @@ -83,12 +83,12 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.is_unnamed(), true); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn is_unnamed(&self) -> bool { false } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "SocketAddr") @@ -109,10 +109,10 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixStream(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -143,7 +143,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -174,7 +174,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -198,7 +198,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -213,7 +213,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -228,7 +228,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -267,7 +267,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -306,7 +306,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -323,7 +323,7 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -340,7 +340,7 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -355,7 +355,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -375,7 +375,7 @@ impl UnixStream { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -397,13 +397,13 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -415,7 +415,7 @@ impl io::Read for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -427,7 +427,7 @@ impl<'a> io::Read for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -438,7 +438,7 @@ impl io::Write for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -449,21 +449,21 @@ impl<'a> io::Write for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -498,10 +498,10 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct UnixListener(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -529,7 +529,7 @@ impl UnixListener { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -563,7 +563,7 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } @@ -583,7 +583,7 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -599,7 +599,7 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -615,7 +615,7 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -636,7 +636,7 @@ impl UnixListener { /// /// # Platform specific /// On Redox this always returns `None`. - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -672,34 +672,34 @@ impl UnixListener { /// } /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.29")] + #[stable(feature = "unix_socket_redox", since = "1.29.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -740,12 +740,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } -#[stable(feature = "unix_socket_redox", since = "1.29")] +#[stable(feature = "unix_socket_redox", since = "1.29.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index c7a109e050987..afadedd8b6bbb 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -249,7 +249,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { Err(err) => { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({})", + "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})", line_number, since_str, err, diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 0bab1427be849..7ea788a85180b 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -1,10 +1,11 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; +use std::convert::TryInto; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { - parts: Vec, + parts: [u32; 3], } impl fmt::Display for Version { @@ -14,12 +15,27 @@ impl fmt::Display for Version { } } +#[derive(Debug, PartialEq, Eq)] +pub enum ParseVersionError { + ParseIntError(ParseIntError), + // core::array::TryFromSlice is not exported from std, so we invent our own variant + WrongNumberOfParts +} + +impl From for ParseVersionError { + fn from(err: ParseIntError) -> Self { + ParseVersionError::ParseIntError(err) + } +} + impl FromStr for Version { - type Err = ParseIntError; + type Err = ParseVersionError; fn from_str(s: &str) -> Result { - let parts = s.split('.').map(|part| part.parse()).collect::>()?; - Ok(Version { parts }) + let parts: Vec<_> = s.split('.').map(|part| part.parse()).collect::>()?; + Ok(Self { + parts: parts.as_slice().try_into() .or(Err(ParseVersionError::WrongNumberOfParts))?, + }) } } @@ -33,32 +49,32 @@ mod test { assert!("hello".parse::().is_err()); assert!("1.32.hi".parse::().is_err()); assert!("1.32..1".parse::().is_err()); + assert!("1.32".parse::().is_err()); + assert!("1.32.0.1".parse::().is_err()); } #[test] fn test_try_from_single() { - assert_eq!("1.32.0".parse(), Ok(Version { parts: vec![1, 32, 0] })); - assert_eq!("1.0.0".parse(), Ok(Version { parts: vec![1, 0, 0] })); + assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] })); + assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] })); } #[test] fn test_compare() { let v_1_0_0 = "1.0.0".parse::().unwrap(); - let v_1_32 = "1.32".parse::().unwrap(); + let v_1_32_0 = "1.32.0".parse::().unwrap(); let v_1_32_1 = "1.32.1".parse::().unwrap(); assert!(v_1_0_0 < v_1_32_1); - assert!(v_1_0_0 < v_1_32); - assert!(v_1_32 < v_1_32_1); + assert!(v_1_0_0 < v_1_32_0); + assert!(v_1_32_0 < v_1_32_1); } #[test] fn test_to_string() { let v_1_0_0 = "1.0.0".parse::().unwrap(); - let v_1_32 = "1.32".parse::().unwrap(); let v_1_32_1 = "1.32.1".parse::().unwrap(); assert_eq!(v_1_0_0.to_string(), "1.0.0"); - assert_eq!(v_1_32.to_string(), "1.32"); assert_eq!(v_1_32_1.to_string(), "1.32.1"); assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 "); assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1"); From 3b4fe7ef37c3ff2afcfda8577f010d3fe926bde5 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Wed, 1 May 2019 22:42:57 +0300 Subject: [PATCH 26/32] Group and sort feature_gate.rs --- src/libsyntax/feature_gate.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 012fcbdd8c8e2..2a1f3c4801406 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -109,15 +109,14 @@ macro_rules! declare_features { // stable (active). // // Note that the features should be grouped into internal/user-facing -// and then sorted by version inside those groups. -// FIXME(60361): Enforce ^-- with tidy. +// and then sorted by version inside those groups. This is inforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. declare_features! ( // ------------------------------------------------------------------------- - // Internal feature gates. + // feature-group-start: internal feature gates // ------------------------------------------------------------------------- // no tracking issue START @@ -211,12 +210,12 @@ declare_features! ( // no tracking issue END - // Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. (active, structural_match, "1.8.0", Some(31434), None), + // Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + // Allows using the `#![panic_runtime]` attribute. (active, panic_runtime, "1.10.0", Some(32837), None), @@ -252,7 +251,11 @@ declare_features! ( (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), // ------------------------------------------------------------------------- - // Actual feature gates (target features). + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) // ------------------------------------------------------------------------- // FIXME: Document these and merge with the list below. @@ -275,7 +278,11 @@ declare_features! ( (active, f16c_target_feature, "1.36.0", Some(44839), None), // ------------------------------------------------------------------------- - // Actual feature gates. + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates // ------------------------------------------------------------------------- // Allows using `asm!` macro with which inline assembly can be embedded. @@ -340,9 +347,6 @@ declare_features! ( // Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - // Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - // Allows `#[no_debug]`. (active, no_debug, "1.5.0", Some(29721), None), @@ -358,6 +362,9 @@ declare_features! ( // Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), + // Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + // Allows `cfg(target_has_atomic = "...")`. (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), @@ -545,6 +552,10 @@ declare_features! ( // Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- ); // Some features are known to be incomplete and using them is likely to have From c120fd823ba1cbd78167f0f3dca32b68d9f2308a Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 00:52:44 +0300 Subject: [PATCH 27/32] Rework Version::parse to avoid extra allocations --- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/features/version.rs | 28 +++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index afadedd8b6bbb..48ecbe3380745 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -147,7 +147,7 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) { } } -fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { +fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { features.iter().map(move |(name, feature)| { format!("{:<32} {:<8} {:<12} {:<8}", name, diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 7ea788a85180b..8d1ebccbff670 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -1,7 +1,6 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; -use std::convert::TryInto; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { @@ -10,16 +9,14 @@ pub struct Version { impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let x = self.parts.iter().map(|x| x.to_string()).collect::>().join("."); - f.pad(&x) + f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2])) } } #[derive(Debug, PartialEq, Eq)] pub enum ParseVersionError { ParseIntError(ParseIntError), - // core::array::TryFromSlice is not exported from std, so we invent our own variant - WrongNumberOfParts + WrongNumberOfParts, } impl From for ParseVersionError { @@ -32,10 +29,23 @@ impl FromStr for Version { type Err = ParseVersionError; fn from_str(s: &str) -> Result { - let parts: Vec<_> = s.split('.').map(|part| part.parse()).collect::>()?; - Ok(Self { - parts: parts.as_slice().try_into() .or(Err(ParseVersionError::WrongNumberOfParts))?, - }) + let mut iter = s.split('.').map(|part| Ok(part.parse()?)); + + let parts = { + let mut part = || { + iter.next() + .unwrap_or(Err(ParseVersionError::WrongNumberOfParts)) + }; + + [part()?, part()?, part()?] + }; + + if let Some(_) = iter.next() { + // Ensure we don't have more than 3 parts. + return Err(ParseVersionError::WrongNumberOfParts); + } + + Ok(Self { parts }) } } From 4bcc828b9ca7611ecb1200056bab5fc6d805fd99 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 14:30:30 +0300 Subject: [PATCH 28/32] Make in_feature_group a simple bool flag --- src/tools/tidy/src/features.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 48ecbe3380745..63731a0cb056b 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -20,7 +20,7 @@ use regex::{Regex, escape}; mod version; use self::version::Version; -const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start:"; +const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start"; const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; #[derive(Debug, PartialEq, Clone)] @@ -194,7 +194,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { // without one inside `// no tracking issue START` and `// no tracking issue END`. let mut next_feature_omits_tracking_issue = false; - let mut next_feature_group = None; + let mut in_feature_group = false; let mut prev_since = None; contents.lines().zip(1..) @@ -215,7 +215,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } if line.starts_with(FEATURE_GROUP_START_PREFIX) { - if next_feature_group.is_some() { + if in_feature_group { tidy_error!( bad, // ignore-tidy-linelength @@ -224,12 +224,11 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { ); } - let group = line.trim_start_matches(FEATURE_GROUP_START_PREFIX).trim(); - next_feature_group = Some(group.to_owned()); + in_feature_group = true; prev_since = None; return None; } else if line.starts_with(FEATURE_GROUP_END_PREFIX) { - next_feature_group = None; + in_feature_group = false; prev_since = None; return None; } @@ -257,7 +256,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { None } }; - if next_feature_group.is_some() { + if in_feature_group { if prev_since > since { tidy_error!( bad, From 201f14b88b19d43615845bfc2a6de9bc31985b13 Mon Sep 17 00:00:00 2001 From: Alexey Shmalko Date: Thu, 2 May 2019 14:38:16 +0300 Subject: [PATCH 29/32] Make tidy::version::Version copy --- src/tools/tidy/src/features.rs | 6 +++--- src/tools/tidy/src/features/version.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 63731a0cb056b..3144df6dd4cdf 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -153,8 +153,8 @@ fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator name, family, feature.level, - feature.since.as_ref().map_or("None".to_owned(), - |since| since.to_string())) + feature.since.map_or("None".to_owned(), + |since| since.to_string())) }) } @@ -265,7 +265,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { name, ); } - prev_since = since.clone(); + prev_since = since; } let issue_str = parts.next().unwrap().trim(); diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs index 8d1ebccbff670..6027e7d35e28c 100644 --- a/src/tools/tidy/src/features/version.rs +++ b/src/tools/tidy/src/features/version.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use std::num::ParseIntError; use std::fmt; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { parts: [u32; 3], } From 69fd757eca778cb3b83ccfc9fcfae4c6b839f8e6 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 2 May 2019 12:33:59 -0400 Subject: [PATCH 30/32] fix markdown syntax in `LateContext` examples --- src/librustc/lint/context.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 8d5c1798e0fa4..e713cf8d80553 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -757,12 +757,12 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { /// Check if a `DefId`'s path matches the given absolute type path usage. /// /// # Examples - /// ```rust,ignore (no `cx` or `def_id` available) + /// + /// ```rust,ignore (no context or def id available) /// if cx.match_def_path(def_id, &["core", "option", "Option"]) { /// // The given `def_id` is that of an `Option` type /// } /// ``` - // Uplifted from rust-lang/rust-clippy pub fn match_def_path(&self, def_id: DefId, path: &[&str]) -> bool { let names = self.get_def_path(def_id); @@ -772,13 +772,13 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { /// Gets the absolute path of `def_id` as a vector of `&str`. /// /// # Examples - /// ```rust,ignore (no `cx` or `def_id` available) + /// + /// ```rust,ignore (no context or def id available) /// let def_path = cx.get_def_path(def_id); /// if let &["core", "option", "Option"] = &def_path[..] { /// // The given `def_id` is that of an `Option` type /// } /// ``` - // Uplifted from rust-lang/rust-clippy pub fn get_def_path(&self, def_id: DefId) -> Vec { pub struct AbsolutePathPrinter<'a, 'tcx> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, From bbe7b85ef154dad5c7e17e7dc00895ec3bfcd189 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 2 May 2019 14:03:33 -0400 Subject: [PATCH 31/32] mention `hir::Body` in docs for `hir::FnDecl` --- src/librustc/hir/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 5a2807ac93d85..4293019aed568 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1927,6 +1927,9 @@ pub enum ArgSource { /// Represents the header (not the body) of a function declaration. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct FnDecl { + /// The types of the function's arguments. + /// + /// Additional argument data is stored in the function's [body](Body::arguments). pub inputs: HirVec, pub output: FunctionRetTy, pub c_variadic: bool, From 2fe50bc01bf9023b64a72407bb41a1f3b7245abd Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 3 May 2019 13:04:26 +0900 Subject: [PATCH 32/32] Propagate mutability from arguments to local bindings in async fn --- src/libsyntax/parse/parser.rs | 10 ++++------ src/test/ui/async-await/mutable-arguments.rs | 10 ++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/async-await/mutable-arguments.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f70acb3e7da9a..c5173aa556953 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8725,9 +8725,9 @@ impl<'a> Parser<'a> { // Check if this is a ident pattern, if so, we can optimize and avoid adding a // `let = __argN;` statement, instead just adding a `let = ;` // statement. - let (ident, is_simple_pattern) = match input.pat.node { - PatKind::Ident(_, ident, _) => (ident, true), - _ => (ident, false), + let (binding_mode, ident, is_simple_pattern) = match input.pat.node { + PatKind::Ident(binding_mode, ident, _) => (binding_mode, ident, true), + _ => (BindingMode::ByValue(Mutability::Immutable), ident, false), }; // Construct an argument representing `__argN: ` to replace the argument of the @@ -8755,9 +8755,7 @@ impl<'a> Parser<'a> { let move_local = Local { pat: P(Pat { id, - node: PatKind::Ident( - BindingMode::ByValue(Mutability::Immutable), ident, None, - ), + node: PatKind::Ident(binding_mode, ident, None), span, }), // We explicitly do not specify the type for this statement. When the user's diff --git a/src/test/ui/async-await/mutable-arguments.rs b/src/test/ui/async-await/mutable-arguments.rs new file mode 100644 index 0000000000000..4d6dba74097ca --- /dev/null +++ b/src/test/ui/async-await/mutable-arguments.rs @@ -0,0 +1,10 @@ +// edition:2018 +// run-pass + +#![feature(async_await)] + +async fn foo(n: u32, mut vec: Vec) { + vec.push(n); +} + +fn main() {}