From cc2689a2539a28d54d0f0ec029c487aadad724f0 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Tue, 16 Apr 2019 20:41:23 +0200 Subject: [PATCH 01/23] implement nth_back for Bytes --- src/libcore/str/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 8d28be621d647..24c008460447e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -795,6 +795,11 @@ impl DoubleEndedIterator for Bytes<'_> { self.0.next_back() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + #[inline] fn rfind

(&mut self, predicate: P) -> Option where P: FnMut(&Self::Item) -> bool From fae2a68ba21d5cdd3557cd01ca18b792b0bcbd67 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Tue, 16 Apr 2019 21:40:50 +0200 Subject: [PATCH 02/23] implement nth_back for Fuse --- src/libcore/iter/adapters/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index cccd51b577930..f08f2a5ec7519 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1789,6 +1789,17 @@ impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { } } + #[inline] + default fn nth_back(&mut self, n: usize) -> Option<::Item> { + if self.done { + None + } else { + let nth = self.iter.nth_back(n); + self.done = nth.is_none(); + nth + } + } + #[inline] default fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try @@ -1877,6 +1888,11 @@ impl DoubleEndedIterator for Fuse self.iter.next_back() } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { + self.iter.nth_back(n) + } + #[inline] fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try From 2605537012022980d5ec69ad11653794db935cf6 Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Tue, 16 Apr 2019 23:45:59 +0200 Subject: [PATCH 03/23] implement nth_back for Enumerate --- src/libcore/iter/adapters/mod.rs | 10 ++++++++++ src/libcore/tests/iter.rs | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index f08f2a5ec7519..9f9146a1523b3 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -980,6 +980,16 @@ impl DoubleEndedIterator for Enumerate where }) } + #[inline] + fn nth_back(&mut self, n: usize) -> Option<(usize, ::Item)> { + self.iter.nth_back(n).map(|a| { + let len = self.iter.len(); + // Can safely add, `ExactSizeIterator` promises that the number of + // elements fits into a `usize`. + (self.count + len, a) + }) + } + #[inline] fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index d5b581d336d2f..5247331fba24f 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -389,6 +389,24 @@ fn test_iterator_enumerate_nth() { assert_eq!(i, 3); } +#[test] +fn test_iterator_enumerate_nth_back() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(0) { + assert_eq!(i, x); + } + + let mut it = xs.iter().enumerate(); + while let Some((i, &x)) = it.nth_back(1) { + assert_eq!(i, x); + } + + let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap(); + assert_eq!(i, x); + assert_eq!(i, 2); +} + #[test] fn test_iterator_enumerate_count() { let xs = [0, 1, 2, 3, 4, 5]; From 4fed94bf0dcb3a58ec179f0e0248f493c140f6d0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 17 Apr 2019 10:42:10 +0200 Subject: [PATCH 04/23] Remove unwanted z-index change --- src/librustdoc/html/static/rustdoc.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8cf70b9a99502..53b08cf569783 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -166,7 +166,6 @@ nav.sub { top: 0; height: 100vh; overflow: auto; - z-index: 1; } .sidebar .block > ul > li { From ca19ffe13f077c818a3373904308946f48d5aa2e Mon Sep 17 00:00:00 2001 From: topecongiro Date: Thu, 18 Apr 2019 07:42:18 +0900 Subject: [PATCH 05/23] Update rustfmt to 1.2.1 --- Cargo.lock | 17 ++++++++++++++--- src/tools/rustfmt | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc11ff2bbbcc7..95efd04d6f84f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,14 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "annotate-snippets" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -2246,7 +2254,7 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", "rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 1.2.0", + "rustfmt-nightly 1.2.1", "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_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3038,8 +3046,9 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.2.0" +version = "1.2.1" dependencies = [ + "annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3049,6 +3058,7 @@ dependencies = [ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3061,7 +3071,7 @@ dependencies = [ "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)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3987,6 +3997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" +"checksum annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bcdcd5b291ce85a78f2b9d082a8de9676c12b1840d386d67bc5eea6f9d2b4e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 09940a70d0a9f..b860feaffccb8 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 09940a70d0a9fabfb4985426aa7d66ca1875c65e +Subproject commit b860feaffccb81199c045e9b1511c2e25825dc0c From 365a48a8bf0d4dbb343889c53f773adad74ef965 Mon Sep 17 00:00:00 2001 From: tyler Date: Wed, 17 Apr 2019 16:38:54 -0700 Subject: [PATCH 06/23] whitelist rtm x86 cpu feature --- src/librustc_codegen_llvm/llvm_util.rs | 1 + src/librustc_typeck/collect.rs | 1 + src/libsyntax/feature_gate.rs | 1 + src/test/ui/target-feature-gate.rs | 1 + src/test/ui/target-feature-gate.stderr | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 5fea9c8747e0f..0cba15b31668f 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -154,6 +154,7 @@ const X86_WHITELIST: &[(&str, Option<&str>)] = &[ ("popcnt", None), ("rdrand", None), ("rdseed", None), + ("rtm", Some("rtm_target_feature")), ("sha", None), ("sse", None), ("sse2", None), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0cd7fe9159493..d601c962fc6af 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2432,6 +2432,7 @@ fn from_target_feature( Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature, Some("adx_target_feature") => rust_features.adx_target_feature, Some("movbe_target_feature") => rust_features.movbe_target_feature, + Some("rtm_target_feature") => rust_features.rtm_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c8b020d8c0b03..7bae5ba75719a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -402,6 +402,7 @@ declare_features! ( (active, adx_target_feature, "1.32.0", Some(44839), None), (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), // Allows macro invocations on modules expressions and statements and // procedural macros to expand to non-items. diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index 84300301b7629..8f3a52ba5d677 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -23,6 +23,7 @@ // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature // gate-test-movbe_target_feature +// gate-test-rtm_target_feature // min-llvm-version 6.0 #[target_feature(enable = "avx512bw")] diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index 155298e5062b5..e142125225fb4 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/target-feature-gate.rs:28:18 + --> $DIR/target-feature-gate.rs:29:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ From 007b40be01ca4e0eb0bca875e9134e4f87c9cd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Apr 2019 18:30:26 -0700 Subject: [PATCH 07/23] Point at try `?` on errors affecting the err match arm of the desugared code --- src/librustc/hir/lowering.rs | 22 +++++++++++++------ src/test/ui/issues/issue-32709.stderr | 4 ++-- .../ui/try-block/try-block-bad-type.stderr | 4 ++-- src/test/ui/try-on-option.stderr | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a8269bb139570..42ad571cf2832 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -4685,6 +4685,14 @@ impl<'a> LoweringContext<'a> { Symbol::intern("try_trait") ].into()), ); + let try_span = self.sess.source_map().end_point(e.span); + let try_span = self.mark_span_with_reason( + CompilerDesugaringKind::QuestionMark, + try_span, + Some(vec![ + Symbol::intern("try_trait") + ].into()), + ); // `Try::into_result()` let discr = { @@ -4729,14 +4737,14 @@ impl<'a> LoweringContext<'a> { // return Try::from_error(From::from(err)),` let err_arm = { let err_ident = self.str_to_ident("err"); - let (err_local, err_local_nid) = self.pat_ident(e.span, err_ident); + let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { let path = &["convert", "From", "from"]; let from = P(self.expr_std_path( - e.span, path, None, ThinVec::new())); - let err_expr = self.expr_ident(e.span, err_ident, err_local_nid); + try_span, path, None, ThinVec::new())); + let err_expr = self.expr_ident(try_span, err_ident, err_local_nid); - self.expr_call(e.span, from, hir_vec![err_expr]) + self.expr_call(try_span, from, hir_vec![err_expr]) }; let from_err_expr = self.wrap_in_try_constructor("from_error", from_expr, unstable_span); @@ -4745,7 +4753,7 @@ impl<'a> LoweringContext<'a> { let ret_expr = if let Some(catch_node) = catch_scope { let target_id = Ok(self.lower_node_id(catch_node).hir_id); P(self.expr( - e.span, + try_span, hir::ExprKind::Break( hir::Destination { label: None, @@ -4756,10 +4764,10 @@ impl<'a> LoweringContext<'a> { thin_attrs, )) } else { - P(self.expr(e.span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) + P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) }; - let err_pat = self.pat_err(e.span, err_local); + let err_pat = self.pat_err(try_span, err_local); self.arm(hir_vec![err_pat], ret_expr) }; diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index 9127c7546582a..4a37e0a2e5282 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): std::convert::From<{integer}>` is not satisfied - --> $DIR/issue-32709.rs:4:5 + --> $DIR/issue-32709.rs:4:11 | LL | Err(5)?; - | ^^^^^^^ the trait `std::convert::From<{integer}>` is not implemented for `()` + | ^ the trait `std::convert::From<{integer}>` is not implemented for `()` | = note: required by `std::convert::From::from` diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 07e7149793c14..a39c8cfba12aa 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied - --> $DIR/try-block-bad-type.rs:7:9 + --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `i32` + | ^ the trait `std::convert::From<&str>` is not implemented for `i32` | = help: the following implementations were found: > diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 7dfa1a7d3a0c0..3e081d0376649 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): std::convert::From` is not satisfied - --> $DIR/try-on-option.rs:7:5 + --> $DIR/try-on-option.rs:7:6 | LL | x?; - | ^^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `std::convert::From` is not implemented for `()` | = note: required by `std::convert::From::from` From 1e99b2ec9dc60dc01a413118051d273ed7688c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Apr 2019 19:50:50 -0700 Subject: [PATCH 08/23] Give custom error for E0277 on `?` error case --- src/librustc/traits/error_reporting.rs | 12 ++++++++++++ src/test/ui/issues/issue-32709.stderr | 2 +- src/test/ui/try-block/try-block-bad-type.rs | 2 +- src/test/ui/try-block/try-block-bad-type.stderr | 2 +- src/test/ui/try-on-option.rs | 4 ++-- src/test/ui/try-on-option.stderr | 2 +- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5b5a7cc9ed85b..14c81a806c259 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -638,6 +638,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let OnUnimplementedNote { message, label, note } = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); + let is_try = self.tcx.sess.source_map().span_to_snippet(span) + .map(|s| &s == "?") + .unwrap_or(false); + let is_from = format!("{}", trait_ref).starts_with("std::convert::From<"); + let message = if is_try && is_from { + Some(format!( + "`?` couldn't convert the error to `{}`", + trait_ref.self_ty(), + )) + } else { + message + }; let mut err = struct_span_err!( self.tcx.sess, diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index 4a37e0a2e5282..84cca5b20af47 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): std::convert::From<{integer}>` is not satisfied +error[E0277]: `?` couldn't convert the error to `()` --> $DIR/issue-32709.rs:4:11 | LL | Err(5)?; diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index 0e297dd8ff16b..4dfc8e6a2fca4 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -4,7 +4,7 @@ pub fn main() { let res: Result = try { - Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied + Err("")?; //~ ERROR `?` couldn't convert the error 5 }; diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index a39c8cfba12aa..13593c4e8e72d 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied +error[E0277]: `?` couldn't convert the error to `i32` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-on-option.rs index 9c8e8b33ad68a..5d94cee8e3721 100644 --- a/src/test/ui/try-on-option.rs +++ b/src/test/ui/try-on-option.rs @@ -4,12 +4,12 @@ fn main() {} fn foo() -> Result { let x: Option = None; - x?; //~ the trait bound + x?; //~ ERROR `?` couldn't convert the error Ok(22) } fn bar() -> u32 { let x: Option = None; - x?; //~ the `?` operator + x?; //~ ERROR the `?` operator 22 } diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 3e081d0376649..4465fbe14b75c 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): std::convert::From` is not satisfied +error[E0277]: `?` couldn't convert the error to `()` --> $DIR/try-on-option.rs:7:6 | LL | x?; From 379c5412efae5bc86e483999c0f14e329e4ea6e2 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Wed, 17 Apr 2019 16:02:17 +0200 Subject: [PATCH 09/23] Simplify the returning of a Result a bit --- src/libstd/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index dea198d8c9178..1772879d01362 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -901,8 +901,7 @@ impl OpenOptions { } fn _open(&self, path: &Path) -> io::Result { - let inner = fs_imp::File::open(path, &self.0)?; - Ok(File { inner }) + fs_imp::File::open(path, &self.0).map(|inner| File { inner }) } } From 553ec5d3eb8af66f86599b0abb0efda74393921e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 17 Apr 2019 12:53:02 +0200 Subject: [PATCH 10/23] Update run-make PGO test to new commandline syntax. --- src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile index dc52e91317a5a..e22fac25cf7a4 100644 --- a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -2,7 +2,7 @@ all: ifeq ($(PROFILER_SUPPORT),1) - $(RUSTC) -O -Ccodegen-units=1 -Z pgo-gen="$(TMPDIR)/test.profraw" --emit=llvm-ir test.rs + $(RUSTC) -O -Ccodegen-units=1 -Z pgo-gen="$(TMPDIR)" --emit=llvm-ir test.rs # We expect symbols starting with "__llvm_profile_". $(CGREP) "__llvm_profile_" < $(TMPDIR)/test.ll # We do NOT expect the "__imp_" version of these symbols. From 4269be382fdf1ac92665234502bab33ef9c0d8fa Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 18 Apr 2019 15:21:05 +0200 Subject: [PATCH 11/23] Prefix PROFILER_SUPPORT and SANITIZER_SUPPORT test env vars with RUSTC_ to make things clearer. --- src/bootstrap/test.rs | 4 ++-- src/test/run-make-fulldeps/pgo-gen-lto/Makefile | 2 +- src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile | 2 +- src/test/run-make-fulldeps/pgo-gen/Makefile | 2 +- src/test/run-make-fulldeps/profile/Makefile | 2 +- src/test/run-make-fulldeps/sanitizer-address/Makefile | 4 ++-- src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile | 2 +- src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile | 2 +- .../run-make-fulldeps/sanitizer-invalid-cratetype/Makefile | 4 ++-- src/test/run-make-fulldeps/sanitizer-leak/Makefile | 2 +- src/test/run-make-fulldeps/sanitizer-memory/Makefile | 2 +- src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile | 4 ++-- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c552f607960b4..a443b7b5863e5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1268,11 +1268,11 @@ impl Step for Compiletest { builder.add_rust_test_threads(&mut cmd); if builder.config.sanitizers { - cmd.env("SANITIZER_SUPPORT", "1"); + cmd.env("RUSTC_SANITIZER_SUPPORT", "1"); } if builder.config.profiler { - cmd.env("PROFILER_SUPPORT", "1"); + cmd.env("RUSTC_PROFILER_SUPPORT", "1"); } cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp")); diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index 7c19961b1e420..d6e45d838535f 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: -ifeq ($(PROFILER_SUPPORT),1) +ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile index e22fac25cf7a4..bfb57bfeefe5c 100644 --- a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: -ifeq ($(PROFILER_SUPPORT),1) +ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -O -Ccodegen-units=1 -Z pgo-gen="$(TMPDIR)" --emit=llvm-ir test.rs # We expect symbols starting with "__llvm_profile_". $(CGREP) "__llvm_profile_" < $(TMPDIR)/test.ll diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 0469c4443d85a..28294f6e1d82d 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: -ifeq ($(PROFILER_SUPPORT),1) +ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -g -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) diff --git a/src/test/run-make-fulldeps/profile/Makefile b/src/test/run-make-fulldeps/profile/Makefile index 7300bfc955363..880bc38f408e6 100644 --- a/src/test/run-make-fulldeps/profile/Makefile +++ b/src/test/run-make-fulldeps/profile/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk all: -ifeq ($(PROFILER_SUPPORT),1) +ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -g -Z profile test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) diff --git a/src/test/run-make-fulldeps/sanitizer-address/Makefile b/src/test/run-make-fulldeps/sanitizer-address/Makefile index 207615bfbd5c6..5f3486a495be2 100644 --- a/src/test/run-make-fulldeps/sanitizer-address/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-address/Makefile @@ -5,11 +5,11 @@ LOG := $(TMPDIR)/log.txt # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) # Apparently there are very specific Linux kernels, notably the one that's # currently on Travis CI, which contain a buggy commit that triggers failures in diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile index 4b7fece36d92a..bb323d2a6341a 100644 --- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile @@ -8,7 +8,7 @@ LOG := $(TMPDIR)/log.txt # is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile index 97f6172142224..77f119d889967 100644 --- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile @@ -8,7 +8,7 @@ LOG := $(TMPDIR)/log.txt # is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile index dc37c0d0bc946..ac49e519c7b96 100644 --- a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile @@ -3,11 +3,11 @@ # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG= endif endif diff --git a/src/test/run-make-fulldeps/sanitizer-leak/Makefile b/src/test/run-make-fulldeps/sanitizer-leak/Makefile index 0f3c18f9293f5..e84e1cbd2b61b 100644 --- a/src/test/run-make-fulldeps/sanitizer-leak/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-leak/Makefile @@ -6,7 +6,7 @@ # FIXME(#46126) ThinLTO for libstd broke this test all: -ifdef SANITIZER_SUPPORT +ifdef RUSTC_SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan $(TMPDIR)/leak 2>&1 | $(CGREP) 'detected memory leaks' endif diff --git a/src/test/run-make-fulldeps/sanitizer-memory/Makefile b/src/test/run-make-fulldeps/sanitizer-memory/Makefile index 718d9637ea06d..aca3591555cfd 100644 --- a/src/test/run-make-fulldeps/sanitizer-memory/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-memory/Makefile @@ -4,7 +4,7 @@ # only-x86_64 all: -ifdef SANITIZER_SUPPORT +ifdef RUSTC_SANITIZER_SUPPORT $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value endif diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile index 2b444d667bfa3..7a1b9509f4f98 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile @@ -1,11 +1,11 @@ -include ../tools.mk # This test builds a staticlib, then an executable that links to it. -# The staticlib and executable both are compiled with address sanitizer, +# The staticlib and executable both are compiled with address sanitizer, # and we assert that a fault in the staticlib is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(SANITIZER_SUPPORT) +ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG= endif From 227be657cdeee2259199b24fb9691f7f8994c5e6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 18 Apr 2019 15:31:46 +0200 Subject: [PATCH 12/23] compiletest: Allow for tests requiring profiler-rt or sanitizer-rt support. --- src/tools/compiletest/src/header.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 64882c603bad3..fb6ada89171ab 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -88,6 +88,9 @@ impl EarlyProps { } } + let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); + let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); + iter_header(testfile, None, &mut |ln| { // we should check if any only- exists and if it exists // and does not matches the current platform, skip the test @@ -116,6 +119,16 @@ impl EarlyProps { config.parse_needs_matching_clang(ln) { props.ignore = Ignore::Ignore; } + + if !rustc_has_profiler_support && + config.parse_needs_profiler_support(ln) { + props.ignore = Ignore::Ignore; + } + + if !rustc_has_sanitizer_support && + config.parse_needs_sanitizer_support(ln) { + props.ignore = Ignore::Ignore; + } } if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) && @@ -748,6 +761,14 @@ impl Config { self.parse_name_directive(line, "needs-matching-clang") } + fn parse_needs_profiler_support(&self, line: &str) -> bool { + self.parse_name_directive(line, "needs-profiler-support") + } + + fn parse_needs_sanitizer_support(&self, line: &str) -> bool { + self.parse_name_directive(line, "needs-sanitizer-support") + } + /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective { From e2acaee8bb364197af2ab197f0f641e8f988ae04 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 16 Apr 2019 13:54:01 +0200 Subject: [PATCH 13/23] Add codegen test that makes sure PGO instrumentation is emitted as expected. --- src/test/codegen/pgo-instrumentation.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/codegen/pgo-instrumentation.rs diff --git a/src/test/codegen/pgo-instrumentation.rs b/src/test/codegen/pgo-instrumentation.rs new file mode 100644 index 0000000000000..8493ef565d888 --- /dev/null +++ b/src/test/codegen/pgo-instrumentation.rs @@ -0,0 +1,20 @@ +// Test that `-Zpgo-gen` creates expected instrumentation artifacts in LLVM IR. + +// needs-profiler-support +// compile-flags: -Z pgo-gen -Ccodegen-units=1 + +// CHECK: @__llvm_profile_raw_version = +// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global +// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}some_function{{.*}} = private global +// CHECK: @__profc_{{.*}}pgo_instrumentation{{.*}}main{{.*}} = private global +// CHECK: @__profd_{{.*}}pgo_instrumentation{{.*}}main{{.*}} = private global +// CHECK: @__llvm_profile_filename = {{.*}}"default_%m.profraw\00"{{.*}} + +#[inline(never)] +fn some_function() { + +} + +fn main() { + some_function(); +} From d98afc51dcfe254d25925c4b675a6099dede4f47 Mon Sep 17 00:00:00 2001 From: Nathan Kleyn Date: Thu, 18 Apr 2019 14:48:15 +0100 Subject: [PATCH 14/23] Fix small errors in docs for `rchunks_exact` and `rchunks_exact_mut`. The documentation for `rchunks_exact` said it started at the beginning of the slice, bit it actually starts at the end of the slice. In addition, there were a couple of "of the slice of the slice" duplicate phrases going on for `rchunks_exact` and `rchunks_exact_mut`. This fixes #60068. --- src/libcore/slice/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 122ef9c79c276..dc1194d1b2d31 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -838,7 +838,7 @@ impl [T] { } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the - /// beginning of the slice. + /// end of the slice. /// /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved @@ -849,7 +849,7 @@ impl [T] { /// /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the - /// slice of the slice. + /// slice. /// /// # Panics /// @@ -890,7 +890,7 @@ impl [T] { /// /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning - /// of the slice of the slice. + /// of the slice. /// /// # Panics /// From cc77087d6f6143927d9fe98a07ca3d12b26ce474 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 18 Apr 2019 15:49:41 +0200 Subject: [PATCH 15/23] Use new `needs-(profiler|sanitizer)-support` compiletest directive to clean up some run-make tests. --- src/test/run-make-fulldeps/pgo-gen-lto/Makefile | 4 ++-- src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile | 4 ++-- src/test/run-make-fulldeps/pgo-gen/Makefile | 4 ++-- src/test/run-make-fulldeps/profile/Makefile | 4 ++-- src/test/run-make-fulldeps/sanitizer-address/Makefile | 6 ++---- src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile | 5 ++--- src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile | 6 ++---- .../run-make-fulldeps/sanitizer-invalid-cratetype/Makefile | 6 ++---- src/test/run-make-fulldeps/sanitizer-leak/Makefile | 3 +-- src/test/run-make-fulldeps/sanitizer-memory/Makefile | 3 +-- .../run-make-fulldeps/sanitizer-staticlib-link/Makefile | 5 ++--- 11 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index d6e45d838535f..48181bcbdc6d3 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,8 +1,8 @@ +# needs-profiler-support + -include ../tools.mk all: -ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) -endif diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile index bfb57bfeefe5c..20977edb88e87 100644 --- a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -1,11 +1,11 @@ +# needs-profiler-support + -include ../tools.mk all: -ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -O -Ccodegen-units=1 -Z pgo-gen="$(TMPDIR)" --emit=llvm-ir test.rs # We expect symbols starting with "__llvm_profile_". $(CGREP) "__llvm_profile_" < $(TMPDIR)/test.ll # We do NOT expect the "__imp_" version of these symbols. $(CGREP) -v "__imp___llvm_profile_" < $(TMPDIR)/test.ll # 64 bit $(CGREP) -v "__imp____llvm_profile_" < $(TMPDIR)/test.ll # 32 bit -endif diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 28294f6e1d82d..ce44c10a7c2d2 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,8 +1,8 @@ +# needs-profiler-support + -include ../tools.mk all: -ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -g -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) -endif diff --git a/src/test/run-make-fulldeps/profile/Makefile b/src/test/run-make-fulldeps/profile/Makefile index 880bc38f408e6..c12712590e48f 100644 --- a/src/test/run-make-fulldeps/profile/Makefile +++ b/src/test/run-make-fulldeps/profile/Makefile @@ -1,9 +1,9 @@ +# needs-profiler-support + -include ../tools.mk all: -ifeq ($(RUSTC_PROFILER_SUPPORT),1) $(RUSTC) -g -Z profile test.rs $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) [ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) -endif diff --git a/src/test/run-make-fulldeps/sanitizer-address/Makefile b/src/test/run-make-fulldeps/sanitizer-address/Makefile index 5f3486a495be2..51d8a4a947adc 100644 --- a/src/test/run-make-fulldeps/sanitizer-address/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-address/Makefile @@ -1,3 +1,5 @@ +# needs-sanitizer-support + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -5,11 +7,9 @@ LOG := $(TMPDIR)/log.txt # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) # Apparently there are very specific Linux kernels, notably the one that's # currently on Travis CI, which contain a buggy commit that triggers failures in @@ -23,7 +23,5 @@ endif endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) librustc_asan $(TMPDIR)/overflow 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile index bb323d2a6341a..36cde355468be 100644 --- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile @@ -1,3 +1,5 @@ +# needs-sanitizer-support + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -8,15 +10,12 @@ LOG := $(TMPDIR)/log.txt # is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type cdylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs $(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) $(EXTRA_RUSTFLAG) -llibrary program.rs LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile index 77f119d889967..b382ff5e7b24f 100644 --- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile @@ -1,3 +1,5 @@ +# needs-sanitizer-support + -include ../tools.mk LOG := $(TMPDIR)/log.txt @@ -8,15 +10,11 @@ LOG := $(TMPDIR)/log.txt # is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) - # See comment in sanitizer-address/Makefile for why this is here EXTRA_RUSTFLAG=-C relocation-model=dynamic-no-pic endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type dylib --target $(TARGET) $(EXTRA_RUSTFLAG) library.rs $(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) $(EXTRA_RUSTFLAG) -llibrary program.rs LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile index ac49e519c7b96..9581ac565ea02 100644 --- a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile @@ -1,18 +1,16 @@ +# needs-sanitizer-support + -include ../tools.mk # NOTE the address sanitizer only supports x86_64 linux and macOS ifeq ($(TARGET),x86_64-apple-darwin) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG=-C rpath else ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG= endif endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | $(CGREP) '-Z sanitizer' -endif diff --git a/src/test/run-make-fulldeps/sanitizer-leak/Makefile b/src/test/run-make-fulldeps/sanitizer-leak/Makefile index e84e1cbd2b61b..101e8272ab91e 100644 --- a/src/test/run-make-fulldeps/sanitizer-leak/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-leak/Makefile @@ -1,12 +1,11 @@ -include ../tools.mk +# needs-sanitizer-support # only-linux # only-x86_64 # ignore-test # FIXME(#46126) ThinLTO for libstd broke this test all: -ifdef RUSTC_SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan $(TMPDIR)/leak 2>&1 | $(CGREP) 'detected memory leaks' -endif diff --git a/src/test/run-make-fulldeps/sanitizer-memory/Makefile b/src/test/run-make-fulldeps/sanitizer-memory/Makefile index aca3591555cfd..b3376f8a72358 100644 --- a/src/test/run-make-fulldeps/sanitizer-memory/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-memory/Makefile @@ -1,10 +1,9 @@ -include ../tools.mk +# needs-sanitizer-support # only-linux # only-x86_64 all: -ifdef RUSTC_SANITIZER_SUPPORT $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value -endif diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile index 7a1b9509f4f98..8fa08688fdd71 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile @@ -1,3 +1,5 @@ +# needs-sanitizer-support + -include ../tools.mk # This test builds a staticlib, then an executable that links to it. @@ -5,14 +7,11 @@ # and we assert that a fault in the staticlib is correctly detected. ifeq ($(TARGET),x86_64-unknown-linux-gnu) -ASAN_SUPPORT=$(RUSTC_SANITIZER_SUPPORT) EXTRA_RUSTFLAG= endif all: -ifeq ($(ASAN_SUPPORT),1) $(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs $(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS) LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow -endif From 08efbac758aa75f710b8018d8974bde5c7a149c1 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 12 Apr 2019 14:48:41 +0200 Subject: [PATCH 16/23] Implement event filtering for self-profiler. --- src/librustc/session/config.rs | 2 + src/librustc/session/mod.rs | 2 +- src/librustc/util/profiling.rs | 121 +++++++++++++++++++++++++-------- 3 files changed, 97 insertions(+), 28 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index dc1ceaf69f013..97a1c83dbffb6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1467,6 +1467,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "inject the given attribute in the crate"), self_profile: bool = (false, parse_bool, [UNTRACKED], "run the self profiler and output the raw event data"), + self_profile_events: Option> = (None, parse_opt_comma_list, [UNTRACKED], + "specifies which kinds of events get recorded by the self profiler"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emits a section containing stack size metadata"), plt: Option = (None, parse_opt_bool, [TRACKED], diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index eed516a438175..eecd5cba6d358 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1138,7 +1138,7 @@ fn build_session_( ) -> Session { let self_profiler = if sopts.debugging_opts.self_profile { - let profiler = SelfProfiler::new(); + let profiler = SelfProfiler::new(&sopts.debugging_opts.self_profile_events); match profiler { Ok(profiler) => { crate::ty::query::QueryName::register_with_profiler(&profiler); diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index aabf9a401c690..585970e64df8d 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -27,26 +27,42 @@ pub enum ProfileCategory { Other, } -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ProfilerEvent { - QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 }, - QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 }, - GenericActivityStart { category: ProfileCategory, label: Cow<'static, str>, time: u64 }, - GenericActivityEnd { category: ProfileCategory, label: Cow<'static, str>, time: u64 }, - IncrementalLoadResultStart { query_name: &'static str, time: u64 }, - IncrementalLoadResultEnd { query_name: &'static str, time: u64 }, - QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 }, - QueryCount { query_name: &'static str, category: ProfileCategory, count: usize, time: u64 }, - QueryBlockedStart { query_name: &'static str, category: ProfileCategory, time: u64 }, - QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 }, +bitflags! { + struct EventFilter: u32 { + const GENERIC_ACTIVITIES = 1 << 0; + const QUERY_PROVIDERS = 1 << 1; + const QUERY_CACHE_HITS = 1 << 2; + const QUERY_BLOCKED = 1 << 3; + const INCR_CACHE_LOADS = 1 << 4; + + const DEFAULT = Self::GENERIC_ACTIVITIES.bits | + Self::QUERY_PROVIDERS.bits | + Self::QUERY_BLOCKED.bits | + Self::INCR_CACHE_LOADS.bits; + + // empty() and none() aren't const-fns unfortunately + const NONE = 0; + const ALL = !Self::NONE.bits; + } } +const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ + ("none", EventFilter::NONE), + ("all", EventFilter::ALL), + ("generic-activity", EventFilter::GENERIC_ACTIVITIES), + ("query-provider", EventFilter::QUERY_PROVIDERS), + ("query-cache-hit", EventFilter::QUERY_CACHE_HITS), + ("query-blocked" , EventFilter::QUERY_BLOCKED), + ("incr-cache-load", EventFilter::INCR_CACHE_LOADS), +]; + fn thread_id_to_u64(tid: ThreadId) -> u64 { unsafe { mem::transmute::(tid) } } pub struct SelfProfiler { profiler: Profiler, + event_filter_mask: EventFilter, query_event_kind: StringId, generic_activity_event_kind: StringId, incremental_load_result_event_kind: StringId, @@ -55,7 +71,7 @@ pub struct SelfProfiler { } impl SelfProfiler { - pub fn new() -> Result> { + pub fn new(event_filters: &Option>) -> Result> { let filename = format!("pid-{}.rustc_profile", process::id()); let path = std::path::Path::new(&filename); let profiler = Profiler::new(path)?; @@ -66,8 +82,38 @@ impl SelfProfiler { let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); + let mut event_filter_mask = EventFilter::empty(); + + if let Some(ref event_filters) = *event_filters { + let mut unknown_events = vec![]; + for item in event_filters { + if let Some(&(_, mask)) = EVENT_FILTERS_BY_NAME.iter() + .find(|&(name, _)| name == item) { + event_filter_mask |= mask; + } else { + unknown_events.push(item.clone()); + } + } + + // Warn about any unknown event names + if unknown_events.len() > 0 { + unknown_events.sort(); + unknown_events.dedup(); + + warn!("Unknown self-profiler events specified: {}. Available options are: {}.", + unknown_events.join(", "), + EVENT_FILTERS_BY_NAME.iter() + .map(|&(name, _)| name.to_string()) + .collect::>() + .join(", ")); + } + } else { + event_filter_mask = EventFilter::DEFAULT; + } + Ok(SelfProfiler { profiler, + event_filter_mask, query_event_kind, generic_activity_event_kind, incremental_load_result_event_kind, @@ -86,7 +132,6 @@ impl SelfProfiler { pub fn register_query_name(&self, query_name: QueryName) { let id = SelfProfiler::get_query_name_string_id(query_name); - self.profiler.alloc_string_with_reserved_id(id, query_name.as_str()); } @@ -95,7 +140,9 @@ impl SelfProfiler { &self, label: impl Into>, ) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start); + if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { + self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start); + } } #[inline] @@ -103,46 +150,66 @@ impl SelfProfiler { &self, label: impl Into>, ) { - self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End); + if self.event_filter_mask.contains(EventFilter::GENERIC_ACTIVITIES) { + self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End); + } } #[inline] pub fn record_query_hit(&self, query_name: QueryName) { - self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant); + if self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS) { + self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant); + } } #[inline] pub fn start_query(&self, query_name: QueryName) { - self.record_query(query_name, self.query_event_kind, TimestampKind::Start); + if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { + self.record_query(query_name, self.query_event_kind, TimestampKind::Start); + } } #[inline] pub fn end_query(&self, query_name: QueryName) { - self.record_query(query_name, self.query_event_kind, TimestampKind::End); + if self.event_filter_mask.contains(EventFilter::QUERY_PROVIDERS) { + self.record_query(query_name, self.query_event_kind, TimestampKind::End); + } } #[inline] pub fn incremental_load_result_start(&self, query_name: QueryName) { - self.record_query( - query_name, - self.incremental_load_result_event_kind, - TimestampKind::Start - ); + if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { + self.record_query( + query_name, + self.incremental_load_result_event_kind, + TimestampKind::Start + ); + } } #[inline] pub fn incremental_load_result_end(&self, query_name: QueryName) { - self.record_query(query_name, self.incremental_load_result_event_kind, TimestampKind::End); + if self.event_filter_mask.contains(EventFilter::INCR_CACHE_LOADS) { + self.record_query( + query_name, + self.incremental_load_result_event_kind, + TimestampKind::End + ); + } } #[inline] pub fn query_blocked_start(&self, query_name: QueryName) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start); + if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { + self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start); + } } #[inline] pub fn query_blocked_end(&self, query_name: QueryName) { - self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End); + if self.event_filter_mask.contains(EventFilter::QUERY_BLOCKED) { + self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End); + } } #[inline] From ae1f2b571ad782f1bd80fd776b6c34e057f6625e Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 18:06:39 +0200 Subject: [PATCH 17/23] Update miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index ae9e9cb47c7b7..7d7cf4d42e414 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit ae9e9cb47c7b79d8bb29fab90929bd9b3606348a +Subproject commit 7d7cf4d42e41437f5a5b04a6b8dd567f330ae6ee From 04cf7701f12bb14a0e35aa1499bff62937b912bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 17 Apr 2019 17:22:16 -0700 Subject: [PATCH 18/23] Change suggestion of field when not in self context --- src/librustc_resolve/diagnostics.rs | 22 ++++++++++--------- src/test/ui/class-missing-self.stderr | 2 +- src/test/ui/issues/issue-60057.rs | 17 ++++++++++++++ src/test/ui/issues/issue-60057.stderr | 20 +++++++++++++++++ src/test/ui/resolve/issue-14254.stderr | 8 +++---- src/test/ui/resolve/issue-2356.stderr | 12 +++------- .../resolve/resolve-assoc-suggestions.stderr | 2 +- .../resolve-speculative-adjustment.stderr | 2 +- .../unresolved_static_type_field.stderr | 5 +---- 9 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/issues/issue-60057.rs create mode 100644 src/test/ui/issues/issue-60057.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 9e3894dab0da0..6821921e45467 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -166,16 +166,18 @@ impl<'a> Resolver<'a> { let self_is_available = self.self_value_is_available(path[0].ident.span, span); match candidate { AssocSuggestion::Field => { - err.span_suggestion( - span, - "try", - format!("self.{}", path_str), - Applicability::MachineApplicable, - ); - if !self_is_available { - err.span_label(span, format!("`self` value is a keyword \ - only available in \ - methods with `self` parameter")); + if self_is_available { + err.span_suggestion( + span, + "you might have meant to use the available field", + format!("self.{}", path_str), + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + format!("a field by this name exists in `Self::{}`", path_str), + ); } } AssocSuggestion::MethodWithSelf if self_is_available => { diff --git a/src/test/ui/class-missing-self.stderr b/src/test/ui/class-missing-self.stderr index ec11f1253990f..25cb85dadb903 100644 --- a/src/test/ui/class-missing-self.stderr +++ b/src/test/ui/class-missing-self.stderr @@ -2,7 +2,7 @@ error[E0425]: cannot find value `meows` in this scope --> $DIR/class-missing-self.rs:9:7 | LL | meows += 1; - | ^^^^^ help: try: `self.meows` + | ^^^^^ help: you might have meant to use the available field: `self.meows` error[E0425]: cannot find function `sleep` in this scope --> $DIR/class-missing-self.rs:10:7 diff --git a/src/test/ui/issues/issue-60057.rs b/src/test/ui/issues/issue-60057.rs new file mode 100644 index 0000000000000..3027d01c5325b --- /dev/null +++ b/src/test/ui/issues/issue-60057.rs @@ -0,0 +1,17 @@ +struct A { + banana: u8, +} + +impl A { + fn new(peach: u8) -> A { + A { + banana: banana //~ ERROR cannot find value `banana` in this scope + } + } + + fn foo(&self, peach: u8) -> A { + A { + banana: banana //~ ERROR cannot find value `banana` in this scope + } + } +} diff --git a/src/test/ui/issues/issue-60057.stderr b/src/test/ui/issues/issue-60057.stderr new file mode 100644 index 0000000000000..0bee87a43722f --- /dev/null +++ b/src/test/ui/issues/issue-60057.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `banana` in this scope + --> $DIR/issue-60057.rs:8:21 + | +LL | banana: banana + | ^^^^^^ a field by this name exists in `Self::banana` + +error[E0425]: cannot find value `banana` in this scope + --> $DIR/issue-60057.rs:14:21 + | +LL | banana: banana + | ^^^^^^ help: you might have meant to use the available field: `self.banana` + +error[E0601]: `main` function not found in crate `issue_60057` + | + = note: consider adding a `main` function to `$DIR/issue-60057.rs` + +error: aborting due to 3 previous errors + +Some errors occurred: E0425, E0601. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr index 783b3addfc2ec..97d42aa8ef4a5 100644 --- a/src/test/ui/resolve/issue-14254.stderr +++ b/src/test/ui/resolve/issue-14254.stderr @@ -20,13 +20,13 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:30:9 | LL | x; - | ^ help: try: `self.x` + | ^ help: you might have meant to use the available field: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:32:9 | LL | y; - | ^ help: try: `self.y` + | ^ help: you might have meant to use the available field: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:34:9 @@ -56,13 +56,13 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:47:9 | LL | x; - | ^ help: try: `self.x` + | ^ help: you might have meant to use the available field: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:49:9 | LL | y; - | ^ help: try: `self.y` + | ^ help: you might have meant to use the available field: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:51:9 diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index fb4acaa141e35..548f4ec573dfa 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -20,10 +20,7 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:39:5 | LL | whiskers -= other; - | ^^^^^^^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.whiskers` + | ^^^^^^^^ a field by this name exists in `Self::whiskers` error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:41:5 @@ -83,16 +80,13 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:79:5 | LL | whiskers = 0; - | ^^^^^^^^ help: try: `self.whiskers` + | ^^^^^^^^ help: you might have meant to use the available field: `self.whiskers` error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:84:5 | LL | whiskers = 4; - | ^^^^^^^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.whiskers` + | ^^^^^^^^ a field by this name exists in `Self::whiskers` error[E0425]: cannot find function `purr_louder` in this scope --> $DIR/issue-2356.rs:86:5 diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr index f2e1d72e7a351..523eeaacbbba7 100644 --- a/src/test/ui/resolve/resolve-assoc-suggestions.stderr +++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr @@ -14,7 +14,7 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-assoc-suggestions.rs:20:9 | LL | field; - | ^^^^^ help: try: `self.field` + | ^^^^^ help: you might have meant to use the available field: `self.field` error[E0412]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:23:16 diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr index c4a6ced1ca4c0..892b50309a905 100644 --- a/src/test/ui/resolve/resolve-speculative-adjustment.stderr +++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr @@ -14,7 +14,7 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-speculative-adjustment.rs:23:9 | LL | field; - | ^^^^^ help: try: `self.field` + | ^^^^^ help: you might have meant to use the available field: `self.field` error[E0425]: cannot find function `method` in this scope --> $DIR/resolve-speculative-adjustment.rs:25:9 diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr index a517324378772..7008fadad8170 100644 --- a/src/test/ui/resolve/unresolved_static_type_field.stderr +++ b/src/test/ui/resolve/unresolved_static_type_field.stderr @@ -2,10 +2,7 @@ error[E0425]: cannot find value `cx` in this scope --> $DIR/unresolved_static_type_field.rs:9:11 | LL | f(cx); - | ^^ - | | - | `self` value is a keyword only available in methods with `self` parameter - | help: try: `self.cx` + | ^^ a field by this name exists in `Self::cx` error: aborting due to previous error From 9daeaa821e0a994d901511e55ab3893e4df2d84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 18 Apr 2019 09:43:15 -0700 Subject: [PATCH 19/23] review comments: change wording --- src/librustc_resolve/diagnostics.rs | 2 +- src/test/ui/issues/issue-60057.stderr | 2 +- src/test/ui/resolve/issue-2356.stderr | 4 ++-- src/test/ui/resolve/unresolved_static_type_field.stderr | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 6821921e45467..9b02f98164fdf 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -176,7 +176,7 @@ impl<'a> Resolver<'a> { } else { err.span_label( span, - format!("a field by this name exists in `Self::{}`", path_str), + "a field by this name exists in `Self`", ); } } diff --git a/src/test/ui/issues/issue-60057.stderr b/src/test/ui/issues/issue-60057.stderr index 0bee87a43722f..bbe16d04919c0 100644 --- a/src/test/ui/issues/issue-60057.stderr +++ b/src/test/ui/issues/issue-60057.stderr @@ -2,7 +2,7 @@ error[E0425]: cannot find value `banana` in this scope --> $DIR/issue-60057.rs:8:21 | LL | banana: banana - | ^^^^^^ a field by this name exists in `Self::banana` + | ^^^^^^ a field by this name exists in `Self` error[E0425]: cannot find value `banana` in this scope --> $DIR/issue-60057.rs:14:21 diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index 548f4ec573dfa..bf4087733c746 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -20,7 +20,7 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:39:5 | LL | whiskers -= other; - | ^^^^^^^^ a field by this name exists in `Self::whiskers` + | ^^^^^^^^ a field by this name exists in `Self` error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:41:5 @@ -86,7 +86,7 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:84:5 | LL | whiskers = 4; - | ^^^^^^^^ a field by this name exists in `Self::whiskers` + | ^^^^^^^^ a field by this name exists in `Self` error[E0425]: cannot find function `purr_louder` in this scope --> $DIR/issue-2356.rs:86:5 diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr index 7008fadad8170..06926b53ddd35 100644 --- a/src/test/ui/resolve/unresolved_static_type_field.stderr +++ b/src/test/ui/resolve/unresolved_static_type_field.stderr @@ -2,7 +2,7 @@ error[E0425]: cannot find value `cx` in this scope --> $DIR/unresolved_static_type_field.rs:9:11 | LL | f(cx); - | ^^ a field by this name exists in `Self::cx` + | ^^ a field by this name exists in `Self` error: aborting due to previous error From 2d37ce1c703f9515eba2d83e04640c627ae8f59b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 14 Apr 2019 17:09:03 -0700 Subject: [PATCH 20/23] Emit specific error for struct literal in conditions --- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/libsyntax/parse/parser.rs | 57 +++++++++++++++++-- src/test/ui/error-codes/E0423.rs | 6 +- src/test/ui/error-codes/E0423.stderr | 54 +++++------------- src/test/ui/parser/struct-literal-in-for.rs | 6 +- .../ui/parser/struct-literal-in-for.stderr | 41 ++++++------- src/test/ui/parser/struct-literal-in-if.rs | 6 +- .../ui/parser/struct-literal-in-if.stderr | 34 ++++------- .../struct-literal-in-match-discriminant.rs | 10 ++-- ...truct-literal-in-match-discriminant.stderr | 47 ++++----------- src/test/ui/parser/struct-literal-in-while.rs | 7 +-- .../ui/parser/struct-literal-in-while.stderr | 41 ++++--------- .../struct-literal-restrictions-in-lamda.rs | 7 +-- ...truct-literal-restrictions-in-lamda.stderr | 48 +++++++--------- 14 files changed, 162 insertions(+), 206 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index fe39e3ae0c6cd..a2f6d9713f026 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -897,8 +897,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast) } BorrowViolation(euv::ClosureInvocation) => { - span_bug!(err.span, - "err_mutbl with a closure invocation"); + span_bug!(err.span, "err_mutbl with a closure invocation"); } }; @@ -1096,7 +1095,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::MatchDiscriminant) => { "cannot borrow data mutably" } - BorrowViolation(euv::ClosureInvocation) => { is_closure = true; "closure invocation" diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a5adb37f7455c..7d130470c6ac1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2855,11 +2855,13 @@ impl<'a> Parser<'a> { let (delim, tts) = self.expect_delimited_token_tree()?; hi = self.prev_span; ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim })); - } else if self.check(&token::OpenDelim(token::Brace)) && - !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) { - // This is a struct literal, unless we're prohibited - // from parsing struct literals here. - return self.parse_struct_expr(lo, path, attrs); + } else if self.check(&token::OpenDelim(token::Brace)) { + if let Some(expr) = self.should_parse_struct_expr(lo, path.clone(), attrs.clone()) { + return expr; + } else { + hi = path.span; + ex = ExprKind::Path(None, path); + } } else { hi = path.span; ex = ExprKind::Path(None, path); @@ -2902,6 +2904,51 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn should_parse_struct_expr( + &mut self, + lo: Span, + path: ast::Path, + attrs: ThinVec, + ) -> Option>> { + let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && ( + self.look_ahead(2, |t| *t == token::Colon) + || self.look_ahead(2, |t| *t == token::Comma) + // We could also check for `token::CloseDelim(token::Brace)`, but that would + // have false positives in the case of `if x == y { z } { a }`. + ); + let mut bad_struct = false; + let mut parse_struct = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); + if self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && could_be_struct { + // This is a struct literal, but we don't can't accept them here + bad_struct = true; + parse_struct = true; + } + if parse_struct { + match self.parse_struct_expr(lo, path, attrs) { + Err(err) => return Some(Err(err)), + Ok(expr) => { + if bad_struct { + let mut err = self.diagnostic().struct_span_err( + expr.span, + "struct literals are not allowed here", + ); + err.multipart_suggestion( + "surround the struct literal with parenthesis", + vec![ + (lo.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + err.emit(); + } + return Some(Ok(expr)); + } + } + } + None + } + fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec) -> PResult<'a, P> { let struct_sp = lo.to(self.prev_span); diff --git a/src/test/ui/error-codes/E0423.rs b/src/test/ui/error-codes/E0423.rs index 2b26808d4bde5..5080a5e059987 100644 --- a/src/test/ui/error-codes/E0423.rs +++ b/src/test/ui/error-codes/E0423.rs @@ -10,8 +10,7 @@ fn bar() { struct T {} if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - //~^ ERROR E0423 - //~| expected type, found `1` + //~^ ERROR struct literals are not allowed here if T {} == T {} { println!("Ok"); } //~^ ERROR E0423 //~| ERROR expected expression, found `==` @@ -19,6 +18,5 @@ fn bar() { fn foo() { for _ in std::ops::Range { start: 0, end: 10 } {} - //~^ ERROR E0423 - //~| ERROR expected type, found `0` + //~^ ERROR struct literals are not allowed here } diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr index b0ef4e1b25413..5cb7121a0d1c3 100644 --- a/src/test/ui/error-codes/E0423.stderr +++ b/src/test/ui/error-codes/E0423.stderr @@ -1,36 +1,28 @@ -error: expected type, found `1` - --> $DIR/E0423.rs:12:39 +error: struct literals are not allowed here + --> $DIR/E0423.rs:12:32 | LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - | ^ expecting a type here because of type ascription - | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/E0423.rs:12:36 + | ^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis | -LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - | ^ - = help: this might be indicative of a syntax error elsewhere +LL | if let S { x: _x, y: 2 } = (S { x: 1, y: 2 }) { println!("Ok"); } + | ^ ^ error: expected expression, found `==` - --> $DIR/E0423.rs:15:13 + --> $DIR/E0423.rs:14:13 | LL | if T {} == T {} { println!("Ok"); } | ^^ expected expression -error: expected type, found `0` - --> $DIR/E0423.rs:21:39 +error: struct literals are not allowed here + --> $DIR/E0423.rs:20:14 | LL | for _ in std::ops::Range { start: 0, end: 10 } {} - | ^ expecting a type here because of type ascription + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/E0423.rs:21:32 - | -LL | for _ in std::ops::Range { start: 0, end: 10 } {} - | ^^^^^ - = help: this might be indicative of a syntax error elsewhere +LL | for _ in (std::ops::Range { start: 0, end: 10 }) {} + | ^ ^ error[E0423]: expected function, found struct `Foo` --> $DIR/E0423.rs:4:13 @@ -41,30 +33,14 @@ LL | let f = Foo(); | did you mean `Foo { /* fields */ }`? | help: a function with a similar name exists: `foo` -error[E0423]: expected value, found struct `S` - --> $DIR/E0423.rs:12:32 - | -LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } - | ^--------------- - | | - | help: surround the struct literal with parenthesis: `(S { x: 1, y: 2 })` - error[E0423]: expected value, found struct `T` - --> $DIR/E0423.rs:15:8 + --> $DIR/E0423.rs:14:8 | LL | if T {} == T {} { println!("Ok"); } | ^--- | | | help: surround the struct literal with parenthesis: `(T {})` -error[E0423]: expected value, found struct `std::ops::Range` - --> $DIR/E0423.rs:21:14 - | -LL | for _ in std::ops::Range { start: 0, end: 10 } {} - | ^^^^^^^^^^^^^^^---------------------- - | | - | help: surround the struct literal with parenthesis: `(std::ops::Range { start: 0, end: 10 })` - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/parser/struct-literal-in-for.rs b/src/test/ui/parser/struct-literal-in-for.rs index 526b5e75c4574..3227ae37bfd05 100644 --- a/src/test/ui/parser/struct-literal-in-for.rs +++ b/src/test/ui/parser/struct-literal-in-for.rs @@ -9,9 +9,9 @@ impl Foo { } fn main() { - for x in Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + for x in Foo { //~ ERROR struct literals are not allowed here + x: 3 //~^ ERROR `bool` is not an iterator + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr index 07f2e41ac4fb0..3c3f6e7f032f6 100644 --- a/src/test/ui/parser/struct-literal-in-for.stderr +++ b/src/test/ui/parser/struct-literal-in-for.stderr @@ -1,29 +1,30 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-for.rs:13:12 - | -LL | x: 3 - | ^ expecting a type here because of type ascription +error: struct literals are not allowed here + --> $DIR/struct-literal-in-for.rs:12:14 | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-in-for.rs:13:9 +LL | for x in Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parenthesis | +LL | for x in (Foo { LL | x: 3 - | ^ - = help: this might be indicative of a syntax error elsewhere - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-for.rs:14:12 +LL | }).hi() { | -LL | }.hi() { - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here -error[E0423]: expected value, found struct `Foo` +error[E0277]: `bool` is not an iterator --> $DIR/struct-literal-in-for.rs:12:14 | -LL | for x in Foo { - | ^^^ did you mean `(Foo { /* fields */ })`? +LL | for x in Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |__________^ `bool` is not an iterator + | + = help: the trait `std::iter::Iterator` is not implemented for `bool` + = note: required by `std::iter::IntoIterator::into_iter` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0423`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/struct-literal-in-if.rs b/src/test/ui/parser/struct-literal-in-if.rs index 362a71c577fc9..2ce2c8f189944 100644 --- a/src/test/ui/parser/struct-literal-in-if.rs +++ b/src/test/ui/parser/struct-literal-in-if.rs @@ -9,9 +9,9 @@ impl Foo { } fn main() { - if Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` + if Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-if.stderr b/src/test/ui/parser/struct-literal-in-if.stderr index 3dd61e74f12ed..851c495abb4b0 100644 --- a/src/test/ui/parser/struct-literal-in-if.stderr +++ b/src/test/ui/parser/struct-literal-in-if.stderr @@ -1,29 +1,17 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-if.rs:13:12 - | -LL | x: 3 - | ^ expecting a type here because of type ascription +error: struct literals are not allowed here + --> $DIR/struct-literal-in-if.rs:12:8 | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-in-if.rs:13:9 +LL | if Foo { + | ________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parenthesis | +LL | if (Foo { LL | x: 3 - | ^ - = help: this might be indicative of a syntax error elsewhere - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-if.rs:14:12 - | -LL | }.hi() { - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` - --> $DIR/struct-literal-in-if.rs:12:8 +LL | }).hi() { | -LL | if Foo { - | ^^^ did you mean `(Foo { /* fields */ })`? -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.rs b/src/test/ui/parser/struct-literal-in-match-discriminant.rs index 35a1109035146..ce132df5a888b 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.rs +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.rs @@ -3,11 +3,11 @@ struct Foo { } fn main() { - match Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:` + match Foo { //~ ERROR struct literals are not allowed here + x: 3 } { - Foo { //~ ERROR mismatched types - x: x //~ ERROR cannot find value `x` in this scope - } => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` + Foo { + x: x + } => {} } } diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr index 94a758eb5268d..0058e8981cd25 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr @@ -1,42 +1,17 @@ -error: expected one of `=>`, `@`, `if`, or `|`, found `:` - --> $DIR/struct-literal-in-match-discriminant.rs:7:10 - | -LL | x: 3 - | ^ expected one of `=>`, `@`, `if`, or `|` here - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` - --> $DIR/struct-literal-in-match-discriminant.rs:11:11 - | -LL | } => {} - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` +error: struct literals are not allowed here --> $DIR/struct-literal-in-match-discriminant.rs:6:11 | -LL | match Foo { - | ^^^ did you mean `(Foo { /* fields */ })`? - -error[E0425]: cannot find value `x` in this scope - --> $DIR/struct-literal-in-match-discriminant.rs:10:16 - | -LL | x: x - | ^ not found in this scope - -error[E0308]: mismatched types - --> $DIR/struct-literal-in-match-discriminant.rs:9:9 +LL | match Foo { + | ___________^ +LL | | x: 3 +LL | | } { + | |_____^ +help: surround the struct literal with parenthesis | -LL | fn main() { - | - expected `()` because of default return type -... -LL | / Foo { -LL | | x: x -LL | | } => {} - | |_________^ expected (), found struct `Foo` +LL | match (Foo { +LL | x: 3 +LL | }) { | - = note: expected type `()` - found type `Foo` -error: aborting due to 5 previous errors +error: aborting due to previous error -Some errors occurred: E0308, E0423, E0425. -For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/struct-literal-in-while.rs b/src/test/ui/parser/struct-literal-in-while.rs index 561cdcea089a5..5000ce85b7f71 100644 --- a/src/test/ui/parser/struct-literal-in-while.rs +++ b/src/test/ui/parser/struct-literal-in-while.rs @@ -9,10 +9,9 @@ impl Foo { } fn main() { - while Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - //~| ERROR no method named `hi` found for type `()` in the current scope + while Foo { //~ ERROR struct literals are not allowed here + x: 3 + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-in-while.stderr b/src/test/ui/parser/struct-literal-in-while.stderr index d48244654cd02..9959a57be8596 100644 --- a/src/test/ui/parser/struct-literal-in-while.stderr +++ b/src/test/ui/parser/struct-literal-in-while.stderr @@ -1,36 +1,17 @@ -error: expected type, found `3` - --> $DIR/struct-literal-in-while.rs:13:12 - | -LL | x: 3 - | ^ expecting a type here because of type ascription +error: struct literals are not allowed here + --> $DIR/struct-literal-in-while.rs:12:11 | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-in-while.rs:13:9 +LL | while Foo { + | ___________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parenthesis | +LL | while (Foo { LL | x: 3 - | ^ - = help: this might be indicative of a syntax error elsewhere - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-in-while.rs:14:12 - | -LL | }.hi() { - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here - -error[E0423]: expected value, found struct `Foo` - --> $DIR/struct-literal-in-while.rs:12:11 - | -LL | while Foo { - | ^^^ did you mean `(Foo { /* fields */ })`? - -error[E0599]: no method named `hi` found for type `()` in the current scope - --> $DIR/struct-literal-in-while.rs:14:7 +LL | }).hi() { | -LL | }.hi() { - | ^^ -error: aborting due to 4 previous errors +error: aborting due to previous error -Some errors occurred: E0423, E0599. -For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs b/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs index e5049082ab016..e185153dcf62a 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.rs @@ -9,10 +9,9 @@ impl Foo { } fn main() { - while || Foo { //~ ERROR expected value, found struct `Foo` - x: 3 //~ ERROR expected type, found `3` - }.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - //~| ERROR no method named `hi` found for type `()` in the current scope + while || Foo { //~ ERROR struct literals are not allowed here + x: 3 //~^ ERROR mismatched types + }.hi() { println!("yo"); } } diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr index a8c93233dbc53..81f7a91ddb38a 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr @@ -1,36 +1,30 @@ -error: expected type, found `3` - --> $DIR/struct-literal-restrictions-in-lamda.rs:13:12 - | -LL | x: 3 - | ^ expecting a type here because of type ascription +error: struct literals are not allowed here + --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-restrictions-in-lamda.rs:13:9 +LL | while || Foo { + | ______________^ +LL | | x: 3 +LL | | }.hi() { + | |_____^ +help: surround the struct literal with parenthesis | +LL | while || (Foo { LL | x: 3 - | ^ - = help: this might be indicative of a syntax error elsewhere - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{` - --> $DIR/struct-literal-restrictions-in-lamda.rs:14:12 +LL | }).hi() { | -LL | }.hi() { - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here -error[E0423]: expected value, found struct `Foo` - --> $DIR/struct-literal-restrictions-in-lamda.rs:12:14 +error[E0308]: mismatched types + --> $DIR/struct-literal-restrictions-in-lamda.rs:12:11 | -LL | while || Foo { - | ^^^ did you mean `(Foo { /* fields */ })`? - -error[E0599]: no method named `hi` found for type `()` in the current scope - --> $DIR/struct-literal-restrictions-in-lamda.rs:14:7 +LL | while || Foo { + | ___________^ +LL | | x: 3 +LL | | }.hi() { + | |__________^ expected bool, found closure | -LL | }.hi() { - | ^^ + = note: expected type `bool` + found type `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0423, E0599. -For more information about an error, try `rustc --explain E0423`. +For more information about this error, try `rustc --explain E0308`. From b22261ef490436875fc1a8c4fab742c524020a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Apr 2019 08:08:46 -0700 Subject: [PATCH 21/23] Identify missing ambiguous case with best effort suggestion --- src/librustc_resolve/diagnostics.rs | 128 +++++++++++------- src/libsyntax/parse/parser.rs | 8 +- src/test/ui/struct-literal-variant-in-if.rs | 14 ++ .../ui/struct-literal-variant-in-if.stderr | 33 +++++ 4 files changed, 132 insertions(+), 51 deletions(-) create mode 100644 src/test/ui/struct-literal-variant-in-if.rs create mode 100644 src/test/ui/struct-literal-variant-in-if.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 9e3894dab0da0..afab02e52f08c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -238,6 +238,56 @@ impl<'a> Resolver<'a> { (err, candidates) } + fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) { + // HACK(estebank): find a better way to figure out that this was a + // parser issue where a struct literal is being used on an expression + // where a brace being opened means a block is being started. Look + // ahead for the next text to see if `span` is followed by a `{`. + let sm = self.session.source_map(); + let mut sp = span; + loop { + sp = sm.next_point(sp); + match sm.span_to_snippet(sp) { + Ok(ref snippet) => { + if snippet.chars().any(|c| { !c.is_whitespace() }) { + break; + } + } + _ => break, + } + } + let followed_by_brace = match sm.span_to_snippet(sp) { + Ok(ref snippet) if snippet == "{" => true, + _ => false, + }; + // In case this could be a struct literal that needs to be surrounded + // by parenthesis, find the appropriate span. + let mut i = 0; + let mut closing_brace = None; + loop { + sp = sm.next_point(sp); + match sm.span_to_snippet(sp) { + Ok(ref snippet) => { + if snippet == "}" { + let sp = span.to(sp); + if let Ok(snippet) = sm.span_to_snippet(sp) { + closing_brace = Some((sp, snippet)); + } + break; + } + } + _ => break, + } + i += 1; + // The bigger the span, the more likely we're incorrect -- + // bound it to 100 chars long. + if i > 100 { + break; + } + } + return (followed_by_brace, closing_brace) + } + /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` /// function. /// Returns `true` if able to provide context-dependent help. @@ -276,6 +326,8 @@ impl<'a> Resolver<'a> { _ => false, }; + let (followed_by_brace, closing_brace) = self.followed_by_brace(span); + match (def, source) { (Def::Macro(..), _) => { err.span_suggestion( @@ -329,52 +381,6 @@ impl<'a> Resolver<'a> { ); } } else { - // HACK(estebank): find a better way to figure out that this was a - // parser issue where a struct literal is being used on an expression - // where a brace being opened means a block is being started. Look - // ahead for the next text to see if `span` is followed by a `{`. - let sm = self.session.source_map(); - let mut sp = span; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet.chars().any(|c| { !c.is_whitespace() }) { - break; - } - } - _ => break, - } - } - let followed_by_brace = match sm.span_to_snippet(sp) { - Ok(ref snippet) if snippet == "{" => true, - _ => false, - }; - // In case this could be a struct literal that needs to be surrounded - // by parenthesis, find the appropriate span. - let mut i = 0; - let mut closing_brace = None; - loop { - sp = sm.next_point(sp); - match sm.span_to_snippet(sp) { - Ok(ref snippet) => { - if snippet == "}" { - let sp = span.to(sp); - if let Ok(snippet) = sm.span_to_snippet(sp) { - closing_brace = Some((sp, snippet)); - } - break; - } - } - _ => break, - } - i += 1; - // The bigger the span, the more likely we're incorrect -- - // bound it to 100 chars long. - if i > 100 { - break; - } - } match source { PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) { err.span_label( @@ -409,7 +415,35 @@ impl<'a> Resolver<'a> { (Def::Union(..), _) | (Def::Variant(..), _) | (Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => { - err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str)); + match source { + PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) { + err.span_label( + span, + format!("did you mean `{} {{ /* fields */ }}`?", path_str), + ); + } + PathSource::Expr(None) if followed_by_brace == true => { + if let Some((sp, snippet)) = closing_brace { + err.span_suggestion( + sp, + "surround the struct literal with parenthesis", + format!("({})", snippet), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + span, + format!("did you mean `({} {{ /* fields */ }})`?", path_str), + ); + } + }, + _ => { + err.span_label( + span, + format!("did you mean `{} {{ /* fields */ }}`?", path_str), + ); + }, + } } (Def::SelfTy(..), _) if ns == ValueNS => { err.span_label(span, fallback_label); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7d130470c6ac1..a82b1e11a5227 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2856,7 +2856,7 @@ impl<'a> Parser<'a> { hi = self.prev_span; ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim })); } else if self.check(&token::OpenDelim(token::Brace)) { - if let Some(expr) = self.should_parse_struct_expr(lo, path.clone(), attrs.clone()) { + if let Some(expr) = self.should_parse_struct_expr(lo, &path, &attrs) { return expr; } else { hi = path.span; @@ -2907,8 +2907,8 @@ impl<'a> Parser<'a> { fn should_parse_struct_expr( &mut self, lo: Span, - path: ast::Path, - attrs: ThinVec, + path: &ast::Path, + attrs: &ThinVec, ) -> Option>> { let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && ( self.look_ahead(2, |t| *t == token::Colon) @@ -2924,7 +2924,7 @@ impl<'a> Parser<'a> { parse_struct = true; } if parse_struct { - match self.parse_struct_expr(lo, path, attrs) { + match self.parse_struct_expr(lo, path.clone(), attrs.clone()) { Err(err) => return Some(Err(err)), Ok(expr) => { if bad_struct { diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs new file mode 100644 index 0000000000000..2d87c4ca73d01 --- /dev/null +++ b/src/test/ui/struct-literal-variant-in-if.rs @@ -0,0 +1,14 @@ +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +enum E { + V { field: bool } +} +fn test_E(x: E) { + let field = true; + if x == E::V { field } {} + //~^ ERROR expected value, found struct variant `E::V` + //~| ERROR mismatched types + let y: usize = (); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr new file mode 100644 index 0000000000000..e38eb0d61e060 --- /dev/null +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -0,0 +1,33 @@ +error[E0423]: expected value, found struct variant `E::V` + --> $DIR/struct-literal-variant-in-if.rs:7:13 + | +LL | if x == E::V { field } {} + | ^^^^---------- + | | + | help: surround the struct literal with parenthesis: `(E::V { field })` + +error[E0308]: mismatched types + --> $DIR/struct-literal-variant-in-if.rs:7:20 + | +LL | fn test_E(x: E) { + | - help: try adding a return type: `-> bool` +LL | let field = true; +LL | if x == E::V { field } {} + | ^^^^^ expected (), found bool + | + = note: expected type `()` + found type `bool` + +error[E0308]: mismatched types + --> $DIR/struct-literal-variant-in-if.rs:10:20 + | +LL | let y: usize = (); + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 3 previous errors + +Some errors occurred: E0308, E0423. +For more information about an error, try `rustc --explain E0308`. From 088421748dfa07eb3b78633336613ab9e3937b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 18 Apr 2019 11:35:11 -0700 Subject: [PATCH 22/23] remove duplicated code and simplify logic --- src/librustc_resolve/diagnostics.rs | 93 +++++++------------ src/libsyntax/parse/parser.rs | 61 ++++++------ src/test/ui/struct-literal-variant-in-if.rs | 15 ++- .../ui/struct-literal-variant-in-if.stderr | 70 +++++++++++++- 4 files changed, 145 insertions(+), 94 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index afab02e52f08c..68e0d60db0330 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -326,7 +326,38 @@ impl<'a> Resolver<'a> { _ => false, }; - let (followed_by_brace, closing_brace) = self.followed_by_brace(span); + let mut bad_struct_syntax_suggestion = || { + let (followed_by_brace, closing_brace) = self.followed_by_brace(span); + let mut suggested = false; + match source { + PathSource::Expr(Some(parent)) => { + suggested = path_sep(err, &parent); + } + PathSource::Expr(None) if followed_by_brace == true => { + if let Some((sp, snippet)) = closing_brace { + err.span_suggestion( + sp, + "surround the struct literal with parenthesis", + format!("({})", snippet), + Applicability::MaybeIncorrect, + ); + } else { + err.span_label( + span, // Note the parenthesis surrounding the suggestion below + format!("did you mean `({} {{ /* fields */ }})`?", path_str), + ); + } + suggested = true; + }, + _ => {} + } + if !suggested { + err.span_label( + span, + format!("did you mean `{} {{ /* fields */ }}`?", path_str), + ); + } + }; match (def, source) { (Def::Macro(..), _) => { @@ -381,69 +412,13 @@ impl<'a> Resolver<'a> { ); } } else { - match source { - PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - } - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, - format!("did you mean `({} {{ /* fields */ }})`?", path_str), - ); - } - }, - _ => { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - }, - } + bad_struct_syntax_suggestion(); } } (Def::Union(..), _) | (Def::Variant(..), _) | (Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => { - match source { - PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - } - PathSource::Expr(None) if followed_by_brace == true => { - if let Some((sp, snippet)) = closing_brace { - err.span_suggestion( - sp, - "surround the struct literal with parenthesis", - format!("({})", snippet), - Applicability::MaybeIncorrect, - ); - } else { - err.span_label( - span, - format!("did you mean `({} {{ /* fields */ }})`?", path_str), - ); - } - }, - _ => { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", path_str), - ); - }, - } + bad_struct_syntax_suggestion(); } (Def::SelfTy(..), _) if ns == ValueNS => { err.span_label(span, fallback_label); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a82b1e11a5227..a2a2c4637c571 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2856,7 +2856,7 @@ impl<'a> Parser<'a> { hi = self.prev_span; ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim })); } else if self.check(&token::OpenDelim(token::Brace)) { - if let Some(expr) = self.should_parse_struct_expr(lo, &path, &attrs) { + if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { return expr; } else { hi = path.span; @@ -2904,47 +2904,48 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn should_parse_struct_expr( + fn maybe_parse_struct_expr( &mut self, lo: Span, path: &ast::Path, attrs: &ThinVec, ) -> Option>> { + // We don't want to assume it's a struct when encountering `{ : }` because + // it could be type ascription, like in `{ ident: u32 }`. + let isnt_ascription = self.look_ahead(1, |t| t.is_ident()) && + self.look_ahead(2, |t| *t == token::Colon) && ( + (self.look_ahead(3, |t| t.is_ident()) && + self.look_ahead(4, |t| *t == token::Comma)) || + self.look_ahead(3, |t| t.is_lit()) || + self.look_ahead(3, |t| *t == token::BinOp(token::Minus)) && + self.look_ahead(4, |t| t.is_lit()) + ); let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && ( - self.look_ahead(2, |t| *t == token::Colon) + self.look_ahead(2, |t| *t == token::Colon) && isnt_ascription || self.look_ahead(2, |t| *t == token::Comma) // We could also check for `token::CloseDelim(token::Brace)`, but that would // have false positives in the case of `if x == y { z } { a }`. ); - let mut bad_struct = false; - let mut parse_struct = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && could_be_struct { + let bad_struct = self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); + if !bad_struct || could_be_struct { // This is a struct literal, but we don't can't accept them here - bad_struct = true; - parse_struct = true; - } - if parse_struct { - match self.parse_struct_expr(lo, path.clone(), attrs.clone()) { - Err(err) => return Some(Err(err)), - Ok(expr) => { - if bad_struct { - let mut err = self.diagnostic().struct_span_err( - expr.span, - "struct literals are not allowed here", - ); - err.multipart_suggestion( - "surround the struct literal with parenthesis", - vec![ - (lo.shrink_to_lo(), "(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - err.emit(); - } - return Some(Ok(expr)); - } + let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); + if let (Ok(expr), true) = (&expr, bad_struct) { + let mut err = self.diagnostic().struct_span_err( + expr.span, + "struct literals are not allowed here", + ); + err.multipart_suggestion( + "surround the struct literal with parenthesis", + vec![ + (lo.shrink_to_lo(), "(".to_string()), + (expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + err.emit(); } + return Some(expr); } None } diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs index 2d87c4ca73d01..8f2d50586c055 100644 --- a/src/test/ui/struct-literal-variant-in-if.rs +++ b/src/test/ui/struct-literal-variant-in-if.rs @@ -1,12 +1,25 @@ #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] enum E { - V { field: bool } + V { field: bool }, + I { field1: bool, field2: usize }, + J { field: isize }, + K { field: &'static str}, } fn test_E(x: E) { let field = true; if x == E::V { field } {} //~^ ERROR expected value, found struct variant `E::V` //~| ERROR mismatched types + if x == E::I { field1: true, field2: 42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::V { field: false } {} + //~^ ERROR expected identifier, found keyword `false` + //~| ERROR expected type, found keyword `false` + //~| ERROR expected value, found struct variant `E::V` + if x == E::J { field: -42 } {} + //~^ ERROR struct literals are not allowed here + if x == E::K { field: "" } {} + //~^ ERROR struct literals are not allowed here let y: usize = (); //~^ ERROR mismatched types } diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr index e38eb0d61e060..0af0c6aefaf40 100644 --- a/src/test/ui/struct-literal-variant-in-if.stderr +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -1,13 +1,75 @@ +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:13:13 + | +LL | if x == E::I { field1: true, field2: 42 } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis + | +LL | if x == (E::I { field1: true, field2: 42 }) {} + | ^ ^ + +error: expected identifier, found keyword `false` + --> $DIR/struct-literal-variant-in-if.rs:15:27 + | +LL | if x == E::V { field: false } {} + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | if x == E::V { field: r#false } {} + | ^^^^^^^ + +error: expected type, found keyword `false` + --> $DIR/struct-literal-variant-in-if.rs:15:27 + | +LL | if x == E::V { field: false } {} + | ^^^^^ expecting a type here because of type ascription + | + = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` +note: this expression expects an ascribed type after the colon + --> $DIR/struct-literal-variant-in-if.rs:15:20 + | +LL | if x == E::V { field: false } {} + | ^^^^^ + = help: this might be indicative of a syntax error elsewhere + +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:19:13 + | +LL | if x == E::J { field: -42 } {} + | ^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis + | +LL | if x == (E::J { field: -42 }) {} + | ^ ^ + +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:21:13 + | +LL | if x == E::K { field: "" } {} + | ^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis + | +LL | if x == (E::K { field: "" }) {} + | ^ ^ + error[E0423]: expected value, found struct variant `E::V` - --> $DIR/struct-literal-variant-in-if.rs:7:13 + --> $DIR/struct-literal-variant-in-if.rs:10:13 | LL | if x == E::V { field } {} | ^^^^---------- | | | help: surround the struct literal with parenthesis: `(E::V { field })` +error[E0423]: expected value, found struct variant `E::V` + --> $DIR/struct-literal-variant-in-if.rs:15:13 + | +LL | if x == E::V { field: false } {} + | ^^^^----------------- + | | + | help: surround the struct literal with parenthesis: `(E::V { field: false })` + error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:7:20 + --> $DIR/struct-literal-variant-in-if.rs:10:20 | LL | fn test_E(x: E) { | - help: try adding a return type: `-> bool` @@ -19,7 +81,7 @@ LL | if x == E::V { field } {} found type `bool` error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:10:20 + --> $DIR/struct-literal-variant-in-if.rs:23:20 | LL | let y: usize = (); | ^^ expected usize, found () @@ -27,7 +89,7 @@ LL | let y: usize = (); = note: expected type `usize` found type `()` -error: aborting due to 3 previous errors +error: aborting due to 9 previous errors Some errors occurred: E0308, E0423. For more information about an error, try `rustc --explain E0308`. From 9c42ec34e7412259dc8c3d288d2a376ed304e3f2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Apr 2019 23:58:57 +0300 Subject: [PATCH 23/23] Some cleanup to `maybe_parse_struct_expr` --- src/libsyntax/parse/parser.rs | 31 ++++++-------- src/test/ui/struct-literal-variant-in-if.rs | 4 +- .../ui/struct-literal-variant-in-if.stderr | 42 +++++-------------- 3 files changed, 24 insertions(+), 53 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2a2c4637c571..8feab373e7102 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2910,27 +2910,22 @@ impl<'a> Parser<'a> { path: &ast::Path, attrs: &ThinVec, ) -> Option>> { - // We don't want to assume it's a struct when encountering `{ : }` because - // it could be type ascription, like in `{ ident: u32 }`. - let isnt_ascription = self.look_ahead(1, |t| t.is_ident()) && - self.look_ahead(2, |t| *t == token::Colon) && ( - (self.look_ahead(3, |t| t.is_ident()) && - self.look_ahead(4, |t| *t == token::Comma)) || - self.look_ahead(3, |t| t.is_lit()) || - self.look_ahead(3, |t| *t == token::BinOp(token::Minus)) && - self.look_ahead(4, |t| t.is_lit()) - ); - let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && ( - self.look_ahead(2, |t| *t == token::Colon) && isnt_ascription - || self.look_ahead(2, |t| *t == token::Comma) - // We could also check for `token::CloseDelim(token::Brace)`, but that would - // have false positives in the case of `if x == y { z } { a }`. + let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); + let certainly_not_a_block = || self.look_ahead(1, |t| t.is_ident()) && ( + // `{ ident, ` cannot start a block + self.look_ahead(2, |t| t == &token::Comma) || + self.look_ahead(2, |t| t == &token::Colon) && ( + // `{ ident: token, ` cannot start a block + self.look_ahead(4, |t| t == &token::Comma) || + // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type` + self.look_ahead(3, |t| !t.can_begin_type()) + ) ); - let bad_struct = self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if !bad_struct || could_be_struct { + + if struct_allowed || certainly_not_a_block() { // This is a struct literal, but we don't can't accept them here let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); - if let (Ok(expr), true) = (&expr, bad_struct) { + if let (Ok(expr), false) = (&expr, struct_allowed) { let mut err = self.diagnostic().struct_span_err( expr.span, "struct literals are not allowed here", diff --git a/src/test/ui/struct-literal-variant-in-if.rs b/src/test/ui/struct-literal-variant-in-if.rs index 8f2d50586c055..4ef8effaf1f5f 100644 --- a/src/test/ui/struct-literal-variant-in-if.rs +++ b/src/test/ui/struct-literal-variant-in-if.rs @@ -13,9 +13,7 @@ fn test_E(x: E) { if x == E::I { field1: true, field2: 42 } {} //~^ ERROR struct literals are not allowed here if x == E::V { field: false } {} - //~^ ERROR expected identifier, found keyword `false` - //~| ERROR expected type, found keyword `false` - //~| ERROR expected value, found struct variant `E::V` + //~^ ERROR struct literals are not allowed here if x == E::J { field: -42 } {} //~^ ERROR struct literals are not allowed here if x == E::K { field: "" } {} diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr index 0af0c6aefaf40..3288fa9fc7d31 100644 --- a/src/test/ui/struct-literal-variant-in-if.stderr +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -8,32 +8,18 @@ help: surround the struct literal with parenthesis LL | if x == (E::I { field1: true, field2: 42 }) {} | ^ ^ -error: expected identifier, found keyword `false` - --> $DIR/struct-literal-variant-in-if.rs:15:27 - | -LL | if x == E::V { field: false } {} - | ^^^^^ expected identifier, found keyword -help: you can escape reserved keywords to use them as identifiers - | -LL | if x == E::V { field: r#false } {} - | ^^^^^^^ - -error: expected type, found keyword `false` - --> $DIR/struct-literal-variant-in-if.rs:15:27 +error: struct literals are not allowed here + --> $DIR/struct-literal-variant-in-if.rs:15:13 | LL | if x == E::V { field: false } {} - | ^^^^^ expecting a type here because of type ascription - | - = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `: ` -note: this expression expects an ascribed type after the colon - --> $DIR/struct-literal-variant-in-if.rs:15:20 + | ^^^^^^^^^^^^^^^^^^^^^ +help: surround the struct literal with parenthesis | -LL | if x == E::V { field: false } {} - | ^^^^^ - = help: this might be indicative of a syntax error elsewhere +LL | if x == (E::V { field: false }) {} + | ^ ^ error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:19:13 + --> $DIR/struct-literal-variant-in-if.rs:17:13 | LL | if x == E::J { field: -42 } {} | ^^^^^^^^^^^^^^^^^^^ @@ -43,7 +29,7 @@ LL | if x == (E::J { field: -42 }) {} | ^ ^ error: struct literals are not allowed here - --> $DIR/struct-literal-variant-in-if.rs:21:13 + --> $DIR/struct-literal-variant-in-if.rs:19:13 | LL | if x == E::K { field: "" } {} | ^^^^^^^^^^^^^^^^^^ @@ -60,14 +46,6 @@ LL | if x == E::V { field } {} | | | help: surround the struct literal with parenthesis: `(E::V { field })` -error[E0423]: expected value, found struct variant `E::V` - --> $DIR/struct-literal-variant-in-if.rs:15:13 - | -LL | if x == E::V { field: false } {} - | ^^^^----------------- - | | - | help: surround the struct literal with parenthesis: `(E::V { field: false })` - error[E0308]: mismatched types --> $DIR/struct-literal-variant-in-if.rs:10:20 | @@ -81,7 +59,7 @@ LL | if x == E::V { field } {} found type `bool` error[E0308]: mismatched types - --> $DIR/struct-literal-variant-in-if.rs:23:20 + --> $DIR/struct-literal-variant-in-if.rs:21:20 | LL | let y: usize = (); | ^^ expected usize, found () @@ -89,7 +67,7 @@ LL | let y: usize = (); = note: expected type `usize` found type `()` -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors Some errors occurred: E0308, E0423. For more information about an error, try `rustc --explain E0308`.