From cec2a9fad057f71fc640392ba3fa47602aea12f6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 18:47:44 +0100 Subject: [PATCH 01/12] macro_legacy_warnings -> error --- src/librustc_expand/expand.rs | 11 ++-- src/librustc_expand/mbe/macro_rules.rs | 2 +- src/librustc_parse/parser/stmt.rs | 62 +++---------------- .../ui/missing/missing-semicolon-warning.rs | 12 ---- .../missing/missing-semicolon-warning.stderr | 24 ------- src/test/ui/parser/missing-semicolon.rs | 8 +++ src/test/ui/parser/missing-semicolon.stderr | 13 ++++ 7 files changed, 35 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/missing/missing-semicolon-warning.rs delete mode 100644 src/test/ui/missing/missing-semicolon-warning.stderr create mode 100644 src/test/ui/parser/missing-semicolon.rs create mode 100644 src/test/ui/parser/missing-semicolon.stderr diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 90692fe1ec9dd..6b1a41943ce2f 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -821,7 +821,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { span: Span, ) -> AstFragment { let mut parser = self.cx.new_parser_from_tts(toks); - match parse_ast_fragment(&mut parser, kind, false) { + match parse_ast_fragment(&mut parser, kind) { Ok(fragment) => { ensure_complete_parse(&mut parser, path, kind.name(), span); fragment @@ -840,7 +840,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { pub fn parse_ast_fragment<'a>( this: &mut Parser<'a>, kind: AstFragmentKind, - macro_legacy_warnings: bool, ) -> PResult<'a, AstFragment> { Ok(match kind { AstFragmentKind::Items => { @@ -873,11 +872,9 @@ pub fn parse_ast_fragment<'a>( } AstFragmentKind::Stmts => { let mut stmts = SmallVec::new(); - while this.token != token::Eof && - // won't make progress on a `}` - this.token != token::CloseDelim(token::Brace) - { - if let Some(stmt) = this.parse_full_stmt(macro_legacy_warnings)? { + // Won't make progress on a `}`. + while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) { + if let Some(stmt) = this.parse_full_stmt()? { stmts.push(stmt); } } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 9e6edee265c98..6a9f5459cb5d0 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -87,7 +87,7 @@ fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Pa impl<'a> ParserAnyMacro<'a> { crate fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; - let fragment = panictry!(parse_ast_fragment(parser, kind, true).map_err(|mut e| { + let fragment = panictry!(parse_ast_fragment(parser, kind).map_err(|mut e| { if parser.token == token::Eof && e.message().ends_with(", found ``") { if !e.span.is_dummy() { // early end of macro arm (#52866) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index e11cdd5dadb72..928d2a4026602 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -22,17 +22,14 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. pub fn parse_stmt(&mut self) -> PResult<'a, Option> { - Ok(self.parse_stmt_without_recovery(true).unwrap_or_else(|mut e| { + Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None })) } - fn parse_stmt_without_recovery( - &mut self, - macro_legacy_warnings: bool, - ) -> PResult<'a, Option> { + fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; @@ -74,7 +71,7 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Expr)?; if self.eat(&token::Not) { - return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings); + return self.parse_stmt_mac(lo, attrs.into(), path); } let expr = if self.check(&token::OpenDelim(token::Brace)) { @@ -137,7 +134,6 @@ impl<'a> Parser<'a> { lo: Span, attrs: AttrVec, path: ast::Path, - legacy_warnings: bool, ) -> PResult<'a, Option> { let args = self.parse_mac_args()?; let delim = args.delim(); @@ -150,30 +146,6 @@ impl<'a> Parser<'a> { let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { - StmtKind::Mac(P((mac, style, attrs.into()))) - } - // We used to incorrectly stop parsing macro-expanded statements here. - // If the next token will be an error anyway but could have parsed with the - // earlier behavior, stop parsing here and emit a warning to avoid breakage. - else if legacy_warnings - && self.token.can_begin_expr() - && match self.token.kind { - // These can continue an expression, so we can't stop parsing and warn. - token::OpenDelim(token::Paren) - | token::OpenDelim(token::Bracket) - | token::BinOp(token::Minus) - | token::BinOp(token::Star) - | token::BinOp(token::And) - | token::BinOp(token::Or) - | token::AndAnd - | token::OrOr - | token::DotDot - | token::DotDotDot - | token::DotDotEq => false, - _ => true, - } - { - self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs))) } else { // Since none of the above applied, this is an expression statement macro. @@ -334,7 +306,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery(false) { + match self.parse_stmt_without_recovery() { Ok(Some(stmt)) => { if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) || do_not_suggest_help @@ -393,7 +365,7 @@ impl<'a> Parser<'a> { if self.token == token::Eof { break; } - let stmt = match self.parse_full_stmt(false) { + let stmt = match self.parse_full_stmt() { Err(mut err) => { self.maybe_annotate_with_ascription(&mut err, false); err.emit(); @@ -413,11 +385,11 @@ impl<'a> Parser<'a> { } /// Parses a statement, including the trailing semicolon. - pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { + pub fn parse_full_stmt(&mut self) -> PResult<'a, Option> { // Skip looking for a trailing semicolon when we have an interpolated statement. maybe_whole!(self, NtStmt, |x| Some(x)); - let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? { + let mut stmt = match self.parse_stmt_without_recovery()? { Some(stmt) => stmt, None => return Ok(None), }; @@ -457,13 +429,8 @@ impl<'a> Parser<'a> { } } StmtKind::Local(..) => { - // We used to incorrectly allow a macro-expanded let statement to lack a semicolon. - if macro_legacy_warnings && self.token != token::Semi { - self.warn_missing_semicolon(); - } else { - self.expect_semi()?; - eat_semi = false; - } + self.expect_semi()?; + eat_semi = false; } _ => {} } @@ -475,17 +442,6 @@ impl<'a> Parser<'a> { Ok(Some(stmt)) } - fn warn_missing_semicolon(&self) { - self.diagnostic() - .struct_span_warn(self.token.span, { - &format!("expected `;`, found {}", super::token_descr(&self.token)) - }) - .note({ - "this was erroneously allowed and will become a hard error in a future release" - }) - .emit(); - } - pub(super) fn mk_block(&self, stmts: Vec, rules: BlockCheckMode, span: Span) -> P { P(Block { stmts, id: DUMMY_NODE_ID, rules, span }) } diff --git a/src/test/ui/missing/missing-semicolon-warning.rs b/src/test/ui/missing/missing-semicolon-warning.rs deleted file mode 100644 index d962a52139eea..0000000000000 --- a/src/test/ui/missing/missing-semicolon-warning.rs +++ /dev/null @@ -1,12 +0,0 @@ -// build-pass (FIXME(62277): could be check-pass?) -#![allow(unused)] - -macro_rules! m { - ($($e1:expr),*; $($e2:expr),*) => { - $( let x = $e1 )*; //~ WARN expected `;` - $( println!("{}", $e2) )*; //~ WARN expected `;` - } -} - - -fn main() { m!(0, 0; 0, 0); } diff --git a/src/test/ui/missing/missing-semicolon-warning.stderr b/src/test/ui/missing/missing-semicolon-warning.stderr deleted file mode 100644 index ecaefd47de0b4..0000000000000 --- a/src/test/ui/missing/missing-semicolon-warning.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: expected `;`, found keyword `let` - --> $DIR/missing-semicolon-warning.rs:6:12 - | -LL | $( let x = $e1 )*; - | ^^^ -... -LL | fn main() { m!(0, 0; 0, 0); } - | --------------- in this macro invocation - | - = note: this was erroneously allowed and will become a hard error in a future release - = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: expected `;`, found `println` - --> $DIR/missing-semicolon-warning.rs:7:12 - | -LL | $( println!("{}", $e2) )*; - | ^^^^^^^ -... -LL | fn main() { m!(0, 0; 0, 0); } - | --------------- in this macro invocation - | - = note: this was erroneously allowed and will become a hard error in a future release - = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - diff --git a/src/test/ui/parser/missing-semicolon.rs b/src/test/ui/parser/missing-semicolon.rs new file mode 100644 index 0000000000000..a24dfa761a60f --- /dev/null +++ b/src/test/ui/parser/missing-semicolon.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($($e1:expr),*; $($e2:expr),*) => { + $( let x = $e1 )*; //~ ERROR expected one of `.`, `;`, `?`, or + $( println!("{}", $e2) )*; + } +} + +fn main() { m!(0, 0; 0, 0); } diff --git a/src/test/ui/parser/missing-semicolon.stderr b/src/test/ui/parser/missing-semicolon.stderr new file mode 100644 index 0000000000000..26cb3d13d9c48 --- /dev/null +++ b/src/test/ui/parser/missing-semicolon.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `;`, `?`, or an operator, found keyword `let` + --> $DIR/missing-semicolon.rs:3:12 + | +LL | $( let x = $e1 )*; + | ^^^ expected one of `.`, `;`, `?`, or an operator +... +LL | fn main() { m!(0, 0; 0, 0); } + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + From 6351bfd182267133409c5174decdff2071f90454 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:53:58 +0900 Subject: [PATCH 02/12] Add test for issue-39618 --- src/test/ui/specialization/issue-39618.rs | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/ui/specialization/issue-39618.rs diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs new file mode 100644 index 0000000000000..78894a5699775 --- /dev/null +++ b/src/test/ui/specialization/issue-39618.rs @@ -0,0 +1,24 @@ +// Regression test for #39618, shouldn't crash. +// check-pass + +#![feature(specialization)] + +trait Foo { + fn foo(&self); +} + +trait Bar { + fn bar(&self); +} + +impl Bar for T where T: Foo { + fn bar(&self) {} +} + +impl Foo for T where T: Bar { + fn foo(&self) {} +} + +impl Foo for u64 {} + +fn main() {} From f32447d54138e9f42ba5a729550603573913397f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:16 +0900 Subject: [PATCH 03/12] Add test for issue-51798 --- src/test/ui/issues/auxiliary/issue-51798.rs | 3 +++ src/test/ui/issues/issue-51798.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/issues/auxiliary/issue-51798.rs create mode 100644 src/test/ui/issues/issue-51798.rs diff --git a/src/test/ui/issues/auxiliary/issue-51798.rs b/src/test/ui/issues/auxiliary/issue-51798.rs new file mode 100644 index 0000000000000..fef5213db9f7a --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-51798.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +pub fn vec() -> Vec { vec![] } diff --git a/src/test/ui/issues/issue-51798.rs b/src/test/ui/issues/issue-51798.rs new file mode 100644 index 0000000000000..b075809e93ac2 --- /dev/null +++ b/src/test/ui/issues/issue-51798.rs @@ -0,0 +1,14 @@ +// edition:2018 +// aux-build:issue-51798.rs +// check-pass + +extern crate issue_51798; + +mod server { + fn f() { + let mut v = issue_51798::vec(); + v.clear(); + } +} + +fn main() {} From ecb8bf069e0a32d8c76884786a5a0b1ea7ccf8d9 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:33 +0900 Subject: [PATCH 04/12] Add test for issue-62894 --- src/test/ui/parser/issue-62894.rs | 7 ++++ src/test/ui/parser/issue-62894.stderr | 47 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/test/ui/parser/issue-62894.rs create mode 100644 src/test/ui/parser/issue-62894.stderr diff --git a/src/test/ui/parser/issue-62894.rs b/src/test/ui/parser/issue-62894.rs new file mode 100644 index 0000000000000..b9c0bf834ddb2 --- /dev/null +++ b/src/test/ui/parser/issue-62894.rs @@ -0,0 +1,7 @@ +// Regression test for #62894, shouldn't crash. +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected one of `(`, `[`, or `{`, found keyword `fn` + +fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + +fn main() {} diff --git a/src/test/ui/parser/issue-62894.stderr b/src/test/ui/parser/issue-62894.stderr new file mode 100644 index 0000000000000..6db380f7a7fe2 --- /dev/null +++ b/src/test/ui/parser/issue-62894.stderr @@ -0,0 +1,47 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: expected one of `(`, `[`, or `{`, found keyword `fn` + --> $DIR/issue-62894.rs:7:1 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - expected one of `(`, `[`, or `{` +LL | +LL | fn main() {} + | ^^ unexpected token + +error: aborting due to 4 previous errors + From 426dcf0da03b4287991e378c50ddb0718960941b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:54:51 +0900 Subject: [PATCH 05/12] Add test for issue-63952 --- src/test/ui/consts/issue-63952.rs | 28 +++++++++++++++++++++++++++ src/test/ui/consts/issue-63952.stderr | 17 ++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/ui/consts/issue-63952.rs create mode 100644 src/test/ui/consts/issue-63952.stderr diff --git a/src/test/ui/consts/issue-63952.rs b/src/test/ui/consts/issue-63952.rs new file mode 100644 index 0000000000000..35cbc7003f095 --- /dev/null +++ b/src/test/ui/consts/issue-63952.rs @@ -0,0 +1,28 @@ +// Regression test for #63952, shouldn't hang. + +use std::usize; + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +union SliceTransmute { + repr: SliceRepr, + slice: &'static [u8], +} + +// bad slice: length too big to even exist anywhere +const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: it is undefined behavior to use this value + SliceTransmute { + repr: SliceRepr { + ptr: &42, + len: usize::MAX, + }, + } + .slice +}; + +fn main() {} diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr new file mode 100644 index 0000000000000..d5ed970fc3533 --- /dev/null +++ b/src/test/ui/consts/issue-63952.stderr @@ -0,0 +1,17 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-63952.rs:18:1 + | +LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { +LL | | SliceTransmute { +LL | | repr: SliceRepr { +LL | | ptr: &42, +... | +LL | | .slice +LL | | }; + | |__^ invalid slice: total size is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From 9478503315795401ce037fbca87bf1dbf82f8d31 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 02:55:03 +0900 Subject: [PATCH 06/12] Add test for issue-68653 --- .../ui/generic-associated-types/issue-68653.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/generic-associated-types/issue-68653.rs diff --git a/src/test/ui/generic-associated-types/issue-68653.rs b/src/test/ui/generic-associated-types/issue-68653.rs new file mode 100644 index 0000000000000..01f4c95639d19 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68653.rs @@ -0,0 +1,16 @@ +// A regression test for #68653, which was fixed by #68938. + +// check-pass + +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait Fun { + type F<'a: 'a>; +} + +impl Fun for T { + type F<'a> = Self; +} + +fn main() {} From 2f39ec24b20bc1ef09c7810f8210ea48bb5a3d29 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 16 Feb 2020 04:36:44 +0900 Subject: [PATCH 07/12] Add FIXME note --- src/test/ui/specialization/issue-39618.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs index 78894a5699775..20e81e4359bac 100644 --- a/src/test/ui/specialization/issue-39618.rs +++ b/src/test/ui/specialization/issue-39618.rs @@ -1,4 +1,7 @@ // Regression test for #39618, shouldn't crash. +// FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here. +// More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796 + // check-pass #![feature(specialization)] From 759526e513f28443b845b63176f15424686d0254 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 16 Feb 2020 00:57:48 +0100 Subject: [PATCH 08/12] Fix printing of `Yield` terminator --- src/librustc/mir/mod.rs | 18 ++++++++++-------- .../mir-opt/generator-storage-dead-unwind.rs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4520d3a333316..a3e3a26db05d6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1468,21 +1468,23 @@ impl<'tcx> TerminatorKind<'tcx> { /// successors, which may be rendered differently between the text and the graphviz format. pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { use self::TerminatorKind::*; - match *self { + match self { Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr: ref place, .. } => write!(fmt, "switchInt({:?})", place), + SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), Abort => write!(fmt, "abort"), - Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), + Yield { value, resume_arg, .. } => { + write!(fmt, "{:?} = suspend({:?})", resume_arg, value) + } Unreachable => write!(fmt, "unreachable"), - Drop { ref location, .. } => write!(fmt, "drop({:?})", location), - DropAndReplace { ref location, ref value, .. } => { + Drop { location, .. } => write!(fmt, "drop({:?})", location), + DropAndReplace { location, value, .. } => { write!(fmt, "replace({:?} <- {:?})", location, value) } - Call { ref func, ref args, ref destination, .. } => { - if let Some((ref destination, _)) = *destination { + Call { func, args, destination, .. } => { + if let Some((destination, _)) = destination { write!(fmt, "{:?} = ", destination)?; } write!(fmt, "{:?}(", func)?; @@ -1494,7 +1496,7 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ")") } - Assert { ref cond, expected, ref msg, .. } => { + Assert { cond, expected, msg, .. } => { write!(fmt, "assert(")?; if !expected { write!(fmt, "!")?; diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 4442fa5f52126..98acce8375974 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -49,7 +49,7 @@ fn main() { // StorageLive(_4); // _4 = Bar(const 6i32,); // ... -// _1 = suspend(move _6) -> [resume: bb2, drop: bb4]; +// _5 = suspend(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; From bb482ebf2870bae6e1b69822f1c7d7d9d4b33103 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 16 Feb 2020 13:08:36 +0100 Subject: [PATCH 09/12] suspend -> yield --- src/librustc/mir/mod.rs | 4 +--- src/test/mir-opt/generator-storage-dead-unwind.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a3e3a26db05d6..9b94f92acd476 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1475,9 +1475,7 @@ impl<'tcx> TerminatorKind<'tcx> { GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), Abort => write!(fmt, "abort"), - Yield { value, resume_arg, .. } => { - write!(fmt, "{:?} = suspend({:?})", resume_arg, value) - } + Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), Drop { location, .. } => write!(fmt, "drop({:?})", location), DropAndReplace { location, value, .. } => { diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 98acce8375974..82b216a99cf55 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -49,7 +49,7 @@ fn main() { // StorageLive(_4); // _4 = Bar(const 6i32,); // ... -// _5 = suspend(move _6) -> [resume: bb2, drop: bb4]; +// _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; From bec5d37ee19c33bec96ed235f0197317d3728e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 14:44:16 +0100 Subject: [PATCH 10/12] debug_assert a few more raw pointer methods --- src/libcore/intrinsics.rs | 9 +++++---- src/libcore/ptr/mod.rs | 12 +++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2cee23a5c752c..9a23b54dfa0a5 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1423,13 +1423,14 @@ pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { } /// Checks whether the regions of memory starting at `src` and `dst` of size -/// `count * size_of::()` overlap. -fn overlaps(src: *const T, dst: *const T, count: usize) -> bool { +/// `count * size_of::()` do *not* overlap. +pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) -> bool { let src_usize = src as usize; let dst_usize = dst as usize; let size = mem::size_of::().checked_mul(count).unwrap(); let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize }; - size > diff + let overlaps = size > diff; + !overlaps } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -1524,7 +1525,7 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); - debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory"); + debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory"); copy_nonoverlapping(src, dst, count) } diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 0ee50966f968c..ce21773165a6a 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -72,7 +72,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash; -use crate::intrinsics; +use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping}; use crate::mem::{self, MaybeUninit}; #[stable(feature = "rust1", since = "1.0.0")] @@ -389,6 +389,10 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { + debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer"); + debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer"); + debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory"); + let x = x as *mut u8; let y = y as *mut u8; let len = mem::size_of::() * count; @@ -612,6 +616,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); tmp.assume_init() @@ -703,6 +708,7 @@ pub unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); tmp.assume_init() @@ -795,6 +801,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::move_val_init(&mut *dst, src) } @@ -887,6 +894,7 @@ pub unsafe fn write(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { + // `copy_nonoverlapping` takes care of debug_assert. copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); mem::forget(src); } @@ -956,6 +964,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn read_volatile(src: *const T) -> T { + debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer"); intrinsics::volatile_load(src) } @@ -1024,6 +1033,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn write_volatile(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::volatile_store(dst, src); } From 8bafe883b6bb273b7a256d7720e638b267c2e574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 13 Feb 2020 22:45:48 -0800 Subject: [PATCH 11/12] Select an appropriate unused lifetime name in suggestion --- src/librustc_typeck/collect.rs | 50 ++++++++++++++++--- ...iated-types-project-from-hrtb-in-struct.rs | 11 +++- ...d-types-project-from-hrtb-in-struct.stderr | 23 +++++++-- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 80d914d8d0ae5..ca3bcac1206be 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -33,7 +33,7 @@ use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -369,10 +369,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { hir::ItemKind::Enum(_, generics) | hir::ItemKind::Struct(_, generics) | hir::ItemKind::Union(_, generics) => { - // FIXME: look for an appropriate lt name if `'a` is already used + let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics); let (lt_sp, sugg) = match &generics.params[..] { - [] => (generics.span, "<'a>".to_string()), - [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()), + [] => (generics.span, format!("<{}>", lt_name)), + [bound, ..] => { + (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) + } }; let suggestions = vec![ (lt_sp, sugg), @@ -387,7 +389,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { ty::EarlyBoundRegion { def_id: item_def_id, index: 0, - name: Symbol::intern("'a"), + name: Symbol::intern(<_name), }, )) }) @@ -445,6 +447,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } +/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. +fn get_new_lifetime_name<'tcx>( + tcx: TyCtxt<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + generics: &hir::Generics<'tcx>, +) -> String { + let existing_lifetimes = tcx + .collect_referenced_late_bound_regions(&poly_trait_ref) + .into_iter() + .filter_map(|lt| { + if let ty::BoundRegion::BrNamed(_, name) = lt { + Some(name.as_str().to_string()) + } else { + None + } + }) + .chain(generics.params.iter().filter_map(|param| { + if let hir::GenericParamKind::Lifetime { .. } = ¶m.kind { + Some(param.name.ident().as_str().to_string()) + } else { + None + } + })) + .collect::>(); + + let a_to_z_repeat_n = |n| { + (b'a'..=b'z').map(move |c| { + let mut s = format!("'"); + s.extend(std::iter::repeat(char::from(c)).take(n)); + s + }) + }; + + // If all single char lifetime names are present, we wrap around and double the chars. + (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap() +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( @@ -1588,7 +1627,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - use rustc_data_structures::fx::FxHashSet; use rustc_hir::*; debug!("explicit_predicates_of(def_id={:?})", def_id); diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 8a5777d4d7cb5..58f186d7775ea 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -12,11 +12,12 @@ struct SomeStruct Foo<&'x isize>> { //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } -enum SomeEnum Foo<&'x isize>> { +enum SomeEnum<'b, I: for<'a> Foo<&'a isize>> { TupleVariant(I::A), //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context StructVariant { field: I::A }, //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + OkVariant(&'b usize), } // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. @@ -26,7 +27,13 @@ enum SomeEnum Foo<&'x isize>> { // } struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { - field: >::A + field: >::A, +} + +struct Why<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, + 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { + field: I::A, + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index c71bc70ea6c4e..e3fd2860ebcf3 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -18,8 +18,8 @@ LL | TupleVariant(I::A), | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { -LL | TupleVariant(>::A), +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { +LL | TupleVariant(>::A), | error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context @@ -30,11 +30,24 @@ LL | StructVariant { field: I::A }, | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { LL | TupleVariant(I::A), LL | -LL | StructVariant { field: >::A }, +LL | StructVariant { field: >::A }, | -error: aborting due to 3 previous errors +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:35:12 + | +LL | field: I::A, + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | struct Why<'bb, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, +LL | 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { +LL | field: >::A, + | + +error: aborting due to 4 previous errors From e5b2c66dea8e2d721612089ebfa00e0799cd5e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 14 Feb 2020 17:49:16 -0800 Subject: [PATCH 12/12] Do not ICE when encountering `yield` inside `async` block --- src/librustc/hir/map/hir_id_validator.rs | 4 ++-- src/librustc/hir/map/mod.rs | 2 +- src/test/ui/generator/async-generator-issue-67158.rs | 6 ++++++ src/test/ui/generator/async-generator-issue-67158.stderr | 9 +++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/generator/async-generator-issue-67158.rs create mode 100644 src/test/ui/generator/async-generator-issue-67158.stderr diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index c721faafbecaf..a4f9193c0eb64 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -7,7 +7,7 @@ use rustc_hir::intravisit; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{HirId, ItemLocalId}; -pub fn check_crate(hir_map: &Map<'_>) { +pub fn check_crate(hir_map: &Map<'_>, sess: &rustc_session::Session) { hir_map.dep_graph.assert_ignored(); let errors = Lock::new(Vec::new()); @@ -24,7 +24,7 @@ pub fn check_crate(hir_map: &Map<'_>) { if !errors.is_empty() { let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2); - bug!("{}", message); + sess.delay_span_bug(rustc_span::DUMMY_SP, &message); } } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 1645420892a75..adda0cde24fc0 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1235,7 +1235,7 @@ pub fn map_crate<'hir>( let map = Map { krate, dep_graph, crate_hash, map, hir_to_node_id, definitions }; sess.time("validate_HIR_map", || { - hir_id_validator::check_crate(&map); + hir_id_validator::check_crate(&map, sess); }); map diff --git a/src/test/ui/generator/async-generator-issue-67158.rs b/src/test/ui/generator/async-generator-issue-67158.rs new file mode 100644 index 0000000000000..8125a7a9bb664 --- /dev/null +++ b/src/test/ui/generator/async-generator-issue-67158.rs @@ -0,0 +1,6 @@ +#![feature(generators)] +// edition:2018 +// Regression test for #67158. +fn main() { + async { yield print!(":C") }; //~ ERROR `async` generators are not yet supported +} diff --git a/src/test/ui/generator/async-generator-issue-67158.stderr b/src/test/ui/generator/async-generator-issue-67158.stderr new file mode 100644 index 0000000000000..7270d188e8b88 --- /dev/null +++ b/src/test/ui/generator/async-generator-issue-67158.stderr @@ -0,0 +1,9 @@ +error[E0727]: `async` generators are not yet supported + --> $DIR/async-generator-issue-67158.rs:5:13 + | +LL | async { yield print!(":C") }; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0727`.