From 756be4a052cf43d5dec2b7ee99e611d2127d989e Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 03:14:05 +0300 Subject: [PATCH 01/26] refactored StyledBuffer parts into StyledChar --- compiler/rustc_errors/src/styled_buffer.rs | 47 ++++++++++++---------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index ec122e7be6e8e..89b8afdc7ab55 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -1,39 +1,49 @@ // Code for creating styled buffers use crate::snippet::{Style, StyledString}; -use std::iter; #[derive(Debug)] pub struct StyledBuffer { - text: Vec>, - styles: Vec>, + text: Vec>, +} + +#[derive(Debug)] +struct StyledChar { + chr: char, + style: Style, +} + +impl StyledChar { + fn new(chr: char, style: Style) -> Self { + StyledChar { chr, style } + } } impl StyledBuffer { pub fn new() -> StyledBuffer { - StyledBuffer { text: vec![], styles: vec![] } + StyledBuffer { text: vec![] } } pub fn render(&self) -> Vec> { // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(self.text.iter().all(|r| !r.contains(&'\t'))); + debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t'))); let mut output: Vec> = vec![]; let mut styled_vec: Vec = vec![]; - for (row, row_style) in iter::zip(&self.text, &self.styles) { + for styled_row in &self.text { let mut current_style = Style::NoStyle; let mut current_text = String::new(); - for (&c, &s) in iter::zip(row, row_style) { - if s != current_style { + for sc in styled_row { + if sc.style != current_style { if !current_text.is_empty() { styled_vec.push(StyledString { text: current_text, style: current_style }); } - current_style = s; + current_style = sc.style; current_text = String::new(); } - current_text.push(c); + current_text.push(sc.chr); } if !current_text.is_empty() { styled_vec.push(StyledString { text: current_text, style: current_style }); @@ -51,24 +61,20 @@ impl StyledBuffer { fn ensure_lines(&mut self, line: usize) { while line >= self.text.len() { self.text.push(vec![]); - self.styles.push(vec![]); } } pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { self.ensure_lines(line); if col < self.text[line].len() { - self.text[line][col] = chr; - self.styles[line][col] = style; + self.text[line][col] = StyledChar::new(chr, style); } else { let mut i = self.text[line].len(); while i < col { - self.text[line].push(' '); - self.styles[line].push(Style::NoStyle); + self.text[line].push(StyledChar::new(' ', Style::NoStyle)); i += 1; } - self.text[line].push(chr); - self.styles[line].push(style); + self.text[line].push(StyledChar::new(chr, style)); } } @@ -86,8 +92,7 @@ impl StyledBuffer { // Push the old content over to make room for new content for _ in 0..string_len { - self.styles[line].insert(0, Style::NoStyle); - self.text[line].insert(0, ' '); + self.text[line].insert(0, StyledChar::new(' ', Style::NoStyle)); } self.puts(line, 0, string, style); @@ -120,8 +125,8 @@ impl StyledBuffer { } pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { - if let Some(ref mut line) = self.styles.get_mut(line) { - if let Some(s) = line.get_mut(col) { + if let Some(ref mut line) = self.text.get_mut(line) { + if let Some(StyledChar { style: s, .. }) = line.get_mut(col) { if *s == Style::NoStyle || *s == Style::Quotation || overwrite { *s = style; } From f5229916e350e5b70a6db4f3378f63993eaecb3d Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 03:20:07 +0300 Subject: [PATCH 02/26] added default for StyledChar --- compiler/rustc_errors/src/styled_buffer.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 89b8afdc7ab55..8ce9c4bbfa1b6 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -19,6 +19,12 @@ impl StyledChar { } } +impl Default for StyledChar { + fn default() -> Self { + StyledChar::new(' ', Style::NoStyle) + } +} + impl StyledBuffer { pub fn new() -> StyledBuffer { StyledBuffer { text: vec![] } @@ -71,7 +77,7 @@ impl StyledBuffer { } else { let mut i = self.text[line].len(); while i < col { - self.text[line].push(StyledChar::new(' ', Style::NoStyle)); + self.text[line].push(StyledChar::default()); i += 1; } self.text[line].push(StyledChar::new(chr, style)); @@ -92,7 +98,7 @@ impl StyledBuffer { // Push the old content over to make room for new content for _ in 0..string_len { - self.text[line].insert(0, StyledChar::new(' ', Style::NoStyle)); + self.text[line].insert(0, StyledChar::default()); } self.puts(line, 0, string, style); From e97ddedac644fb192c25490f6f6eab711bc1bea8 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 04:14:59 +0300 Subject: [PATCH 03/26] added some docs for StyledBuffer --- compiler/rustc_errors/src/styled_buffer.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 8ce9c4bbfa1b6..a89d0aeaffd84 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -30,6 +30,7 @@ impl StyledBuffer { StyledBuffer { text: vec![] } } + /// Returns content of `StyledBuffer` splitted by lines and line styles pub fn render(&self) -> Vec> { // Tabs are assumed to have been replaced by spaces in calling code. debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t'))); @@ -70,6 +71,9 @@ impl StyledBuffer { } } + /// Sets `chr` with `style` for given `line`, `col`. + /// If line not exist in `StyledBuffer`, adds lines up to given + /// and fills last line with spaces and `Style::NoStyle` style pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { self.ensure_lines(line); if col < self.text[line].len() { @@ -84,6 +88,9 @@ impl StyledBuffer { } } + /// Sets `string` with `style` for given `line`, starting from `col`. + /// If line not exist in `StyledBuffer`, adds lines up to given + /// and fills last line with spaces and `Style::NoStyle` style pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) { let mut n = col; for c in string.chars() { @@ -92,6 +99,8 @@ impl StyledBuffer { } } + /// For given `line` inserts `string` with `style` before old content of that line, + /// adding lines if needed pub fn prepend(&mut self, line: usize, string: &str, style: Style) { self.ensure_lines(line); let string_len = string.chars().count(); @@ -104,6 +113,8 @@ impl StyledBuffer { self.puts(line, 0, string, style); } + /// For given `line` inserts `string` with `style` after old content of that line, + /// adding lines if needed pub fn append(&mut self, line: usize, string: &str, style: Style) { if line >= self.text.len() { self.puts(line, 0, string, style); @@ -117,6 +128,9 @@ impl StyledBuffer { self.text.len() } + /// Set `style` for `line`, `col_start..col_end` range if: + /// 1. That line and column range exist in `StyledBuffer` + /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation` pub fn set_style_range( &mut self, line: usize, @@ -130,6 +144,9 @@ impl StyledBuffer { } } + /// Set `style` for `line`, `col` if: + /// 1. That line and column exist in `StyledBuffer` + /// 2. Existing style is `Style::NoStyle` or `Style::Quotation` or `overwrite` is `true` pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { if let Some(ref mut line) = self.text.get_mut(line) { if let Some(StyledChar { style: s, .. }) = line.get_mut(col) { From 7e9d3c6f6cf3956dbf2a7870cebe89ebeb5d9ea5 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 05:11:45 +0300 Subject: [PATCH 04/26] StyledBuffer::prepend: if line is empty, insert content without inserting spaces --- compiler/rustc_errors/src/styled_buffer.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index a89d0aeaffd84..9c19c96d64f9a 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -105,9 +105,11 @@ impl StyledBuffer { self.ensure_lines(line); let string_len = string.chars().count(); - // Push the old content over to make room for new content - for _ in 0..string_len { - self.text[line].insert(0, StyledChar::default()); + if !self.text[line].is_empty() { + // Push the old content over to make room for new content + for _ in 0..string_len { + self.text[line].insert(0, StyledChar::default()); + } } self.puts(line, 0, string, style); From 247d74f207633a5aeceb1e0ede878427465c5093 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 05:23:40 +0300 Subject: [PATCH 05/26] StyledBuffer::set_style: check overwrite first --- compiler/rustc_errors/src/styled_buffer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 9c19c96d64f9a..01d2a8de39d50 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -148,11 +148,11 @@ impl StyledBuffer { /// Set `style` for `line`, `col` if: /// 1. That line and column exist in `StyledBuffer` - /// 2. Existing style is `Style::NoStyle` or `Style::Quotation` or `overwrite` is `true` + /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation` pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { if let Some(ref mut line) = self.text.get_mut(line) { if let Some(StyledChar { style: s, .. }) = line.get_mut(col) { - if *s == Style::NoStyle || *s == Style::Quotation || overwrite { + if overwrite || *s == Style::NoStyle || *s == Style::Quotation { *s = style; } } From cb2d52282fb3c226c370a86c9111892384bbcb21 Mon Sep 17 00:00:00 2001 From: klensy Date: Fri, 16 Apr 2021 05:38:32 +0300 Subject: [PATCH 06/26] rename StyledBuffer.text to lines --- compiler/rustc_errors/src/styled_buffer.rs | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 01d2a8de39d50..fb9575b290a0d 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -4,7 +4,7 @@ use crate::snippet::{Style, StyledString}; #[derive(Debug)] pub struct StyledBuffer { - text: Vec>, + lines: Vec>, } #[derive(Debug)] @@ -27,22 +27,22 @@ impl Default for StyledChar { impl StyledBuffer { pub fn new() -> StyledBuffer { - StyledBuffer { text: vec![] } + StyledBuffer { lines: vec![] } } /// Returns content of `StyledBuffer` splitted by lines and line styles pub fn render(&self) -> Vec> { // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t'))); + debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t'))); let mut output: Vec> = vec![]; let mut styled_vec: Vec = vec![]; - for styled_row in &self.text { + for styled_line in &self.lines { let mut current_style = Style::NoStyle; let mut current_text = String::new(); - for sc in styled_row { + for sc in styled_line { if sc.style != current_style { if !current_text.is_empty() { styled_vec.push(StyledString { text: current_text, style: current_style }); @@ -66,8 +66,8 @@ impl StyledBuffer { } fn ensure_lines(&mut self, line: usize) { - while line >= self.text.len() { - self.text.push(vec![]); + while line >= self.lines.len() { + self.lines.push(vec![]); } } @@ -76,15 +76,15 @@ impl StyledBuffer { /// and fills last line with spaces and `Style::NoStyle` style pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { self.ensure_lines(line); - if col < self.text[line].len() { - self.text[line][col] = StyledChar::new(chr, style); + if col < self.lines[line].len() { + self.lines[line][col] = StyledChar::new(chr, style); } else { - let mut i = self.text[line].len(); + let mut i = self.lines[line].len(); while i < col { - self.text[line].push(StyledChar::default()); + self.lines[line].push(StyledChar::default()); i += 1; } - self.text[line].push(StyledChar::new(chr, style)); + self.lines[line].push(StyledChar::new(chr, style)); } } @@ -105,10 +105,10 @@ impl StyledBuffer { self.ensure_lines(line); let string_len = string.chars().count(); - if !self.text[line].is_empty() { + if !self.lines[line].is_empty() { // Push the old content over to make room for new content for _ in 0..string_len { - self.text[line].insert(0, StyledChar::default()); + self.lines[line].insert(0, StyledChar::default()); } } @@ -118,16 +118,16 @@ impl StyledBuffer { /// For given `line` inserts `string` with `style` after old content of that line, /// adding lines if needed pub fn append(&mut self, line: usize, string: &str, style: Style) { - if line >= self.text.len() { + if line >= self.lines.len() { self.puts(line, 0, string, style); } else { - let col = self.text[line].len(); + let col = self.lines[line].len(); self.puts(line, col, string, style); } } pub fn num_lines(&self) -> usize { - self.text.len() + self.lines.len() } /// Set `style` for `line`, `col_start..col_end` range if: @@ -150,7 +150,7 @@ impl StyledBuffer { /// 1. That line and column exist in `StyledBuffer` /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation` pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { - if let Some(ref mut line) = self.text.get_mut(line) { + if let Some(ref mut line) = self.lines.get_mut(line) { if let Some(StyledChar { style: s, .. }) = line.get_mut(col) { if overwrite || *s == Style::NoStyle || *s == Style::Quotation { *s = style; From e4ce655cbf11dded14af67a9d8201207c6d18c1f Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 23 Apr 2021 13:29:18 -0400 Subject: [PATCH 07/26] Handle pretty printing of `else if let` clauses Closes #84434. Closes #82329. --- compiler/rustc_hir_pretty/src/lib.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5820e7a261230..77d083fc5e967 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1095,8 +1095,8 @@ impl<'a> State<'a> { fn print_else(&mut self, els: Option<&hir::Expr<'_>>) { match els { - Some(_else) => { - match _else.kind { + Some(else_) => { + match else_.kind { // "another else-if" hir::ExprKind::If(ref i, ref then, ref e) => { self.cbox(INDENT_UNIT - 1); @@ -1114,6 +1114,26 @@ impl<'a> State<'a> { self.s.word(" else "); self.print_block(&b) } + hir::ExprKind::Match(ref expr, arms, _) => { + // else if let desugared to match + assert!(arms.len() == 2, "if let desugars to match with two arms"); + + self.s.word(" else "); + self.s.word("{"); + + self.cbox(INDENT_UNIT); + self.ibox(INDENT_UNIT); + self.word_nbsp("match"); + self.print_expr_as_cond(&expr); + self.s.space(); + self.bopen(); + for arm in arms { + self.print_arm(arm); + } + self.bclose(expr.span); + + self.s.word("}"); + } // BLEAH, constraints would be great here _ => { panic!("print_if saw if with weird alternative"); From fc97ce6daed320027a47c1a0ddb86c9242ebde0c Mon Sep 17 00:00:00 2001 From: Smitty Date: Fri, 23 Apr 2021 14:06:02 -0400 Subject: [PATCH 08/26] add tests for new behavior --- src/test/ui/match/issue-82392.rs | 9 +++++++++ src/test/ui/match/issue-82392.stdout | 20 ++++++++++++++++++++ src/test/ui/match/issue-84434.rs | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/test/ui/match/issue-82392.rs create mode 100644 src/test/ui/match/issue-82392.stdout create mode 100644 src/test/ui/match/issue-84434.rs diff --git a/src/test/ui/match/issue-82392.rs b/src/test/ui/match/issue-82392.rs new file mode 100644 index 0000000000000..d26d883040b48 --- /dev/null +++ b/src/test/ui/match/issue-82392.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/82329 +// compile-flags: -Zunpretty=hir,typed +// check-pass + +pub fn main() { + if true { + } else if let Some(a) = Some(3) { + } +} diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout new file mode 100644 index 0000000000000..8ff76c64fc789 --- /dev/null +++ b/src/test/ui/match/issue-82392.stdout @@ -0,0 +1,20 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// https://github.com/rust-lang/rust/issues/82329 +// compile-flags: -Zunpretty=hir,typed +// check-pass + +pub fn main() ({ + (if (true as bool) + ({ } as + ()) else {match ((Some as + fn(i32) -> Option {Option::::Some})((3 + as + i32)) + as Option) { + Some(a) => { } + _ => { } + }} as ()) + } as ()) diff --git a/src/test/ui/match/issue-84434.rs b/src/test/ui/match/issue-84434.rs new file mode 100644 index 0000000000000..423481fd5f02d --- /dev/null +++ b/src/test/ui/match/issue-84434.rs @@ -0,0 +1,18 @@ +// https://github.com/rust-lang/rust/issues/84434 +// check-pass + +use std::path::Path; +struct A { + pub func: fn(check: bool, a: &Path, b: Option<&Path>), +} +const MY_A: A = A { + func: |check, a, b| { + if check { + let _ = (); + } else if let Some(parent) = b.and_then(|p| p.parent()) { + let _ = (); + } + }, +}; + +fn main() {} From 862901781d5980e7cd1865b6cd6d77760f4016ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Apr 2021 18:08:51 -0700 Subject: [PATCH 09/26] Add regression test --- .../import-trait-for-method-call.rs | 9 +++++++ .../import-trait-for-method-call.stderr | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/ui/suggestions/import-trait-for-method-call.rs create mode 100644 src/test/ui/suggestions/import-trait-for-method-call.stderr diff --git a/src/test/ui/suggestions/import-trait-for-method-call.rs b/src/test/ui/suggestions/import-trait-for-method-call.rs new file mode 100644 index 0000000000000..646f68dea14e8 --- /dev/null +++ b/src/test/ui/suggestions/import-trait-for-method-call.rs @@ -0,0 +1,9 @@ +use std::hash::BuildHasher; + +fn next_u64() -> u64 { + let bh = std::collections::hash_map::RandomState::new(); + let h = bh.build_hasher(); + h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher` +} + +fn main() {} diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr new file mode 100644 index 0000000000000..8b72e8c922cfe --- /dev/null +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -0,0 +1,26 @@ +error[E0599]: no method named `finish` found for struct `DefaultHasher` in the current scope + --> $DIR/import-trait-for-method-call.rs:6:7 + | +LL | h.finish() + | ^^^^^^ method not found in `DefaultHasher` + | + ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL + | +LL | fn finish(&self) -> u64; + | ------ + | | + | the method is available for `Box` here + | the method is available for `Box<&mut DefaultHasher>` here + | +help: consider wrapping the receiver expression with the appropriate type + | +LL | Box::new(h).finish() + | ^^^^^^^^^ ^ +help: consider wrapping the receiver expression with the appropriate type + | +LL | Box::new(&mut h).finish() + | ^^^^^^^^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From 64ee9cc28ceda652ac06b7d6bf68d1b7f408cf23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Apr 2021 18:12:54 -0700 Subject: [PATCH 10/26] Recover trait import suggestion --- compiler/rustc_typeck/src/check/method/suggest.rs | 2 +- src/test/ui/suggestions/import-trait-for-method-call.stderr | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 02fe8312c4c1f..47e4e1223ff18 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1047,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if !alt_rcvr_sugg && self.suggest_valid_traits(err, valid_out_of_scope_traits) { + if self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; } diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index 8b72e8c922cfe..b6fc09cc5d0ad 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -12,6 +12,7 @@ LL | fn finish(&self) -> u64; | the method is available for `Box` here | the method is available for `Box<&mut DefaultHasher>` here | + = help: items from traits can only be used if the trait is in scope help: consider wrapping the receiver expression with the appropriate type | LL | Box::new(h).finish() @@ -20,6 +21,10 @@ help: consider wrapping the receiver expression with the appropriate type | LL | Box::new(&mut h).finish() | ^^^^^^^^^^^^^ ^ +help: the following trait is implemented but not in scope; perhaps add a `use` for it: + | +LL | use std::hash::Hasher; + | error: aborting due to previous error From fb1fb7d2ef45760bfe133381286dc750fe51e49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Apr 2021 18:24:02 -0700 Subject: [PATCH 11/26] Tweak suggestion output --- .../rustc_typeck/src/check/method/suggest.rs | 35 +++++++++++++++---- src/test/ui/hygiene/trait_items.stderr | 3 ++ .../no-method-suggested-traits.stderr | 8 +++++ src/test/ui/issues/issue-43189.stderr | 5 +++ src/test/ui/issues/issue-56175.stderr | 10 ++++++ .../rust-2018/trait-import-suggestions.stderr | 6 ++++ .../ui/shadowed/shadowed-trait-methods.stderr | 3 ++ .../import-trait-for-method-call.stderr | 13 +------ src/test/ui/traits/item-privacy.stderr | 3 ++ 9 files changed, 67 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 47e4e1223ff18..73e35f0171aa7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -988,6 +988,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut alt_rcvr_sugg = false; if let SelfSource::MethodCall(rcvr) = source { debug!(?span, ?item_name, ?rcvr_ty, ?rcvr); + let skippable = [ + self.tcx.lang_items().clone_trait(), + self.tcx.lang_items().deref_trait(), + self.tcx.lang_items().deref_mut_trait(), + self.tcx.lang_items().drop_trait(), + ]; // Try alternative arbitrary self types that could fulfill this call. // FIXME: probe for all types that *could* be arbitrary self-types, not // just this list. @@ -996,6 +1002,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "), (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"), ] { + if let Ok(pick) = self.lookup_probe( + span, + item_name, + rcvr_ty, + rcvr, + crate::check::method::probe::ProbeScope::AllTraits, + ) { + // If the method is defined for the receiver we have, it likely wasn't `use`d. + // We point at the method, but we just skip the rest of the check for arbitrary + // self types and rely on the suggestion to `use` the trait from + // `suggest_valid_traits`. + let did = Some(pick.item.container.id()); + let skip = skippable.contains(&did); + if pick.autoderefs == 0 && !skip { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", rcvr_ty), + ); + } + break; + } for (rcvr_ty, pre) in &[ (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"), (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"), @@ -1015,13 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We don't want to suggest a container type when the missing // method is `.clone()` or `.deref()` otherwise we'd suggest // `Arc::new(foo).clone()`, which is far from what the user wants. - let skip = [ - self.tcx.lang_items().clone_trait(), - self.tcx.lang_items().deref_trait(), - self.tcx.lang_items().deref_mut_trait(), - self.tcx.lang_items().drop_trait(), - ] - .contains(&did); + let skip = skippable.contains(&did); // Make sure the method is defined for the *actual* receiver: we don't // want to treat `Box` as a receiver if it only works because of // an autoderef to `&self` diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr index d24336883e963..2913a955dce1b 100644 --- a/src/test/ui/hygiene/trait_items.stderr +++ b/src/test/ui/hygiene/trait_items.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `f` found for unit type `()` in the current scope --> $DIR/trait_items.rs:17:24 | +LL | fn f(&self) {} + | - the method is available for `()` here +... LL | fn f() { ::baz::m!(); } | ------------ in this macro invocation ... diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index 64ddcb81c0a9b..b993115502fd5 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -37,6 +37,9 @@ LL | use no_method_suggested_traits::Reexported; error[E0599]: no method named `method` found for type `char` in the current scope --> $DIR/no-method-suggested-traits.rs:30:9 | +LL | fn method(&self) {} + | ------ the method is available for `char` here +... LL | 'a'.method(); | ^^^^^^ method not found in `char` | @@ -63,6 +66,11 @@ error[E0599]: no method named `method` found for type `i32` in the current scope | LL | 1i32.method(); | ^^^^^^ method not found in `i32` + | + ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 + | +LL | fn method(&self) {} + | ------ the method is available for `i32` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-43189.stderr b/src/test/ui/issues/issue-43189.stderr index 3f63cb8e78fba..3a3767c349d65 100644 --- a/src/test/ui/issues/issue-43189.stderr +++ b/src/test/ui/issues/issue-43189.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `a` found for unit type `()` in the current scope | LL | ().a(); | ^ method not found in `()` + | + ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8 + | +LL | fn a(&self) {} + | - the method is available for `()` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-56175.stderr b/src/test/ui/issues/issue-56175.stderr index ee3f609f47dca..e6b0fffce663d 100644 --- a/src/test/ui/issues/issue-56175.stderr +++ b/src/test/ui/issues/issue-56175.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `trait_method` found for struct `FooStruct` in the | LL | reexported_trait::FooStruct.trait_method(); | ^^^^^^^^^^^^ method not found in `FooStruct` + | + ::: $DIR/auxiliary/reexported-trait.rs:3:12 + | +LL | fn trait_method(&self) { + | ------------ the method is available for `FooStruct` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -15,6 +20,11 @@ error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in t | LL | reexported_trait::FooStruct.trait_method_b(); | ^^^^^^^^^^^^^^ method not found in `FooStruct` + | + ::: $DIR/auxiliary/reexported-trait.rs:7:12 + | +LL | fn trait_method_b(&self) { + | -------------- the method is available for `FooStruct` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/rust-2018/trait-import-suggestions.stderr b/src/test/ui/rust-2018/trait-import-suggestions.stderr index 4b1898345a32e..2cf5a073fe5c2 100644 --- a/src/test/ui/rust-2018/trait-import-suggestions.stderr +++ b/src/test/ui/rust-2018/trait-import-suggestions.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `foobar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:22:11 | +LL | fn foobar(&self) { } + | ------ the method is available for `u32` here +... LL | x.foobar(); | ^^^^^^ method not found in `u32` | @@ -11,6 +14,9 @@ LL | x.foobar(); error[E0599]: no method named `bar` found for type `u32` in the current scope --> $DIR/trait-import-suggestions.rs:28:7 | +LL | fn bar(&self) { } + | --- the method is available for `u32` here +... LL | x.bar(); | ^^^ method not found in `u32` | diff --git a/src/test/ui/shadowed/shadowed-trait-methods.stderr b/src/test/ui/shadowed/shadowed-trait-methods.stderr index 362907ecbd7ef..c3b9084affdb3 100644 --- a/src/test/ui/shadowed/shadowed-trait-methods.stderr +++ b/src/test/ui/shadowed/shadowed-trait-methods.stderr @@ -1,6 +1,9 @@ error[E0599]: no method named `f` found for unit type `()` in the current scope --> $DIR/shadowed-trait-methods.rs:13:8 | +LL | pub trait T { fn f(&self) {} } + | - the method is available for `()` here +... LL | ().f() | ^ method not found in `()` | diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index b6fc09cc5d0ad..f3ae20552f3d5 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -7,20 +7,9 @@ LL | h.finish() ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | LL | fn finish(&self) -> u64; - | ------ - | | - | the method is available for `Box` here - | the method is available for `Box<&mut DefaultHasher>` here + | ------ the method is available for `DefaultHasher` here | = help: items from traits can only be used if the trait is in scope -help: consider wrapping the receiver expression with the appropriate type - | -LL | Box::new(h).finish() - | ^^^^^^^^^ ^ -help: consider wrapping the receiver expression with the appropriate type - | -LL | Box::new(&mut h).finish() - | ^^^^^^^^^^^^^ ^ help: the following trait is implemented but not in scope; perhaps add a `use` for it: | LL | use std::hash::Hasher; diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr index 68d527dc786aa..30daf8e277024 100644 --- a/src/test/ui/traits/item-privacy.stderr +++ b/src/test/ui/traits/item-privacy.stderr @@ -20,6 +20,9 @@ error[E0599]: no method named `b` found for struct `S` in the current scope LL | struct S; | --------- method `b` not found for this ... +LL | fn b(&self) { } + | - the method is available for `S` here +... LL | S.b(); | ^ method not found in `S` | From ad78b50a86c6ac908df1c385642d46d3183740d6 Mon Sep 17 00:00:00 2001 From: Tor Hovland Date: Sat, 24 Apr 2021 13:57:41 +0200 Subject: [PATCH 12/26] Implemented suggestion. --- compiler/rustc_typeck/src/check/coercion.rs | 4 +- .../src/check/fn_ctxt/suggestions.rs | 78 ++++++++++++++++++- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 427f967a9b6bd..236fec94bdba7 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1494,7 +1494,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let (Some((expr, _)), Some((fn_decl, _, _))) = (expression, fcx.get_node_fn_decl(parent_item)) { - fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found, parent_id); + fcx.suggest_missing_break_or_return_expr( + &mut err, expr, fn_decl, expected, found, id, parent_id, + ); } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index b758334484535..c3417247725fe 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -8,7 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, ItemKind, Node}; +use rustc_hir::{ExprKind, ItemKind, Node, StmtKind}; use rustc_infer::infer; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty}; @@ -55,7 +55,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pointing_at_return_type = self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap(); - self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found, fn_id); + self.suggest_missing_break_or_return_expr( + err, expr, &fn_decl, expected, found, blk_id, fn_id, + ); } pointing_at_return_type } @@ -472,7 +474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn suggest_missing_return_expr( + pub(in super::super) fn suggest_missing_break_or_return_expr( &self, err: &mut DiagnosticBuilder<'_>, expr: &'tcx hir::Expr<'tcx>, @@ -480,14 +482,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, id: hir::HirId, + fn_id: hir::HirId, ) { if !expected.is_unit() { return; } let found = self.resolve_vars_with_obligations(found); + + if self.in_loop(id) { + if self.in_local_statement(id) { + err.multipart_suggestion( + "you might have meant to break the loop with this value", + vec![ + (expr.span.shrink_to_lo(), "break ".to_string()), + (expr.span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return; + } + } + if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = >::ast_ty_to_ty(self, ty); - let bound_vars = self.tcx.late_bound_vars(id); + let bound_vars = self.tcx.late_bound_vars(fn_id); let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = self.normalize_associated_types_in(expr.span, ty); if self.can_coerce(found, ty) { @@ -514,4 +532,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); } } + + fn in_loop(&self, id: hir::HirId) -> bool { + if self.is_loop(id) { + return true; + } + + for (parent_id, _) in self.tcx.hir().parent_iter(id) { + if self.is_loop(parent_id) { + return true; + } + } + + false + } + + fn is_loop(&self, id: hir::HirId) -> bool { + let node = self.tcx.hir().get(id); + + if let Node::Expr(expr) = node { + if let ExprKind::Loop(..) = expr.kind { + return true; + } + } + + false + } + + fn in_local_statement(&self, id: hir::HirId) -> bool { + if self.is_local_statement(id) { + return true; + } + + for (parent_id, _) in self.tcx.hir().parent_iter(id) { + if self.is_local_statement(parent_id) { + return true; + } + } + + false + } + + fn is_local_statement(&self, id: hir::HirId) -> bool { + let node = self.tcx.hir().get(id); + + if let Node::Stmt(stmt) = node { + if let StmtKind::Local(..) = stmt.kind { + return true; + } + } + + false + } } From 0e7489a2e9443069d5a7063f0b47d9923921f57f Mon Sep 17 00:00:00 2001 From: Tor Hovland Date: Sat, 24 Apr 2021 18:08:22 +0200 Subject: [PATCH 13/26] Added a test. --- src/test/ui/loops/loop-no-implicit-break.rs | 5 +++++ src/test/ui/loops/loop-no-implicit-break.stderr | 14 ++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/test/ui/loops/loop-no-implicit-break.rs create mode 100644 src/test/ui/loops/loop-no-implicit-break.stderr diff --git a/src/test/ui/loops/loop-no-implicit-break.rs b/src/test/ui/loops/loop-no-implicit-break.rs new file mode 100644 index 0000000000000..0c57baf14394b --- /dev/null +++ b/src/test/ui/loops/loop-no-implicit-break.rs @@ -0,0 +1,5 @@ +fn main() { + let x: i8 = loop { + 10 //~ ERROR mismatched types + }; +} diff --git a/src/test/ui/loops/loop-no-implicit-break.stderr b/src/test/ui/loops/loop-no-implicit-break.stderr new file mode 100644 index 0000000000000..99767b78d35e3 --- /dev/null +++ b/src/test/ui/loops/loop-no-implicit-break.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/loop-no-implicit-break.rs:3:9 + | +LL | 10 + | ^^ expected `()`, found integer + | +help: you might have meant to break the loop with this value + | +LL | break 10; + | ^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 8bc81a0e4d9d5edc72af0cffe31a78a0bd2156f2 Mon Sep 17 00:00:00 2001 From: Tor Hovland Date: Sat, 24 Apr 2021 18:49:21 +0200 Subject: [PATCH 14/26] Refactor. --- .../src/check/fn_ctxt/suggestions.rs | 80 ++++++------------- 1 file changed, 23 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index c3417247725fe..d6b1e56316b37 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -8,7 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, ItemKind, Node, StmtKind}; +use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind}; use rustc_infer::infer; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty}; @@ -489,18 +489,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let found = self.resolve_vars_with_obligations(found); - if self.in_loop(id) { - if self.in_local_statement(id) { - err.multipart_suggestion( - "you might have meant to break the loop with this value", - vec![ - (expr.span.shrink_to_lo(), "break ".to_string()), - (expr.span.shrink_to_hi(), ";".to_string()), - ], - Applicability::MaybeIncorrect, - ); - return; - } + let in_loop = self.is_loop(id) + || self.tcx.hir().parent_iter(id).any(|(parent_id, _)| self.is_loop(parent_id)); + + let in_local_statement = self.is_local_statement(id) + || self + .tcx + .hir() + .parent_iter(id) + .any(|(parent_id, _)| self.is_local_statement(parent_id)); + + if in_loop && in_local_statement { + err.multipart_suggestion( + "you might have meant to break the loop with this value", + vec![ + (expr.span.shrink_to_lo(), "break ".to_string()), + (expr.span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return; } if let hir::FnRetTy::Return(ty) = fn_decl.output { @@ -533,55 +541,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn in_loop(&self, id: hir::HirId) -> bool { - if self.is_loop(id) { - return true; - } - - for (parent_id, _) in self.tcx.hir().parent_iter(id) { - if self.is_loop(parent_id) { - return true; - } - } - - false - } - fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); - - if let Node::Expr(expr) = node { - if let ExprKind::Loop(..) = expr.kind { - return true; - } - } - - false - } - - fn in_local_statement(&self, id: hir::HirId) -> bool { - if self.is_local_statement(id) { - return true; - } - - for (parent_id, _) in self.tcx.hir().parent_iter(id) { - if self.is_local_statement(parent_id) { - return true; - } - } - - false + matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) } fn is_local_statement(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); - - if let Node::Stmt(stmt) = node { - if let StmtKind::Local(..) = stmt.kind { - return true; - } - } - - false + matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. })) } } From 05a5a1128fc5da178f9b7bd0ab499258652dfc49 Mon Sep 17 00:00:00 2001 From: Tor Hovland Date: Sat, 24 Apr 2021 19:00:24 +0200 Subject: [PATCH 15/26] More tests. --- src/test/ui/loops/loop-no-implicit-break.rs | 26 +++++++++++++-- .../ui/loops/loop-no-implicit-break.stderr | 32 ++++++++++++++++--- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/test/ui/loops/loop-no-implicit-break.rs b/src/test/ui/loops/loop-no-implicit-break.rs index 0c57baf14394b..fc3b3c4a30fac 100644 --- a/src/test/ui/loops/loop-no-implicit-break.rs +++ b/src/test/ui/loops/loop-no-implicit-break.rs @@ -1,5 +1,27 @@ fn main() { - let x: i8 = loop { - 10 //~ ERROR mismatched types + let a: i8 = loop { + 1 //~ ERROR mismatched types }; + + let b: i8 = loop { + break 1; + }; +} + +fn foo() -> i8 { + let a: i8 = loop { + 1 //~ ERROR mismatched types + }; + + let b: i8 = loop { + break 1; + }; + + loop { + 1 //~ ERROR mismatched types + } + + loop { + return 1; + } } diff --git a/src/test/ui/loops/loop-no-implicit-break.stderr b/src/test/ui/loops/loop-no-implicit-break.stderr index 99767b78d35e3..cde6bbe512b28 100644 --- a/src/test/ui/loops/loop-no-implicit-break.stderr +++ b/src/test/ui/loops/loop-no-implicit-break.stderr @@ -1,14 +1,36 @@ error[E0308]: mismatched types --> $DIR/loop-no-implicit-break.rs:3:9 | -LL | 10 - | ^^ expected `()`, found integer +LL | 1 + | ^ expected `()`, found integer | help: you might have meant to break the loop with this value | -LL | break 10; - | ^^^^^ ^ +LL | break 1; + | ^^^^^ ^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/loop-no-implicit-break.rs:13:9 + | +LL | 1 + | ^ expected `()`, found integer + | +help: you might have meant to break the loop with this value + | +LL | break 1; + | ^^^^^ ^ + +error[E0308]: mismatched types + --> $DIR/loop-no-implicit-break.rs:21:9 + | +LL | 1 + | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | return 1; + | ^^^^^^ ^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From 8ebd811b32de96c0e9e4208703465016da3d8764 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 18 Apr 2021 02:15:15 +0300 Subject: [PATCH 16/26] review --- compiler/rustc_errors/src/styled_buffer.rs | 38 ++++++++-------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index fb9575b290a0d..e262d95bb70f2 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -7,21 +7,17 @@ pub struct StyledBuffer { lines: Vec>, } -#[derive(Debug)] +#[derive(Debug, Clone)] struct StyledChar { chr: char, style: Style, } impl StyledChar { - fn new(chr: char, style: Style) -> Self { - StyledChar { chr, style } - } -} + const SPACE: Self = StyledChar::new(' ', Style::NoStyle); -impl Default for StyledChar { - fn default() -> Self { - StyledChar::new(' ', Style::NoStyle) + const fn new(chr: char, style: Style) -> Self { + StyledChar { chr, style } } } @@ -66,31 +62,25 @@ impl StyledBuffer { } fn ensure_lines(&mut self, line: usize) { - while line >= self.lines.len() { - self.lines.push(vec![]); + if line >= self.lines.len() { + self.lines.resize(line + 1, Vec::new()); } } /// Sets `chr` with `style` for given `line`, `col`. - /// If line not exist in `StyledBuffer`, adds lines up to given - /// and fills last line with spaces and `Style::NoStyle` style + /// If `line` does not exist in our buffer, adds empty lines up to the given + /// and fills the last line with unstyled whitespace. pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { self.ensure_lines(line); - if col < self.lines[line].len() { - self.lines[line][col] = StyledChar::new(chr, style); - } else { - let mut i = self.lines[line].len(); - while i < col { - self.lines[line].push(StyledChar::default()); - i += 1; - } - self.lines[line].push(StyledChar::new(chr, style)); + if col >= self.lines[line].len() { + self.lines[line].resize(col + 1, StyledChar::SPACE); } + self.lines[line][col] = StyledChar::new(chr, style); } /// Sets `string` with `style` for given `line`, starting from `col`. - /// If line not exist in `StyledBuffer`, adds lines up to given - /// and fills last line with spaces and `Style::NoStyle` style + /// If `line` does not exist in our buffer, adds empty lines up to the given + /// and fills the last line with unstyled whitespace. pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) { let mut n = col; for c in string.chars() { @@ -108,7 +98,7 @@ impl StyledBuffer { if !self.lines[line].is_empty() { // Push the old content over to make room for new content for _ in 0..string_len { - self.lines[line].insert(0, StyledChar::default()); + self.lines[line].insert(0, StyledChar::SPACE); } } From 3b504610b6768d8cb700bc2a8fa2a6263b9d3a06 Mon Sep 17 00:00:00 2001 From: Tor Hovland Date: Sat, 24 Apr 2021 22:20:08 +0200 Subject: [PATCH 17/26] One more test case. --- src/test/ui/loops/loop-no-implicit-break.rs | 4 ++++ src/test/ui/loops/loop-no-implicit-break.stderr | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/ui/loops/loop-no-implicit-break.rs b/src/test/ui/loops/loop-no-implicit-break.rs index fc3b3c4a30fac..93078cb4b144b 100644 --- a/src/test/ui/loops/loop-no-implicit-break.rs +++ b/src/test/ui/loops/loop-no-implicit-break.rs @@ -24,4 +24,8 @@ fn foo() -> i8 { loop { return 1; } + + loop { + 1 //~ ERROR mismatched types + } } diff --git a/src/test/ui/loops/loop-no-implicit-break.stderr b/src/test/ui/loops/loop-no-implicit-break.stderr index cde6bbe512b28..5087662e7bfa4 100644 --- a/src/test/ui/loops/loop-no-implicit-break.stderr +++ b/src/test/ui/loops/loop-no-implicit-break.stderr @@ -31,6 +31,17 @@ help: you might have meant to return this value LL | return 1; | ^^^^^^ ^ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/loop-no-implicit-break.rs:29:9 + | +LL | 1 + | ^ expected `()`, found integer + | +help: you might have meant to return this value + | +LL | return 1; + | ^^^^^^ ^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From fbc2aadbfc6a54da9d8cc5929287d2bcc55c545e Mon Sep 17 00:00:00 2001 From: KaiJewson Date: Sun, 25 Apr 2021 07:39:09 +0100 Subject: [PATCH 18/26] Inline most raw socket, fd and handle conversions --- library/std/src/sys/sgx/ext/io.rs | 6 ++++++ library/std/src/sys/unix/ext/io.rs | 12 +++++++++++ library/std/src/sys/unix/ext/net/datagram.rs | 3 +++ library/std/src/sys/unix/ext/net/listener.rs | 3 +++ library/std/src/sys/unix/ext/net/raw_fd.rs | 3 +++ library/std/src/sys/unix/ext/net/stream.rs | 3 +++ library/std/src/sys/unix/ext/process.rs | 7 +++++++ library/std/src/sys/wasi/ext/io.rs | 21 ++++++++++++++++++++ library/std/src/sys/windows/ext/io.rs | 12 +++++++++++ library/std/src/sys/windows/ext/process.rs | 4 ++++ library/std/src/sys/windows/ext/thread.rs | 2 ++ 11 files changed, 76 insertions(+) diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs index 795a4d190cf4e..7223ade68158f 100644 --- a/library/std/src/sys/sgx/ext/io.rs +++ b/library/std/src/sys/sgx/ext/io.rs @@ -63,12 +63,14 @@ pub trait TryIntoRawFd: Sized { } impl AsRawFd for net::TcpStream { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() } } impl AsRawFd for net::TcpListener { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.as_inner().as_inner().as_inner().as_inner() } @@ -87,6 +89,7 @@ pub struct TcpStreamMetadata { impl FromRawFd for net::TcpStream { type Metadata = TcpStreamMetadata; + #[inline] unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream { let fd = sys::fd::FileDesc::from_inner(fd); let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); @@ -105,6 +108,7 @@ pub struct TcpListenerMetadata { impl FromRawFd for net::TcpListener { type Metadata = TcpListenerMetadata; + #[inline] unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener { let fd = sys::fd::FileDesc::from_inner(fd); let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); @@ -113,6 +117,7 @@ impl FromRawFd for net::TcpListener { } impl TryIntoRawFd for net::TcpStream { + #[inline] fn try_into_raw_fd(self) -> Result { let (socket, peer_addr) = self.into_inner().into_inner(); match socket.try_into_inner() { @@ -126,6 +131,7 @@ impl TryIntoRawFd for net::TcpStream { } impl TryIntoRawFd for net::TcpListener { + #[inline] fn try_into_raw_fd(self) -> Result { match self.into_inner().into_inner().try_into_inner() { Ok(fd) => Ok(fd.into_inner()), diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index ef3c689bd3921..07c30bfa9ed15 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -104,18 +104,21 @@ pub trait IntoRawFd { #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl AsRawFd for RawFd { + #[inline] fn as_raw_fd(&self) -> RawFd { *self } } #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl IntoRawFd for RawFd { + #[inline] fn into_raw_fd(self) -> RawFd { self } } #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl FromRawFd for RawFd { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> RawFd { fd } @@ -123,18 +126,21 @@ impl FromRawFd for RawFd { #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().raw() } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for fs::File { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } @@ -142,6 +148,7 @@ impl IntoRawFd for fs::File { #[stable(feature = "asraw_stdio", since = "1.21.0")] impl AsRawFd for io::Stdin { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } @@ -149,6 +156,7 @@ impl AsRawFd for io::Stdin { #[stable(feature = "asraw_stdio", since = "1.21.0")] impl AsRawFd for io::Stdout { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } @@ -156,6 +164,7 @@ impl AsRawFd for io::Stdout { #[stable(feature = "asraw_stdio", since = "1.21.0")] impl AsRawFd for io::Stderr { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } @@ -163,6 +172,7 @@ impl AsRawFd for io::Stderr { #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] impl<'a> AsRawFd for io::StdinLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO } @@ -170,6 +180,7 @@ impl<'a> AsRawFd for io::StdinLock<'a> { #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] impl<'a> AsRawFd for io::StdoutLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO } @@ -177,6 +188,7 @@ impl<'a> AsRawFd for io::StdoutLock<'a> { #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] impl<'a> AsRawFd for io::StderrLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO } diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs index a8c13fbb87480..9e39f70f68e69 100644 --- a/library/std/src/sys/unix/ext/net/datagram.rs +++ b/library/std/src/sys/unix/ext/net/datagram.rs @@ -879,6 +879,7 @@ impl UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixDatagram { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } @@ -886,6 +887,7 @@ impl AsRawFd for UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixDatagram { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { UnixDatagram(Socket::from_inner(fd)) } @@ -893,6 +895,7 @@ impl FromRawFd for UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixDatagram { + #[inline] fn into_raw_fd(self) -> RawFd { self.0.into_inner() } diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs index 9803c6e27462c..bdd08fe8380fa 100644 --- a/library/std/src/sys/unix/ext/net/listener.rs +++ b/library/std/src/sys/unix/ext/net/listener.rs @@ -240,6 +240,7 @@ impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixListener { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } @@ -247,6 +248,7 @@ impl AsRawFd for UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixListener { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(Socket::from_inner(fd)) } @@ -254,6 +256,7 @@ impl FromRawFd for UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixListener { + #[inline] fn into_raw_fd(self) -> RawFd { self.0.into_inner() } diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs index c42fee4c73bcd..b3f1284410124 100644 --- a/library/std/src/sys/unix/ext/net/raw_fd.rs +++ b/library/std/src/sys/unix/ext/net/raw_fd.rs @@ -6,6 +6,7 @@ macro_rules! impl_as_raw_fd { ($($t:ident)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::$t { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } @@ -18,6 +19,7 @@ macro_rules! impl_from_raw_fd { ($($t:ident)*) => {$( #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::$t { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::$t { let socket = sys::net::Socket::from_inner(fd); net::$t::from_inner(sys_common::net::$t::from_inner(socket)) @@ -31,6 +33,7 @@ macro_rules! impl_into_raw_fd { ($($t:ident)*) => {$( #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for net::$t { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_socket().into_inner() } diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs index fc08edacb828d..a6f6e091305d5 100644 --- a/library/std/src/sys/unix/ext/net/stream.rs +++ b/library/std/src/sys/unix/ext/net/stream.rs @@ -654,6 +654,7 @@ impl<'a> io::Write for &'a UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl AsRawFd for UnixStream { + #[inline] fn as_raw_fd(&self) -> RawFd { *self.0.as_inner() } @@ -661,6 +662,7 @@ impl AsRawFd for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl FromRawFd for UnixStream { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(Socket::from_inner(fd)) } @@ -668,6 +670,7 @@ impl FromRawFd for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl IntoRawFd for UnixStream { + #[inline] fn into_raw_fd(self) -> RawFd { self.0.into_inner() } diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index bc3bc0dcb0ce3..355855bcd10e2 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -274,6 +274,7 @@ impl ExitStatusExt for process::ExitStatus { #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawFd for process::Stdio { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { let fd = sys::fd::FileDesc::new(fd); let io = sys::process::Stdio::Fd(fd); @@ -283,6 +284,7 @@ impl FromRawFd for process::Stdio { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStdin { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().raw() } @@ -290,6 +292,7 @@ impl AsRawFd for process::ChildStdin { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStdout { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().raw() } @@ -297,6 +300,7 @@ impl AsRawFd for process::ChildStdout { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStderr { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().raw() } @@ -304,6 +308,7 @@ impl AsRawFd for process::ChildStderr { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdin { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } @@ -311,6 +316,7 @@ impl IntoRawFd for process::ChildStdin { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdout { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } @@ -318,6 +324,7 @@ impl IntoRawFd for process::ChildStdout { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStderr { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index 3c480aa8e19bf..b2e79cc1b4a9d 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -54,126 +54,147 @@ pub trait IntoRawFd { #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl AsRawFd for RawFd { + #[inline] fn as_raw_fd(&self) -> RawFd { *self } } #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl IntoRawFd for RawFd { + #[inline] fn into_raw_fd(self) -> RawFd { self } } #[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl FromRawFd for RawFd { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> RawFd { fd } } impl AsRawFd for net::TcpStream { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() } } impl FromRawFd for net::TcpStream { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd)) } } impl IntoRawFd for net::TcpStream { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } impl AsRawFd for net::TcpListener { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() } } impl FromRawFd for net::TcpListener { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd)) } } impl IntoRawFd for net::TcpListener { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } impl AsRawFd for net::UdpSocket { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() } } impl FromRawFd for net::UdpSocket { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd)) } } impl IntoRawFd for net::UdpSocket { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } impl AsRawFd for fs::File { + #[inline] fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() } } impl FromRawFd for fs::File { + #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } impl IntoRawFd for fs::File { + #[inline] fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } impl AsRawFd for io::Stdin { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO as RawFd } } impl AsRawFd for io::Stdout { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO as RawFd } } impl AsRawFd for io::Stderr { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO as RawFd } } impl<'a> AsRawFd for io::StdinLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO as RawFd } } impl<'a> AsRawFd for io::StdoutLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO as RawFd } } impl<'a> AsRawFd for io::StderrLock<'a> { + #[inline] fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO as RawFd } diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs index e75f9a4bfd5e3..31b5d015ed0c3 100644 --- a/library/std/src/sys/windows/ext/io.rs +++ b/library/std/src/sys/windows/ext/io.rs @@ -59,6 +59,7 @@ pub trait IntoRawHandle { #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as RawHandle } @@ -108,6 +109,7 @@ impl<'a> AsRawHandle for io::StderrLock<'a> { #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawHandle for fs::File { + #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { let handle = handle as c::HANDLE; fs::File::from_inner(sys::fs::File::from_inner(handle)) @@ -116,6 +118,7 @@ impl FromRawHandle for fs::File { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for fs::File { + #[inline] fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } @@ -161,18 +164,21 @@ pub trait IntoRawSocket { #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { + #[inline] fn as_raw_socket(&self) -> RawSocket { *self.as_inner().socket().as_inner() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpListener { + #[inline] fn as_raw_socket(&self) -> RawSocket { *self.as_inner().socket().as_inner() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::UdpSocket { + #[inline] fn as_raw_socket(&self) -> RawSocket { *self.as_inner().socket().as_inner() } @@ -180,6 +186,7 @@ impl AsRawSocket for net::UdpSocket { #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpStream { + #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { let sock = sys::net::Socket::from_inner(sock); net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) @@ -187,6 +194,7 @@ impl FromRawSocket for net::TcpStream { } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::TcpListener { + #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { let sock = sys::net::Socket::from_inner(sock); net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) @@ -194,6 +202,7 @@ impl FromRawSocket for net::TcpListener { } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawSocket for net::UdpSocket { + #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { let sock = sys::net::Socket::from_inner(sock); net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) @@ -202,6 +211,7 @@ impl FromRawSocket for net::UdpSocket { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::TcpStream { + #[inline] fn into_raw_socket(self) -> RawSocket { self.into_inner().into_socket().into_inner() } @@ -209,6 +219,7 @@ impl IntoRawSocket for net::TcpStream { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::TcpListener { + #[inline] fn into_raw_socket(self) -> RawSocket { self.into_inner().into_socket().into_inner() } @@ -216,6 +227,7 @@ impl IntoRawSocket for net::TcpListener { #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawSocket for net::UdpSocket { + #[inline] fn into_raw_socket(self) -> RawSocket { self.into_inner().into_socket().into_inner() } diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 67412e1677937..67756b15531bf 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -19,6 +19,7 @@ impl FromRawHandle for process::Stdio { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::Child { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as *mut _ } @@ -33,6 +34,7 @@ impl IntoRawHandle for process::Child { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as *mut _ } @@ -40,6 +42,7 @@ impl AsRawHandle for process::ChildStdin { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdout { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as *mut _ } @@ -47,6 +50,7 @@ impl AsRawHandle for process::ChildStdout { #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStderr { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as *mut _ } diff --git a/library/std/src/sys/windows/ext/thread.rs b/library/std/src/sys/windows/ext/thread.rs index 41c29f5b950ef..6bd02054f7150 100644 --- a/library/std/src/sys/windows/ext/thread.rs +++ b/library/std/src/sys/windows/ext/thread.rs @@ -8,6 +8,7 @@ use crate::thread; #[stable(feature = "thread_extensions", since = "1.9.0")] impl AsRawHandle for thread::JoinHandle { + #[inline] fn as_raw_handle(&self) -> RawHandle { self.as_inner().handle().raw() as *mut _ } @@ -15,6 +16,7 @@ impl AsRawHandle for thread::JoinHandle { #[stable(feature = "thread_extensions", since = "1.9.0")] impl IntoRawHandle for thread::JoinHandle { + #[inline] fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } From e558ddbb3aa8a787aac030969af7575aceed63cb Mon Sep 17 00:00:00 2001 From: Hameer Abbasi Date: Sat, 24 Apr 2021 16:25:36 +0200 Subject: [PATCH 19/26] Improve diagnostics for function passed when a type was expected. --- compiler/rustc_typeck/src/astconv/generics.rs | 14 ++++++++++++++ .../generics/generic-function-item-where-type.rs | 6 ++++++ .../generic-function-item-where-type.stderr | 12 ++++++++++++ src/test/ui/privacy/privacy-ns1.stderr | 3 +++ src/test/ui/privacy/privacy-ns2.stderr | 6 ++++++ 5 files changed, 41 insertions(+) create mode 100644 src/test/ui/generics/generic-function-item-where-type.rs create mode 100644 src/test/ui/generics/generic-function-item-where-type.stderr diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 7a297f2c65f13..748704988627f 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -109,6 +109,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } } + (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { + let body = tcx.hir().body(cnst.value.body); + if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = + body.value.kind + { + if let Res::Def(DefKind::Fn { .. }, id) = path.res { + err.help(&format!( + "`{}` is a function item, not a type", + tcx.item_name(id) + )); + err.help("function item types cannot be named directly"); + } + } + } _ => {} } diff --git a/src/test/ui/generics/generic-function-item-where-type.rs b/src/test/ui/generics/generic-function-item-where-type.rs new file mode 100644 index 0000000000000..e1b0578cadbe9 --- /dev/null +++ b/src/test/ui/generics/generic-function-item-where-type.rs @@ -0,0 +1,6 @@ +fn foo() {} + +fn main() { + foo::
() + //~^ ERROR constant provided when a type was expected +} diff --git a/src/test/ui/generics/generic-function-item-where-type.stderr b/src/test/ui/generics/generic-function-item-where-type.stderr new file mode 100644 index 0000000000000..88594129caaba --- /dev/null +++ b/src/test/ui/generics/generic-function-item-where-type.stderr @@ -0,0 +1,12 @@ +error[E0747]: constant provided when a type was expected + --> $DIR/generic-function-item-where-type.rs:4:11 + | +LL | foo::
() + | ^^^^ + | + = help: `main` is a function item, not a type + = help: function item types cannot be named directly + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr index 714f28941f11f..d09a8aae74801 100644 --- a/src/test/ui/privacy/privacy-ns1.stderr +++ b/src/test/ui/privacy/privacy-ns1.stderr @@ -57,6 +57,9 @@ error[E0747]: constant provided when a type was expected | LL | let _x: Box; | ^^^ + | + = help: `Bar` is a function item, not a type + = help: function item types cannot be named directly error: aborting due to 4 previous errors diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr index c7ad8ec503654..fdf0549cf50bc 100644 --- a/src/test/ui/privacy/privacy-ns2.stderr +++ b/src/test/ui/privacy/privacy-ns2.stderr @@ -83,12 +83,18 @@ error[E0747]: constant provided when a type was expected | LL | let _x : Box; | ^^^ + | + = help: `Bar` is a function item, not a type + = help: function item types cannot be named directly error[E0747]: constant provided when a type was expected --> $DIR/privacy-ns2.rs:48:17 | LL | let _x: Box; | ^^^ + | + = help: `Bar` is a function item, not a type + = help: function item types cannot be named directly error: aborting due to 8 previous errors From 9082078a26b3f8c6e8c9b55a966b2a6d6f410ea2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 12:52:42 +0200 Subject: [PATCH 20/26] unsafety checking: no longer care about is_min_const_fn Rejecting the forbidden unsafe ops is done by const checking, not by unsafety checking --- compiler/rustc_middle/src/mir/query.rs | 4 +- .../rustc_mir/src/transform/check_unsafety.rs | 67 +++++-------------- 2 files changed, 18 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index ad3baccf15496..8c540536d926a 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -19,10 +19,8 @@ use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { - /// Only permitted in regular `fn`s, prohibited in `const fn`s. + /// Unsafe operation outside `unsafe` General, - /// Permitted both in `const fn`s and regular `fn`s. - GeneralAndConstFn, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. UnsafeFn, diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 09da9b2e4d6ff..955be8cc81e18 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -15,13 +15,10 @@ use rustc_session::lint::Level; use std::ops::Bound; -use crate::const_eval::is_min_const_fn; - pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, body_did: LocalDefId, const_context: bool, - min_const_fn: bool, violations: Vec, source_info: SourceInfo, tcx: TyCtxt<'tcx>, @@ -34,21 +31,15 @@ pub struct UnsafetyChecker<'a, 'tcx> { impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn new( const_context: bool, - min_const_fn: bool, body: &'a Body<'tcx>, body_did: LocalDefId, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { - // sanity check - if min_const_fn { - assert!(const_context); - } Self { body, body_did, const_context, - min_const_fn, violations: vec![], source_info: SourceInfo::outermost(body.span), tcx, @@ -84,7 +75,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { let sig = func_ty.fn_sig(self.tcx); if let hir::Unsafety::Unsafe = sig.unsafety() { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::CallToUnsafeFunction, ) } @@ -134,7 +125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {} _ => self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::InitializingTypeWith, ), } @@ -213,7 +204,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { let base_ty = base.ty(self.body, self.tcx).ty; if base_ty.is_unsafe_ptr() { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::DerefOfRawPointer, ) } @@ -258,7 +249,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); if !nodrop { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::AssignToDroppingUnionField, ); } else { @@ -266,7 +257,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } else { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::AccessToUnionField, ) } @@ -277,6 +268,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) { + // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such. + assert_ne!(kind, UnsafetyViolationKind::UnsafeFn); + let source_info = self.source_info; let lint_root = self.body.source_scopes[self.source_info.scope] .local_data @@ -304,8 +298,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { Safety::Safe => { for violation in violations { match violation.kind { - UnsafetyViolationKind::GeneralAndConstFn - | UnsafetyViolationKind::General => {} + UnsafetyViolationKind::General => {} UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } @@ -334,29 +327,6 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { if !violations.is_empty() { self.used_unsafe.insert(hir_id); } - // only some unsafety is allowed in const fn - if self.min_const_fn { - for violation in violations { - match violation.kind { - // these unsafe things are stable in const fn - UnsafetyViolationKind::GeneralAndConstFn => {} - // these things are forbidden in const fns - UnsafetyViolationKind::General => { - let mut violation = *violation; - // const fns don't need to be backwards compatible and can - // emit these violations as a hard error instead of a backwards - // compat lint - violation.kind = UnsafetyViolationKind::General; - if !self.violations.contains(&violation) { - self.violations.push(violation) - } - } - UnsafetyViolationKind::UnsafeFn => bug!( - "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" - ), - } - } - } true } }; @@ -394,7 +364,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } else { continue; }; - self.require_unsafe(UnsafetyViolationKind::GeneralAndConstFn, details); + self.require_unsafe(UnsafetyViolationKind::General, details); } } } @@ -412,7 +382,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { // Is `callee_features` a subset of `calling_features`? if !callee_features.iter().all(|feature| self_features.contains(feature)) { self.require_unsafe( - UnsafetyViolationKind::GeneralAndConstFn, + UnsafetyViolationKind::General, UnsafetyViolationDetails::CallToFunctionWith, ) } @@ -494,15 +464,12 @@ fn unsafety_check_result<'tcx>( let param_env = tcx.param_env(def.did); let id = tcx.hir().local_def_id_to_hir_id(def.did); - let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) { - hir::BodyOwnerKind::Closure => (false, false), - hir::BodyOwnerKind::Fn => { - (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id())) - } - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), + let const_context = match tcx.hir().body_owner_kind(id) { + hir::BodyOwnerKind::Closure => false, + hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()), + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true, }; - let mut checker = - UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env); + let mut checker = UnsafetyChecker::new(const_context, body, def.did, tcx, param_env); checker.visit_body(&body); check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks); @@ -577,7 +544,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; match kind { - UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { + UnsafetyViolationKind::General => { // once struct_span_err!( tcx.sess, From 1ecdaa29f9bbe33b8ea701fb691c7001894dc83a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 12:53:55 +0200 Subject: [PATCH 21/26] remove now-unused 'is_min_const_fn' --- .../rustc_mir/src/const_eval/fn_queries.rs | 49 ------------------- 1 file changed, 49 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs index 8c18dfcb8d0cc..40419a4d201ac 100644 --- a/compiler/rustc_mir/src/const_eval/fn_queries.rs +++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::map::blocks::FnLikeNode; @@ -34,54 +33,6 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { } } -/// Returns `true` if this function must conform to `min_const_fn` -pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Bail out if the signature doesn't contain `const` - if !tcx.is_const_fn_raw(def_id) { - return false; - } - - if tcx.features().staged_api { - // In order for a libstd function to be considered min_const_fn - // it needs to be stable and have no `rustc_const_unstable` attribute. - match tcx.lookup_const_stability(def_id) { - // `rustc_const_unstable` functions don't need to conform. - Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false, - None => { - if let Some(stab) = tcx.lookup_stability(def_id) { - if stab.level.is_stable() { - tcx.sess.delay_span_bug( - tcx.def_span(def_id), - "stable const functions must have either `rustc_const_stable` or \ - `rustc_const_unstable` attribute", - ); - // While we errored above, because we don't know if we need to conform, we - // err on the "safe" side and require min_const_fn. - true - } else { - // Unstable functions need not conform to min_const_fn. - false - } - } else { - // Internal functions are forced to conform to min_const_fn. - // Annotate the internal function with a const stability attribute if - // you need to use unstable features. - // Note: this is an arbitrary choice that does not affect stability or const - // safety or anything, it just changes whether we need to annotate some - // internal functions with `rustc_const_stable` or with `rustc_const_unstable` - true - } - } - // Everything else needs to conform, because it would be callable from - // other `min_const_fn` functions. - _ => true, - } - } else { - // users enabling the `const_fn` feature gate can do what they want - !tcx.features().const_fn - } -} - pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { let parent_id = tcx.hir().get_parent_did(hir_id); if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false } From 43126f357339bd35e6cdc28201516422f6a2dac1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 13:59:10 +0200 Subject: [PATCH 22/26] get rid of min_const_fn references in library/ and rustdoc --- library/alloc/src/raw_vec.rs | 14 ++++---------- src/librustdoc/clean/inline.rs | 3 +-- src/librustdoc/clean/mod.rs | 4 ++-- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index dc02c9c883ea0..fe87a97bac128 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -53,17 +53,11 @@ pub struct RawVec { } impl RawVec { - /// HACK(Centril): This exists because `#[unstable]` `const fn`s needn't conform - /// to `min_const_fn` and so they cannot be called in `min_const_fn`s either. + /// HACK(Centril): This exists because stable `const fn` can only call stable `const fn`, so + /// they cannot call `Self::new()`. /// - /// If you change `RawVec::new` or dependencies, please take care to not - /// introduce anything that would truly violate `min_const_fn`. - /// - /// NOTE: We could avoid this hack and check conformance with some - /// `#[rustc_force_min_const_fn]` attribute which requires conformance - /// with `min_const_fn` but does not necessarily allow calling it in - /// `stable(...) const fn` / user code not enabling `foo` when - /// `#[rustc_const_unstable(feature = "foo", issue = "01234")]` is present. + /// If you change `RawVec::new` or dependencies, please take care to not introduce anything + /// that would truly const-call something unstable. pub const NEW: Self = Self::new(); /// Creates the biggest possible `RawVec` (on the system heap) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e88a739d04296..3986167bac8d3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -10,7 +10,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty::{self, TyCtxt}; -use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -210,7 +209,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi let sig = cx.tcx.fn_sig(did); let constness = - if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst }; + if cx.tcx.is_const_fn_raw(did) { hir::Constness::Const } else { hir::Constness::NotConst }; let asyncness = cx.tcx.asyncness(did); let predicates = cx.tcx.predicates_of(did); let (generics, decl) = clean::enter_impl_trait(cx, |cx| { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c0a8c88bdeba0..6b04157d9530f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime as rl; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; +use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, ExpnKind}; @@ -1048,7 +1048,7 @@ impl Clean for ty::AssocItem { ty::TraitContainer(_) => self.defaultness.has_value(), }; if provided { - let constness = if is_min_const_fn(tcx, self.def_id) { + let constness = if tcx.is_const_fn_raw(self.def_id) { hir::Constness::Const } else { hir::Constness::NotConst From b1ad1fbc03383e6c7a320b7a18a1fd02ebc68e3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 16:32:05 +0200 Subject: [PATCH 23/26] make sure raw ptr casts in 'const' context are unsafe --- src/test/ui/cast/cast-ptr-to-int-const.rs | 22 +++++++++-- src/test/ui/cast/cast-ptr-to-int-const.stderr | 21 ---------- .../cast-ptr-to-int-const.with_feature.stderr | 19 +++++++++ ...st-ptr-to-int-const.without_feature.stderr | 39 +++++++++++++++++++ 4 files changed, 76 insertions(+), 25 deletions(-) delete mode 100644 src/test/ui/cast/cast-ptr-to-int-const.stderr create mode 100644 src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr create mode 100644 src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs index ac153cb57423f..aed099a53eaf4 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.rs +++ b/src/test/ui/cast/cast-ptr-to-int-const.rs @@ -1,11 +1,25 @@ // gate-test-const_raw_ptr_to_usize_cast +// revisions: with_feature without_feature + +#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))] fn main() { - const X: u32 = unsafe { - main as u32 //~ ERROR casting pointers to integers in constants is unstable + const X: usize = unsafe { + main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable }; const Y: u32 = 0; - const Z: u32 = unsafe { - &Y as *const u32 as u32 //~ ERROR is unstable + const Z: usize = unsafe { + &Y as *const u32 as usize //[without_feature]~ ERROR is unstable + }; + // Cast in `const` without `unsafe` block + const SAFE: usize = { + &Y as *const u32 as usize //[without_feature]~ ERROR is unstable + //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe }; } + +// Cast in `const fn` without `unsafe` block +const fn test() -> usize { + &0 as *const i32 as usize //[without_feature]~ ERROR is unstable + //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe +} diff --git a/src/test/ui/cast/cast-ptr-to-int-const.stderr b/src/test/ui/cast/cast-ptr-to-int-const.stderr deleted file mode 100644 index f523b14a98c00..0000000000000 --- a/src/test/ui/cast/cast-ptr-to-int-const.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:5:9 - | -LL | main as u32 - | ^^^^^^^^^^^ - | - = note: see issue #51910 for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:9:9 - | -LL | &Y as *const u32 as u32 - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #51910 for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr new file mode 100644 index 0000000000000..8282bc3db0507 --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr @@ -0,0 +1,19 @@ +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:16:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:23:5 + | +LL | &0 as *const i32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr new file mode 100644 index 0000000000000..c87fa1a14a4c8 --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr @@ -0,0 +1,39 @@ +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:8:9 + | +LL | main as usize + | ^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:12:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constants is unstable + --> $DIR/cast-ptr-to-int-const.rs:16:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error[E0658]: casting pointers to integers in constant functions is unstable + --> $DIR/cast-ptr-to-int-const.rs:23:5 + | +LL | &0 as *const i32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. From 421d54e4aa484b6eec6b5e8a0807f8f4430739b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 17:05:48 +0200 Subject: [PATCH 24/26] fix clippy --- src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 93b7a897405ae..60425ff853b7e 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { - if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) { + if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { cx.tcx.sess.span_err(span, &err); } } else { From 588530d09635bdcdb972c0bc4fa99b983e9368ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 18:41:14 +0200 Subject: [PATCH 25/26] fix typography --- compiler/rustc_middle/src/mir/query.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 8c540536d926a..fdd874c6f6822 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -19,7 +19,7 @@ use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { - /// Unsafe operation outside `unsafe` + /// Unsafe operation outside `unsafe`. General, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. From d326a4b4c9176193ff0ac445ec14ac50bd081f04 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 22 Apr 2021 15:23:30 -0400 Subject: [PATCH 26/26] Give a better error when std or core are missing - Suggest using `rustup target add` if `RUSTUP_HOME` is set. I don't know if there's any precedent for doing this, but it seems harmless enough and it will be a big help. - Add a note about `#![no_std]` if `std` is missing but not core - On nightly, suggest using `cargo build -Z build-std` if `CARGO` is set - Add a note that std may be unsupported if `std` is missing but not core - Don't suggest `#![no_std]` when the load isn't injected by the compiler --- compiler/rustc_metadata/src/creader.rs | 7 ++-- compiler/rustc_metadata/src/locator.rs | 37 ++++++++++++++++++-- src/test/ui/crate-loading/missing-std.rs | 11 ++++++ src/test/ui/crate-loading/missing-std.stderr | 13 +++++++ 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/crate-loading/missing-std.rs create mode 100644 src/test/ui/crate-loading/missing-std.stderr diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 26db3a5f39d7c..e9ae22f8cedbc 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -511,8 +511,11 @@ impl<'a> CrateLoader<'a> { if dep.is_none() { self.used_extern_options.insert(name); } - self.maybe_resolve_crate(name, dep_kind, dep) - .unwrap_or_else(|err| err.report(self.sess, span)) + self.maybe_resolve_crate(name, dep_kind, dep).unwrap_or_else(|err| { + let missing_core = + self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); + err.report(&self.sess, span, missing_core) + }) } fn maybe_resolve_crate<'b>( diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 7f6311861c1b2..6e7360950908e 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -790,7 +790,8 @@ pub fn find_plugin_registrar( ) -> (PathBuf, CrateDisambiguator) { match find_plugin_registrar_impl(sess, metadata_loader, name) { Ok(res) => res, - Err(err) => err.report(sess, span), + // `core` is always available if we got as far as loading plugins. + Err(err) => err.report(sess, span, false), } } @@ -883,7 +884,7 @@ crate enum CrateError { } impl CrateError { - crate fn report(self, sess: &Session, span: Span) -> ! { + crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! { let mut err = match self { CrateError::NonAsciiName(crate_name) => sess.struct_span_err( span, @@ -1068,7 +1069,37 @@ impl CrateError { if (crate_name == sym::std || crate_name == sym::core) && locator.triple != TargetTriple::from_triple(config::host_triple()) { - err.note(&format!("the `{}` target may not be installed", locator.triple)); + if missing_core { + err.note(&format!( + "the `{}` target may not be installed", + locator.triple + )); + } else { + err.note(&format!( + "the `{}` target may not support the standard library", + locator.triple + )); + } + if missing_core && std::env::var("RUSTUP_HOME").is_ok() { + err.help(&format!( + "consider downloading the target with `rustup target add {}`", + locator.triple + )); + } + // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. + // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. + // If it's not a dummy, that means someone added `extern crate std` explicitly and `#![no_std]` won't help. + if !missing_core && span.is_dummy() { + let current_crate = + sess.opts.crate_name.as_deref().unwrap_or(""); + err.note(&format!( + "`std` is required by `{}` because it does not declare `#![no_std]`", + current_crate + )); + } + if sess.is_nightly_build() && std::env::var("CARGO").is_ok() { + err.help("consider building the standard library from source with `cargo build -Zbuild-std`"); + } } else if crate_name == sym::profiler_builtins { err.note(&"the compiler may have been built without the profiler runtime"); } diff --git a/src/test/ui/crate-loading/missing-std.rs b/src/test/ui/crate-loading/missing-std.rs new file mode 100644 index 0000000000000..442a7c01e5a69 --- /dev/null +++ b/src/test/ui/crate-loading/missing-std.rs @@ -0,0 +1,11 @@ +// compile-flags: --target x86_64-unknown-uefi +// rustc-env:CARGO=/usr/bin/cargo +// rustc-env:RUSTUP_HOME=/home/bors/.rustup +#![no_core] +extern crate core; +//~^ ERROR can't find crate for `core` +//~| NOTE can't find crate +//~| NOTE target may not be installed +//~| HELP consider building the standard library from source with `cargo build -Zbuild-std` +//~| HELP consider downloading the target with `rustup target add x86_64-unknown-uefi` +fn main() {} diff --git a/src/test/ui/crate-loading/missing-std.stderr b/src/test/ui/crate-loading/missing-std.stderr new file mode 100644 index 0000000000000..25808efdfa699 --- /dev/null +++ b/src/test/ui/crate-loading/missing-std.stderr @@ -0,0 +1,13 @@ +error[E0463]: can't find crate for `core` + --> $DIR/missing-std.rs:5:1 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ can't find crate + | + = note: the `x86_64-unknown-uefi` target may not be installed + = help: consider downloading the target with `rustup target add x86_64-unknown-uefi` + = help: consider building the standard library from source with `cargo build -Zbuild-std` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0463`.