From 2daa013290e054151424849e51c0b1f24db7e7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 22 May 2018 21:05:35 -0700 Subject: [PATCH 01/16] Underline multiple suggested replacements in the same line Follow up to #50943. Fix #50977. --- src/librustc_errors/emitter.rs | 65 ++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 91075ddcfa42..123b6abab504 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1215,19 +1215,20 @@ impl EmitterWriter { let mut row_num = 2; for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) { - let show_underline = parts.len() == 1 - && complete.lines().count() == 1 - && parts[0].snippet.trim() != complete.trim(); + // Only show underline if the suggestion spans a single line and doesn't cover the + // entirety of the code output. If you have multiple replacements in the same line + // of code, show the underline. + let show_underline = !(parts.len() == 1 + && parts[0].snippet.trim() == complete.trim()) + && complete.lines().count() == 1; let lines = cm.span_to_lines(parts[0].span).unwrap(); assert!(!lines.lines.is_empty()); - let span_start_pos = cm.lookup_char_pos(parts[0].span.lo()); - let line_start = span_start_pos.line; + let line_start = cm.lookup_char_pos(parts[0].span.lo()).line; draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); let mut line_pos = 0; - // Only show underline if there's a single suggestion and it is a single line let mut lines = complete.lines(); for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { // Print the span column to avoid confusion @@ -1241,22 +1242,50 @@ impl EmitterWriter { line_pos += 1; row_num += 1; } + let mut extra = 0; // Only show an underline in the suggestions if the suggestion is not the // entirety of the code being shown and the displayed code is not multiline. if show_underline { draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); - let start = parts[0].snippet.len() - parts[0].snippet.trim_left().len(); - // account for substitutions containing unicode characters - let sub_len = parts[0].snippet.trim().chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) - }); - let underline_start = span_start_pos.col_display + start; - let underline_end = span_start_pos.col_display + start + sub_len; - for p in underline_start..underline_end { - buffer.putc(row_num, - max_line_num_len + 3 + p, - '^', - Style::UnderlinePrimary); + for part in parts { + let span_start_pos = cm.lookup_char_pos(part.span.lo()); + let span_end_pos = cm.lookup_char_pos(part.span.hi()); + // length of the code to be substituted + let snippet_len = span_end_pos.col_display - span_start_pos.col_display; + + // Do not underline the leading or trailing spaces. + let start = part.snippet.len() - part.snippet.trim_left().len(); + // account for substitutions containing unicode characters + let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + }); + + let underline_start = span_start_pos.col_display + start + extra; + let underline_end = span_start_pos.col_display + start + sub_len + extra; + for p in underline_start..underline_end { + buffer.putc(row_num, + max_line_num_len + 3 + p, + '^', + Style::UnderlinePrimary); + } + // underline removals too + if underline_start == underline_end { + for p in underline_start-1..underline_start+1 { + buffer.putc(row_num, + max_line_num_len + 3 + p, + '-', + Style::UnderlineSecondary); + } + } + + // length of the code after substitution + let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + }); + + // For multiple substitutions, use the position *after* the previous + // substitutions have happened. + extra += full_sub_len - snippet_len; } row_num += 1; } From 50eefc0d777a70ff8d11cfd358eb0ed36f6e0651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 23 May 2018 18:31:54 -0700 Subject: [PATCH 02/16] Account for negative offsets in suggestions When suggesting code that has a shorter span than the current code, account for this by keeping the offset as a signed value. --- src/librustc_errors/emitter.rs | 35 +++++++++++-------- .../impl-trait/impl-generic-mismatch.stderr | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 123b6abab504..4d1d33e1325b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1242,29 +1242,32 @@ impl EmitterWriter { line_pos += 1; row_num += 1; } - let mut extra = 0; + + // This offset and the ones below need to be signed to account for replacement code + // that is shorter than the original code. + let mut offset: isize = 0; // Only show an underline in the suggestions if the suggestion is not the // entirety of the code being shown and the displayed code is not multiline. if show_underline { draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); for part in parts { - let span_start_pos = cm.lookup_char_pos(part.span.lo()); - let span_end_pos = cm.lookup_char_pos(part.span.hi()); - // length of the code to be substituted - let snippet_len = span_end_pos.col_display - span_start_pos.col_display; - - // Do not underline the leading or trailing spaces. - let start = part.snippet.len() - part.snippet.trim_left().len(); - // account for substitutions containing unicode characters + let span_start_pos = cm.lookup_char_pos(part.span.lo()).col_display; + let span_end_pos = cm.lookup_char_pos(part.span.hi()).col_display; + + // Do not underline the leading... + let start = part.snippet.len() + .saturating_sub(part.snippet.trim_left().len()); + // ...or trailing spaces. Account for substitutions containing unicode + // characters. let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) }); - let underline_start = span_start_pos.col_display + start + extra; - let underline_end = span_start_pos.col_display + start + sub_len + extra; + let underline_start = (span_start_pos + start) as isize + offset; + let underline_end = (span_start_pos + start + sub_len) as isize + offset; for p in underline_start..underline_end { buffer.putc(row_num, - max_line_num_len + 3 + p, + max_line_num_len + 3 + p as usize, '^', Style::UnderlinePrimary); } @@ -1272,7 +1275,7 @@ impl EmitterWriter { if underline_start == underline_end { for p in underline_start-1..underline_start+1 { buffer.putc(row_num, - max_line_num_len + 3 + p, + max_line_num_len + 3 + p as usize, '-', Style::UnderlineSecondary); } @@ -1280,12 +1283,14 @@ impl EmitterWriter { // length of the code after substitution let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize }); + // length of the code to be substituted + let snippet_len = (span_end_pos - span_start_pos) as isize; // For multiple substitutions, use the position *after* the previous // substitutions have happened. - extra += full_sub_len - snippet_len; + offset += full_sub_len - snippet_len; } row_num += 1; } diff --git a/src/test/ui/impl-trait/impl-generic-mismatch.stderr b/src/test/ui/impl-trait/impl-generic-mismatch.stderr index e133d825ba01..d47adee424c0 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, _: &U) { } help: try removing the generic parameter and using `impl Trait` instead | LL | fn foo(&self, _: &impl Debug) { } - | + | -- ^^^^^^^^^^ error[E0643]: method `bar` has incompatible signature for trait --> $DIR/impl-generic-mismatch.rs:27:23 From 1c2abda671ace3935a70b9d4c44bf944e1d34189 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 24 May 2018 14:08:47 +0200 Subject: [PATCH 03/16] Add `Once::new` as a way of constructing a `Once` --- src/libstd/sync/once.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 6fd8b6a5bbae..138993e2271c 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -73,9 +73,10 @@ use thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related /// functionality. This type can only be constructed with the [`ONCE_INIT`] -/// value. +/// value or the equivalent [`Once::new`] constructor. /// /// [`ONCE_INIT`]: constant.ONCE_INIT.html +/// [`Once::new`]: struct.Once.html#method.new /// /// # Examples /// From 2a900e2b84f33a10ef810d6e986fc3d3be0c432d Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 24 May 2018 14:09:42 +0200 Subject: [PATCH 04/16] Update the `Once` docs to use `Once::new` --- src/libstd/sync/once.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 138993e2271c..7eb7be23128b 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -81,9 +81,9 @@ use thread::{self, Thread}; /// # Examples /// /// ``` -/// use std::sync::{Once, ONCE_INIT}; +/// use std::sync::Once; /// -/// static START: Once = ONCE_INIT; +/// static START: Once = Once::new(); /// /// START.call_once(|| { /// // run initialization here @@ -181,10 +181,10 @@ impl Once { /// # Examples /// /// ``` - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// /// static mut VAL: usize = 0; - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // Accessing a `static mut` is unsafe much of the time, but if we do so /// // in a synchronized fashion (e.g. write once or read all) then we're @@ -249,10 +249,10 @@ impl Once { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -432,10 +432,10 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -453,9 +453,9 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// INIT.call_once_force(|state| { /// assert!(!state.poisoned()); From 6a0806b75a6e7f98b07ef14804c6e9fbc1b7b9f4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 24 May 2018 14:51:33 +0200 Subject: [PATCH 05/16] Remove unused lowering field and method --- src/librustc/hir/lowering.rs | 399 ++++++++++++++++------------------- 1 file changed, 184 insertions(+), 215 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 02c2aa1c71ba..3dcd38afc054 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -82,10 +82,6 @@ pub struct LoweringContext<'a> { cstore: &'a CrateStore, - // As we walk the AST we must keep track of the current 'parent' def id (in - // the form of a DefIndex) so that if we create a new node which introduces - // a definition, then we can properly create the def id. - parent_def: Option, resolver: &'a mut Resolver, name_map: FxHashMap, @@ -205,7 +201,6 @@ pub fn lower_crate( crate_root: std_inject::injected_crate_name(), sess, cstore, - parent_def: None, resolver, name_map: FxHashMap(), items: BTreeMap::new(), @@ -885,22 +880,6 @@ impl<'a> LoweringContext<'a> { result } - fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T - where - F: FnOnce(&mut LoweringContext) -> T, - { - let old_def = self.parent_def; - self.parent_def = { - let defs = self.resolver.definitions(); - Some(defs.opt_def_index(parent_id).unwrap()) - }; - - let result = f(self); - - self.parent_def = old_def; - result - } - fn def_key(&mut self, id: DefId) -> DefKey { if id.is_local() { self.resolver.definitions().def_key(id.index) @@ -2461,74 +2440,72 @@ impl<'a> LoweringContext<'a> { } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { - self.with_parent_def(i.id, |this| { - let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id); - let trait_item_def_id = this.resolver.definitions().local_def_id(node_id); - - let (generics, node) = match i.node { - TraitItemKind::Const(ref ty, ref default) => ( - this.lower_generics(&i.generics, ImplTraitContext::Disallowed), - hir::TraitItemKind::Const( - this.lower_ty(ty, ImplTraitContext::Disallowed), - default - .as_ref() - .map(|x| this.lower_body(None, |this| this.lower_expr(x))), - ), + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id); + let trait_item_def_id = self.resolver.definitions().local_def_id(node_id); + + let (generics, node) = match i.node { + TraitItemKind::Const(ref ty, ref default) => ( + self.lower_generics(&i.generics, ImplTraitContext::Disallowed), + hir::TraitItemKind::Const( + self.lower_ty(ty, ImplTraitContext::Disallowed), + default + .as_ref() + .map(|x| self.lower_body(None, |this| this.lower_expr(x))), ), - TraitItemKind::Method(ref sig, None) => { - let names = this.lower_fn_args_to_names(&sig.decl); - this.add_in_band_defs( - &i.generics, - trait_item_def_id, - AnonymousLifetimeMode::PassThrough, - |this| { - hir::TraitItemKind::Method( - this.lower_method_sig(sig, trait_item_def_id, false), - hir::TraitMethod::Required(names), - ) - }, - ) - } - TraitItemKind::Method(ref sig, Some(ref body)) => { - let body_id = this.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) - }); + ), + TraitItemKind::Method(ref sig, None) => { + let names = self.lower_fn_args_to_names(&sig.decl); + self.add_in_band_defs( + &i.generics, + trait_item_def_id, + AnonymousLifetimeMode::PassThrough, + |this| { + hir::TraitItemKind::Method( + this.lower_method_sig(sig, trait_item_def_id, false), + hir::TraitMethod::Required(names), + ) + }, + ) + } + TraitItemKind::Method(ref sig, Some(ref body)) => { + let body_id = self.lower_body(Some(&sig.decl), |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); - this.add_in_band_defs( - &i.generics, - trait_item_def_id, - AnonymousLifetimeMode::PassThrough, - |this| { - hir::TraitItemKind::Method( - this.lower_method_sig(sig, trait_item_def_id, false), - hir::TraitMethod::Provided(body_id), - ) - }, - ) - } - TraitItemKind::Type(ref bounds, ref default) => ( - this.lower_generics(&i.generics, ImplTraitContext::Disallowed), - hir::TraitItemKind::Type( - this.lower_bounds(bounds, ImplTraitContext::Disallowed), - default - .as_ref() - .map(|x| this.lower_ty(x, ImplTraitContext::Disallowed)), - ), + self.add_in_band_defs( + &i.generics, + trait_item_def_id, + AnonymousLifetimeMode::PassThrough, + |this| { + hir::TraitItemKind::Method( + this.lower_method_sig(sig, trait_item_def_id, false), + hir::TraitMethod::Provided(body_id), + ) + }, + ) + } + TraitItemKind::Type(ref bounds, ref default) => ( + self.lower_generics(&i.generics, ImplTraitContext::Disallowed), + hir::TraitItemKind::Type( + self.lower_bounds(bounds, ImplTraitContext::Disallowed), + default + .as_ref() + .map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)), ), - TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"), - }; + ), + TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"), + }; - hir::TraitItem { - id: node_id, - hir_id, - name: this.lower_ident(i.ident), - attrs: this.lower_attrs(&i.attrs), - generics, - node, - span: i.span, - } - }) + hir::TraitItem { + id: node_id, + hir_id, + name: self.lower_ident(i.ident), + attrs: self.lower_attrs(&i.attrs), + generics, + node, + span: i.span, + } } fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef { @@ -2557,63 +2534,61 @@ impl<'a> LoweringContext<'a> { } fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { - self.with_parent_def(i.id, |this| { - let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id); - let impl_item_def_id = this.resolver.definitions().local_def_id(node_id); + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id); + let impl_item_def_id = self.resolver.definitions().local_def_id(node_id); + + let (generics, node) = match i.node { + ImplItemKind::Const(ref ty, ref expr) => { + let body_id = self.lower_body(None, |this| this.lower_expr(expr)); + ( + self.lower_generics(&i.generics, ImplTraitContext::Disallowed), + hir::ImplItemKind::Const( + self.lower_ty(ty, ImplTraitContext::Disallowed), + body_id, + ), + ) + } + ImplItemKind::Method(ref sig, ref body) => { + let body_id = self.lower_body(Some(&sig.decl), |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); + let impl_trait_return_allow = !self.is_in_trait_impl; - let (generics, node) = match i.node { - ImplItemKind::Const(ref ty, ref expr) => { - let body_id = this.lower_body(None, |this| this.lower_expr(expr)); - ( - this.lower_generics(&i.generics, ImplTraitContext::Disallowed), - hir::ImplItemKind::Const( - this.lower_ty(ty, ImplTraitContext::Disallowed), + self.add_in_band_defs( + &i.generics, + impl_item_def_id, + AnonymousLifetimeMode::PassThrough, + |this| { + hir::ImplItemKind::Method( + this.lower_method_sig( + sig, + impl_item_def_id, + impl_trait_return_allow, + ), body_id, - ), - ) - } - ImplItemKind::Method(ref sig, ref body) => { - let body_id = this.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) - }); - let impl_trait_return_allow = !this.is_in_trait_impl; - - this.add_in_band_defs( - &i.generics, - impl_item_def_id, - AnonymousLifetimeMode::PassThrough, - |this| { - hir::ImplItemKind::Method( - this.lower_method_sig( - sig, - impl_item_def_id, - impl_trait_return_allow, - ), - body_id, - ) - }, - ) - } - ImplItemKind::Type(ref ty) => ( - this.lower_generics(&i.generics, ImplTraitContext::Disallowed), - hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)), - ), - ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), - }; - - hir::ImplItem { - id: node_id, - hir_id, - name: this.lower_ident(i.ident), - attrs: this.lower_attrs(&i.attrs), - generics, - vis: this.lower_visibility(&i.vis, None), - defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), - node, - span: i.span, + ) + }, + ) } - }) + ImplItemKind::Type(ref ty) => ( + self.lower_generics(&i.generics, ImplTraitContext::Disallowed), + hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)), + ), + ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), + }; + + hir::ImplItem { + id: node_id, + hir_id, + name: self.lower_ident(i.ident), + attrs: self.lower_attrs(&i.attrs), + generics, + vis: self.lower_visibility(&i.vis, None), + defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), + node, + span: i.span, + } // [1] since `default impl` is not yet implemented, this is always true in impls } @@ -2689,9 +2664,7 @@ impl<'a> LoweringContext<'a> { return None; } - let node = self.with_parent_def(i.id, |this| { - this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) - }); + let node = self.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node); let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id); @@ -2707,40 +2680,38 @@ impl<'a> LoweringContext<'a> { } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { - self.with_parent_def(i.id, |this| { - let node_id = this.lower_node_id(i.id).node_id; - let def_id = this.resolver.definitions().local_def_id(node_id); - hir::ForeignItem { - id: node_id, - name: i.ident.name, - attrs: this.lower_attrs(&i.attrs), - node: match i.node { - ForeignItemKind::Fn(ref fdec, ref generics) => { - let (generics, (fn_dec, fn_args)) = this.add_in_band_defs( - generics, - def_id, - AnonymousLifetimeMode::PassThrough, - |this| { - ( - // Disallow impl Trait in foreign items - this.lower_fn_decl(fdec, None, false), - this.lower_fn_args_to_names(fdec), - ) - }, - ); + let node_id = self.lower_node_id(i.id).node_id; + let def_id = self.resolver.definitions().local_def_id(node_id); + hir::ForeignItem { + id: node_id, + name: i.ident.name, + attrs: self.lower_attrs(&i.attrs), + node: match i.node { + ForeignItemKind::Fn(ref fdec, ref generics) => { + let (generics, (fn_dec, fn_args)) = self.add_in_band_defs( + generics, + def_id, + AnonymousLifetimeMode::PassThrough, + |this| { + ( + // Disallow impl Trait in foreign items + this.lower_fn_decl(fdec, None, false), + this.lower_fn_args_to_names(fdec), + ) + }, + ); - hir::ForeignItemFn(fn_dec, fn_args, generics) - } - ForeignItemKind::Static(ref t, m) => { - hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m) - } - ForeignItemKind::Ty => hir::ForeignItemType, - ForeignItemKind::Macro(_) => panic!("shouldn't exist here"), - }, - vis: this.lower_visibility(&i.vis, None), - span: i.span, - } - }) + hir::ForeignItemFn(fn_dec, fn_args, generics) + } + ForeignItemKind::Static(ref t, m) => { + hir::ForeignItemStatic(self.lower_ty(t, ImplTraitContext::Disallowed), m) + } + ForeignItemKind::Ty => hir::ForeignItemType, + ForeignItemKind::Macro(_) => panic!("shouldn't exist here"), + }, + vis: self.lower_visibility(&i.vis, None), + span: i.span, + } } fn lower_method_sig( @@ -3064,46 +3035,44 @@ impl<'a> LoweringContext<'a> { ), ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => { self.with_new_scopes(|this| { - this.with_parent_def(e.id, |this| { - let mut is_generator = false; - let body_id = this.lower_body(Some(decl), |this| { - let e = this.lower_expr(body); - is_generator = this.is_generator; - e - }); - let generator_option = if is_generator { - if !decl.inputs.is_empty() { - span_err!( - this.sess, - fn_decl_span, - E0628, - "generators cannot have explicit arguments" - ); - this.sess.abort_if_errors(); - } - Some(match movability { - Movability::Movable => hir::GeneratorMovability::Movable, - Movability::Static => hir::GeneratorMovability::Static, - }) - } else { - if movability == Movability::Static { - span_err!( - this.sess, - fn_decl_span, - E0906, - "closures cannot be static" - ); - } - None - }; - hir::ExprClosure( - this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl, None, false), - body_id, - fn_decl_span, - generator_option, - ) - }) + let mut is_generator = false; + let body_id = this.lower_body(Some(decl), |this| { + let e = this.lower_expr(body); + is_generator = this.is_generator; + e + }); + let generator_option = if is_generator { + if !decl.inputs.is_empty() { + span_err!( + this.sess, + fn_decl_span, + E0628, + "generators cannot have explicit arguments" + ); + this.sess.abort_if_errors(); + } + Some(match movability { + Movability::Movable => hir::GeneratorMovability::Movable, + Movability::Static => hir::GeneratorMovability::Static, + }) + } else { + if movability == Movability::Static { + span_err!( + this.sess, + fn_decl_span, + E0906, + "closures cannot be static" + ); + } + None + }; + hir::ExprClosure( + this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl, None, false), + body_id, + fn_decl_span, + generator_option, + ) }) } ExprKind::Block(ref blk, opt_label) => { From f36c643d4ff76f5d96304d31bdde45152e4e602e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 24 May 2018 10:01:13 -0700 Subject: [PATCH 06/16] Fix impl Trait suggestion --- src/librustc_typeck/check/compare_method.rs | 2 +- src/test/ui/impl-trait/impl-generic-mismatch.stderr | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index d185bc6f300a..808c134e9944 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -777,7 +777,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let new_generics_span = tcx .sess .codemap() - .generate_fn_name_span(impl_m.span)? + .generate_fn_name_span(impl_span)? .shrink_to_hi(); // in case there are generics, just replace them let generics_span = impl_m diff --git a/src/test/ui/impl-trait/impl-generic-mismatch.stderr b/src/test/ui/impl-trait/impl-generic-mismatch.stderr index d47adee424c0..a5f1580b60d2 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch.stderr @@ -21,12 +21,8 @@ LL | fn bar(&self, _: &impl Debug) { } | ^^^^^^^^^^ expected generic parameter, found `impl Trait` help: try changing the `impl Trait` argument to a generic parameter | -LL | fn bar(&self, _: &U); -LL | } -LL | -LL | impl Bar for () { -LL | fn bar(&self, _: &U) { } - | +LL | fn bar(&self, _: &U) { } + | ^^^^^^^^^^ ^ error[E0643]: method `hash` has incompatible signature for trait --> $DIR/impl-generic-mismatch.rs:38:33 From fe9a19580cd12adc2d0483bb549140fc6566a57e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 May 2018 01:02:22 +0200 Subject: [PATCH 07/16] Add documentation about env! second argument --- src/libstd/macros.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index d1274a409008..8da70f5717e7 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -364,7 +364,6 @@ pub mod builtin { /// /// let s = fmt::format(format_args!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world")); - /// /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] @@ -379,7 +378,7 @@ pub mod builtin { /// compile time, yielding an expression of type `&'static str`. /// /// If the environment variable is not defined, then a compilation error - /// will be emitted. To not emit a compile error, use the [`option_env!`] + /// will be emitted. To not emit a compile error, use the [`option_env!`] /// macro instead. /// /// [`option_env!`]: ../std/macro.option_env.html @@ -390,6 +389,20 @@ pub mod builtin { /// let path: &'static str = env!("PATH"); /// println!("the $PATH variable at the time of compiling was: {}", path); /// ``` + /// + /// You can customize the error message by passing a string as the second + /// parameter: + /// + /// ```compile_fail + /// let doc: &'static str = env!("documentation", "what's that?!"); + /// ``` + /// + /// If the `documentation` environment variable is not defined, you'll get + /// the following error: + /// + /// ```text + /// error: what's that?! + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] macro_rules! env { From 6ff940963715b6d7f2e3f243441c81f2a3ebdd89 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 May 2018 22:26:58 +0200 Subject: [PATCH 08/16] Add more missing examples for Formatter --- src/libcore/fmt/mod.rs | 81 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 5820fe58932c..1dc0faa156d6 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1202,6 +1202,23 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignores the `flag` parameters. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// formatter.pad("Foo") + /// } + /// } + /// + /// assert_eq!(&format!("{:<4}", Foo), "Foo "); + /// assert_eq!(&format!("{:0>4}", Foo), "0Foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front @@ -1368,7 +1385,7 @@ impl<'a> Formatter<'a> { self.buf.write_str(data) } - /// Writes some formatted information into this instance + /// Writes some formatted information into this instance. #[stable(feature = "rust1", since = "1.0.0")] pub fn write_fmt(&mut self, fmt: Arguments) -> Result { write(self.buf, fmt) @@ -1381,11 +1398,69 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead")] pub fn flags(&self) -> u32 { self.flags } - /// Character used as 'fill' whenever there is alignment + /// Character used as 'fill' whenever there is alignment. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let c = formatter.fill(); + /// if let Some(width) = formatter.width() { + /// for _ in 0..width { + /// write!(formatter, "{}", c)?; + /// } + /// Ok(()) + /// } else { + /// write!(formatter, "{}", c) + /// } + /// } + /// } + /// + /// // We set alignment to the left with ">". + /// assert_eq!(&format!("{:G>3}", Foo), "GGG"); + /// assert_eq!(&format!("{:t>6}", Foo), "tttttt"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { self.fill } - /// Flag indicating what form of alignment was requested + /// Flag indicating what form of alignment was requested. + /// + /// # Examples + /// + /// ``` + /// #![feature(fmt_flags_align)] + /// + /// extern crate core; + /// + /// use std::fmt; + /// use core::fmt::Alignment; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let s = match formatter.align() { + /// Alignment::Left => "left", + /// Alignment::Right => "right", + /// Alignment::Center => "center", + /// Alignment::Unknown => "into the void", + /// }; + /// write!(formatter, "{}", s) + /// } + /// } + /// + /// fn main() { + /// assert_eq!(&format!("{:<}", Foo), "left"); + /// assert_eq!(&format!("{:>}", Foo), "right"); + /// assert_eq!(&format!("{:^}", Foo), "center"); + /// assert_eq!(&format!("{}", Foo), "into the void"); + /// } + /// ``` #[unstable(feature = "fmt_flags_align", reason = "method was just created", issue = "27726")] pub fn align(&self) -> Alignment { From 8429d11a0b80dfaf8a79fb0d5e9bb5fd50455712 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 24 May 2018 18:52:01 -0300 Subject: [PATCH 09/16] Use AllFacts from polonius-engine --- src/Cargo.lock | 8 +++ src/librustc/Cargo.toml | 1 + src/librustc/lib.rs | 1 + src/librustc/ty/sty.rs | 19 ++++++ src/librustc_mir/Cargo.toml | 1 + src/librustc_mir/borrow_check/nll/facts.rs | 73 ++++++++++++++------- src/librustc_mir/borrow_check/nll/mod.rs | 1 + src/librustc_mir/dataflow/move_paths/mod.rs | 2 +- src/librustc_mir/lib.rs | 1 + src/tools/tidy/src/deps.rs | 1 + 10 files changed, 82 insertions(+), 26 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 0392466956eb..ef545db1f299 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1424,6 +1424,11 @@ name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "polonius-engine" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1745,6 +1750,7 @@ dependencies = [ "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", @@ -2111,6 +2117,7 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", @@ -3107,6 +3114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum polonius-engine 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6201ffe79e3da53bd065fbec2a9b391e5a0dc21038b39bb300612ddc658eb7ee" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 8f9a8bd5c015..4223b49a5b4f 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" } jobserver = "0.1" lazy_static = "1.0.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } +polonius-engine = "0.1.1" proc_macro = { path = "../libproc_macro" } rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1d53a305193f..08e49ea94bf0 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -80,6 +80,7 @@ extern crate graphviz; #[macro_use] extern crate lazy_static; #[cfg(windows)] extern crate libc; +extern crate polonius_engine; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate serialize; diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index faf93ab30b70..5980e19e6999 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -14,6 +14,7 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use middle::region; +use polonius_engine::Atom; use rustc_data_structures::indexed_vec::Idx; use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; @@ -1169,6 +1170,24 @@ newtype_index!(RegionVid DEBUG_FORMAT = custom, }); +impl Atom for RegionVid { + fn index(self) -> usize { + Idx::index(self) + } +} + +impl From for RegionVid { + fn from(i: usize) -> RegionVid { + RegionVid::new(i) + } +} + +impl From for usize { + fn from(vid: RegionVid) -> usize { + Idx::index(vid) + } +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 62964745b6f9..e88ff38ed7d3 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -14,6 +14,7 @@ bitflags = "1.0" graphviz = { path = "../libgraphviz" } log = "0.4" log_settings = "0.1.1" +polonius-engine = "0.1.1" rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs index 2b2aadba7f92..6cb8e64b9f5b 100644 --- a/src/librustc_mir/borrow_check/nll/facts.rs +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -10,41 +10,28 @@ use borrow_check::location::{LocationIndex, LocationTable}; use dataflow::indexes::BorrowIndex; +use polonius_engine::AllFacts as PoloniusAllFacts; +use polonius_engine::Atom; use rustc::ty::RegionVid; +use rustc_data_structures::indexed_vec::Idx; use std::error::Error; use std::fmt::Debug; use std::fs::{self, File}; use std::io::Write; use std::path::Path; -/// The "facts" which are the basis of the NLL borrow analysis. -#[derive(Default)] -crate struct AllFacts { - // `borrow_region(R, B, P)` -- the region R may refer to data from borrow B - // starting at the point P (this is usually the point *after* a borrow rvalue) - crate borrow_region: Vec<(RegionVid, BorrowIndex, LocationIndex)>, +crate type AllFacts = PoloniusAllFacts; - // universal_region(R) -- this is a "free region" within fn body - crate universal_region: Vec, - - // `cfg_edge(P,Q)` for each edge P -> Q in the control flow - crate cfg_edge: Vec<(LocationIndex, LocationIndex)>, - - // `killed(B,P)` when some prefix of the path borrowed at B is assigned at point P - crate killed: Vec<(BorrowIndex, LocationIndex)>, - - // `outlives(R1, R2, P)` when we require `R1@P: R2@P` - crate outlives: Vec<(RegionVid, RegionVid, LocationIndex)>, - - // `region_live_at(R, P)` when the region R appears in a live variable at P - crate region_live_at: Vec<(RegionVid, LocationIndex)>, - - // `invalidates(P, B)` when the borrow B is invalidated at point P - crate invalidates: Vec<(LocationIndex, BorrowIndex)>, +crate trait AllFactsExt { + fn write_to_dir( + &self, + dir: impl AsRef, + location_table: &LocationTable, + ) -> Result<(), Box>; } -impl AllFacts { - crate fn write_to_dir( +impl AllFactsExt for AllFacts { + fn write_to_dir( &self, dir: impl AsRef, location_table: &LocationTable, @@ -79,6 +66,42 @@ impl AllFacts { } } +impl Atom for BorrowIndex { + fn index(self) -> usize { + Idx::index(self) + } +} + +impl From for BorrowIndex { + fn from(i: usize) -> BorrowIndex { + BorrowIndex::new(i) + } +} + +impl From for usize { + fn from(vid: BorrowIndex) -> usize { + Idx::index(vid) + } +} + +impl Atom for LocationIndex { + fn index(self) -> usize { + Idx::index(self) + } +} + +impl From for LocationIndex { + fn from(i: usize) -> LocationIndex { + LocationIndex::new(i) + } +} + +impl From for usize { + fn from(vid: LocationIndex) -> usize { + Idx::index(vid) + } +} + struct FactWriter<'w> { location_table: &'w LocationTable, dir: &'w Path, diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 04e23c6f041e..a91789733a95 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -10,6 +10,7 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFactsExt; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 3a49e28f0418..610963af9e13 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -34,7 +34,7 @@ pub(crate) mod indexes { macro_rules! new_index { ($Index:ident, $debug_name:expr) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct $Index(NonZeroUsize); impl Idx for $Index { diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 3bf9453fb513..ace4709ba1d6 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -39,6 +39,7 @@ extern crate arena; extern crate bitflags; #[macro_use] extern crate log; extern crate graphviz as dot; +extern crate polonius_engine; #[macro_use] extern crate rustc; #[macro_use] extern crate rustc_data_structures; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 5739ec5f3251..ab323843bf4d 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -94,6 +94,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("owning_ref"), Crate("parking_lot"), Crate("parking_lot_core"), + Crate("polonius-engine"), Crate("quick-error"), Crate("rand"), Crate("redox_syscall"), From de12d437c98af98fa91c5bc476141ee9ffca7b3c Mon Sep 17 00:00:00 2001 From: Jaro Fietz Date: Fri, 25 May 2018 16:48:55 +0200 Subject: [PATCH 10/16] What does an expression look like, that consists only of special characters? --- src/test/run-pass/weird-exprs.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index ecb62b1888dd..254d84dde605 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -112,6 +112,12 @@ fn union() { union union<'union> { union: &'union union<'union>, } } +fn special_characters() { + let val = !((|(..):(_,_),__@_|__)((&*"\\",'@')/**/,{})=={&[..=..][..];})// + ; + assert!(!val); +} + pub fn main() { strange(); funny(); From 7c97203e2fa034fb641848768dc5be41a7e4513d Mon Sep 17 00:00:00 2001 From: Jaro Fietz Date: Fri, 25 May 2018 16:50:59 +0200 Subject: [PATCH 11/16] Call it --- src/test/run-pass/weird-exprs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index 254d84dde605..ec28cefe6553 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -131,4 +131,5 @@ pub fn main() { you_eight(); fishy(); union(); + special_characters(); } From 5ad84cf3fa988e47d5b6b058c2888de076881d5c Mon Sep 17 00:00:00 2001 From: Jaro Fietz Date: Fri, 25 May 2018 16:55:38 +0200 Subject: [PATCH 12/16] Don't use a char that's already used within the expr --- src/test/run-pass/weird-exprs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/weird-exprs.rs b/src/test/run-pass/weird-exprs.rs index ec28cefe6553..37ab2ea27150 100644 --- a/src/test/run-pass/weird-exprs.rs +++ b/src/test/run-pass/weird-exprs.rs @@ -113,7 +113,7 @@ fn union() { } fn special_characters() { - let val = !((|(..):(_,_),__@_|__)((&*"\\",'@')/**/,{})=={&[..=..][..];})// + let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})// ; assert!(!val); } From 37cbd11a9f864f6747ed9b4a3aab4c59ca2bae81 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 25 May 2018 11:47:48 -0700 Subject: [PATCH 13/16] Update nomicon link in transmute docs The list of "invalid primitive values" has moved to a different URL within the Rustonomicon. --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2e3f5cb65c92..95f13daf841e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -717,7 +717,7 @@ extern "rust-intrinsic" { /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, - /// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html). + /// may be an [invalid value](../../nomicon/what-unsafe-does.html). /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the source value into the From 91f7ae26b0b288f7c36fb52efa16e28d5b0c9d5f Mon Sep 17 00:00:00 2001 From: Martin Carton Date: Fri, 25 May 2018 22:55:33 +0200 Subject: [PATCH 14/16] Add inner links in documentation From [this SO question](https://stackoverflow.com/q/50518757/2733851) it looks like this page isn't really clear. I personally do think this page is quite clear, the only think I could think of was adding some references. --- src/liballoc/fmt.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index b2c4582e8406..a4e5373d9075 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -340,7 +340,8 @@ //! //! ## Fill/Alignment //! -//! The fill character is provided normally in conjunction with the `width` +//! The fill character is provided normally in conjunction with the +//! [`width`](#width) //! parameter. This indicates that if the value being formatted is smaller than //! `width` some extra characters will be printed around it. The extra //! characters are specified by `fill`, and the alignment can be one of the @@ -388,7 +389,8 @@ //! padding specified by fill/alignment will be used to take up the required //! space. //! -//! The default fill/alignment for non-numerics is a space and left-aligned. The +//! The default [fill/alignment](#fillalignment) for non-numerics is a space and +//! left-aligned. The //! defaults for numeric formatters is also a space but with right-alignment. If //! the `0` flag is specified for numerics, then the implicit fill character is //! `0`. From 5724dad82ed34f4461f58b3c035b1b06747d8669 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 26 May 2018 02:48:08 +0200 Subject: [PATCH 15/16] Fail typecheck if we encounter a bogus break Lone breaks outside of loops create errors in the loop check pass but as they are not fatal, compilation continues. MIR building code assumes all HIR break statements to point to valid locations and fires ICEs if this assumption is violated. In normal compilation, this causes no issues, as code apparently prevents MIR from being built if errors are present. However, before that, typecheck runs and with it MIR const eval. Here we operate differently from normal compilation: it doesn't check for any errors except for type checker ones and then directly builds the MIR. This constellation causes an ICE-on-error if bogus break statements are being put into array length expressions. This commit fixes this ICE by letting typecheck fail if bogus break statements are encountered. This way, MIR const eval fails cleanly with a type check error. Fixes #50576 Fixes #50581 --- src/librustc_typeck/check/mod.rs | 7 +++++-- src/test/compile-fail/issue-43162.rs | 1 + src/test/ui/issue-50576.rs | 16 ++++++++++++++++ src/test/ui/issue-50576.stderr | 22 ++++++++++++++++++++++ src/test/ui/issue-50581.rs | 13 +++++++++++++ src/test/ui/issue-50581.stderr | 9 +++++++++ 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/issue-50576.rs create mode 100644 src/test/ui/issue-50576.stderr create mode 100644 src/test/ui/issue-50581.rs create mode 100644 src/test/ui/issue-50581.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 70d299437a6e..16695dcef8f7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3764,6 +3764,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } ctxt.may_break = true; + + // the type of a `break` is always `!`, since it diverges + tcx.types.never } else { // Otherwise, we failed to find the enclosing loop; // this can only happen if the `break` was not @@ -3784,10 +3787,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + // There was an error, make typecheck fail + tcx.types.err } - // the type of a `break` is always `!`, since it diverges - tcx.types.never } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { diff --git a/src/test/compile-fail/issue-43162.rs b/src/test/compile-fail/issue-43162.rs index 8f4661299e9d..b236283f7576 100644 --- a/src/test/compile-fail/issue-43162.rs +++ b/src/test/compile-fail/issue-43162.rs @@ -9,6 +9,7 @@ // except according to those terms. fn foo() -> bool { + //~^ ERROR E0308 break true; //~ ERROR E0268 } diff --git a/src/test/ui/issue-50576.rs b/src/test/ui/issue-50576.rs new file mode 100644 index 000000000000..b2032fb226bd --- /dev/null +++ b/src/test/ui/issue-50576.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + |bool: [u8; break 'L]| 0; + //~^ ERROR [E0426] + //~| ERROR [E0268] + Vec::<[u8; break]>::new(); //~ ERROR [E0268] +} diff --git a/src/test/ui/issue-50576.stderr b/src/test/ui/issue-50576.stderr new file mode 100644 index 000000000000..e661be213390 --- /dev/null +++ b/src/test/ui/issue-50576.stderr @@ -0,0 +1,22 @@ +error[E0426]: use of undeclared label `'L` + --> $DIR/issue-50576.rs:12:23 + | +LL | |bool: [u8; break 'L]| 0; + | ^^ undeclared label `'L` + +error[E0268]: `break` outside of loop + --> $DIR/issue-50576.rs:12:17 + | +LL | |bool: [u8; break 'L]| 0; + | ^^^^^^^^ cannot break outside of a loop + +error[E0268]: `break` outside of loop + --> $DIR/issue-50576.rs:15:16 + | +LL | Vec::<[u8; break]>::new(); //~ ERROR [E0268] + | ^^^^^ cannot break outside of a loop + +error: aborting due to 3 previous errors + +Some errors occurred: E0268, E0426. +For more information about an error, try `rustc --explain E0268`. diff --git a/src/test/ui/issue-50581.rs b/src/test/ui/issue-50581.rs new file mode 100644 index 000000000000..97b3f81eaf5f --- /dev/null +++ b/src/test/ui/issue-50581.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + |_: [u8; break]| (); //~ ERROR [E0268] +} diff --git a/src/test/ui/issue-50581.stderr b/src/test/ui/issue-50581.stderr new file mode 100644 index 000000000000..38a87b1e78a1 --- /dev/null +++ b/src/test/ui/issue-50581.stderr @@ -0,0 +1,9 @@ +error[E0268]: `break` outside of loop + --> $DIR/issue-50581.rs:12:14 + | +LL | |_: [u8; break]| (); //~ ERROR [E0268] + | ^^^^^ cannot break outside of a loop + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0268`. From a49bc9ce5996b9cb0c49142f458a6612ef3c252c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 25 May 2018 19:44:07 -0700 Subject: [PATCH 16/16] Rename TokenStream::empty to TokenStream::new There is no precedent for the `empty` name -- we do not have `Vec::empty` or `HashMap::empty` etc. --- src/libproc_macro/lib.rs | 2 +- src/libproc_macro/quote.rs | 4 ++-- src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs | 2 +- src/test/run-pass-fulldeps/proc-macro/auxiliary/not-joint.rs | 4 ++-- src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index bcab61680965..35e2d6b23167 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -93,7 +93,7 @@ impl !Sync for LexError {} impl TokenStream { /// Returns an empty `TokenStream` containing no token trees. #[unstable(feature = "proc_macro", issue = "38356")] - pub fn empty() -> TokenStream { + pub fn new() -> TokenStream { TokenStream(tokenstream::TokenStream::empty()) } diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 390d4bc08682..c9d0bc1405fc 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -71,7 +71,7 @@ macro_rules! quote_tree { } macro_rules! quote { - () => { TokenStream::empty() }; + () => { TokenStream::new() }; ($($t:tt)*) => { [$(quote_tree!($t),)*].iter() .cloned() @@ -104,7 +104,7 @@ impl Quote for Option { impl Quote for TokenStream { fn quote(self) -> TokenStream { if self.is_empty() { - return quote!(::TokenStream::empty()); + return quote!(::TokenStream::new()); } let mut after_dollar = false; let tokens = self.into_iter().filter_map(|tree| { diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs index fb5057557923..c37682220da3 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/modify-ast.rs @@ -26,7 +26,7 @@ pub fn assert1(_a: TokenStream, b: TokenStream) -> TokenStream { #[proc_macro_derive(Foo, attributes(foo))] pub fn assert2(a: TokenStream) -> TokenStream { assert_eq(a, "pub struct MyStructc { _a: i32, }".parse().unwrap()); - TokenStream::empty() + TokenStream::new() } fn assert_eq(a: TokenStream, b: TokenStream) { diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/not-joint.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/not-joint.rs index 062a914534f1..a640fabe04fa 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/not-joint.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/not-joint.rs @@ -20,13 +20,13 @@ use proc_macro::*; #[proc_macro] pub fn tokens(input: TokenStream) -> TokenStream { assert_nothing_joint(input); - TokenStream::empty() + TokenStream::new() } #[proc_macro_attribute] pub fn nothing(_: TokenStream, input: TokenStream) -> TokenStream { assert_nothing_joint(input); - TokenStream::empty() + TokenStream::new() } fn assert_nothing_joint(s: TokenStream) { diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs index 8dfb9cb4fb75..5b8fcab0baaa 100644 --- a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs @@ -50,7 +50,7 @@ fn parse(input: TokenStream) -> Result<(), Diagnostic> { pub fn three_equals(input: TokenStream) -> TokenStream { if let Err(diag) = parse(input) { diag.emit(); - return TokenStream::empty(); + return TokenStream::new(); } "3".parse().unwrap()