From 738b0f30f29d649e004904df28b1339dcd124a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Feb 2017 17:54:56 -0800 Subject: [PATCH 01/18] Clean up "pattern doesn't bind x" messages Group "missing variable bind" spans in `or` matches and clarify wording for the two possible cases: when a variable from the first pattern is not in any of the subsequent patterns, and when a variable in any of the other patterns is not in the first one. Before: ``` error[E0408]: variable `a` from pattern #1 is not bound in pattern #2 --> file.rs:10:23 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^^^^ pattern doesn't bind `a` error[E0408]: variable `b` from pattern #2 is not bound in pattern #1 --> file.rs:10:32 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^ pattern doesn't bind `b` error[E0408]: variable `a` from pattern #1 is not bound in pattern #3 --> file.rs:10:37 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^ pattern doesn't bind `a` error[E0408]: variable `d` from pattern #1 is not bound in pattern #3 --> file.rs:10:37 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^ pattern doesn't bind `d` error[E0408]: variable `c` from pattern #3 is not bound in pattern #1 --> file.rs:10:43 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^ pattern doesn't bind `c` error[E0408]: variable `d` from pattern #1 is not bound in pattern #4 --> file.rs:10:48 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^ pattern doesn't bind `d` error: aborting due to 6 previous errors ``` After: ``` error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4 --> file.rs:10:37 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` | | | | missing variable pattern doesn't bind `d` error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 --> file.rs:10:23 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | - ^^^^^^^^^^^ ^^^^^^^^ pattern doesn't bind `a` | | | | | pattern doesn't bind `a` | missing variable error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1 --> file.rs:10:32 | 10 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ----------- ^ ^ missing variable | | | | | missing variable | pattern does't bind `b`, `c` error: aborting due to 3 previous errors ``` --- src/librustc_resolve/lib.rs | 88 +++++++++++++++---- src/test/compile-fail/E0408.rs | 3 +- src/test/compile-fail/issue-2848.rs | 3 +- src/test/compile-fail/issue-2849.rs | 2 +- .../resolve-inconsistent-names.rs | 6 +- src/test/ui/span/issue-39698.rs | 22 +++++ src/test/ui/span/issue-39698.stderr | 29 ++++++ 7 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/span/issue-39698.rs create mode 100644 src/test/ui/span/issue-39698.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 676ff98e602d6..9736bd9ae22d2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -109,8 +109,10 @@ enum ResolutionError<'a> { TypeNotMemberOfTrait(Name, &'a str), /// error E0438: const is not a member of trait ConstNotMemberOfTrait(Name, &'a str), - /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} - VariableNotBoundInPattern(Name, usize, usize), + /// error E0408: variable `{}` from pattern #{} is not bound in pattern #1 + VariableNotBoundInPattern(Name, Span, Vec<(Span, usize)>), + /// error E0408: variable `{}` from pattern #1 is not bound in pattern #{} + VariableNotBoundInFirstPattern(Span, Vec<(Name, usize, Span)>), /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 VariableBoundWithDifferentMode(Name, usize, Span), /// error E0415: identifier is bound more than once in this parameter list @@ -204,15 +206,53 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } - ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => { - let mut err = struct_span_err!(resolver.session, - span, - E0408, - "variable `{}` from pattern #{} is not bound in pattern #{}", - variable_name, - from, - to); - err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name)); + ResolutionError::VariableNotBoundInPattern(variable_name, sp, missing_vars) => { + let spans: Vec<_> = missing_vars.iter().map(|x| x.0).collect(); + let msp = MultiSpan::from_spans(spans.clone()); + // "variable `a` from pattern #1 is not bound in patterns #2, #3" + let msg = format!("variable `{}` from pattern #1 isn't bound in pattern{} {}", + variable_name, + if spans.len() > 1 { + "s" + } else { + "" + }, + missing_vars.iter() + .map(|x| format!("#{}", x.1)) + .collect::>() + .join(", ")); + let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); + for sp in spans { + err.span_label(sp, &format!("pattern doesn't bind `{}`", variable_name)); + } + err.span_label(sp, &"variable not in all patterns"); + err + } + ResolutionError::VariableNotBoundInFirstPattern(sp, extra_vars) => { + let spans: Vec<_> = extra_vars.iter().map(|x| x.2).collect(); + let msp = MultiSpan::from_spans(spans.clone()); + // "variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern + // #1" + let msg = format!("{} {}n't bound in pattern #1", + extra_vars.iter() + .map(|x| format!("variable `{}` from pattern #{}", x.0, x.1)) + .collect::>() + .join(", "), + if spans.len() > 1 { + "are" + } else { + "is" + }); + let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); + for sp in spans { + err.span_label(sp, &"variable not in all patterns"); + } + err.span_label(sp, + &format!("pattern doesn't bind {}", + extra_vars.iter() + .map(|x| format!("`{}`", x.0)) + .collect::>() + .join(", "))); err } ResolutionError::VariableBoundWithDifferentMode(variable_name, @@ -324,7 +364,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, binding_mode: BindingMode, @@ -1867,14 +1907,20 @@ impl<'a> Resolver<'a> { return; } let map_0 = self.binding_mode_map(&arm.pats[0]); + + let mut missing_vars = FxHashMap(); + let mut extra_vars = vec![]; + for (i, p) in arm.pats.iter().enumerate() { let map_i = self.binding_mode_map(&p); for (&key, &binding_0) in &map_0 { match map_i.get(&key) { None => { - let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1); - resolve_error(self, p.span, error); + let spans = missing_vars + .entry((key.name, binding_0.span)) + .or_insert(vec![]); + spans.push((p.span, i + 1)); } Some(binding_i) => { if binding_0.binding_mode != binding_i.binding_mode { @@ -1891,12 +1937,20 @@ impl<'a> Resolver<'a> { for (&key, &binding) in &map_i { if !map_0.contains_key(&key) { - resolve_error(self, - binding.span, - ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1)); + extra_vars.push((key.name, i + 1, binding.span)); } } } + for (k, v) in missing_vars { + let (name, sp) = k; + resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v)); + } + if extra_vars.len() > 0 { + resolve_error(self, + arm.pats[0].span, + ResolutionError::VariableNotBoundInFirstPattern(arm.pats[0].span, + extra_vars)); + } } fn resolve_arm(&mut self, arm: &Arm) { diff --git a/src/test/compile-fail/E0408.rs b/src/test/compile-fail/E0408.rs index d75f612482772..4d96ff30c0b7b 100644 --- a/src/test/compile-fail/E0408.rs +++ b/src/test/compile-fail/E0408.rs @@ -12,7 +12,8 @@ fn main() { let x = Some(0); match x { - Some(y) | None => {} //~ ERROR variable `y` from pattern #1 is not bound in pattern #2 + Some(y) | None => {} //~ ERROR variable `y` from pattern #1 isn't bound in pattern #2 _ => () //~| NOTE pattern doesn't bind `y` + //~| NOTE variable not in all patterns } } diff --git a/src/test/compile-fail/issue-2848.rs b/src/test/compile-fail/issue-2848.rs index f5e0c545bb524..e7644952f23e2 100644 --- a/src/test/compile-fail/issue-2848.rs +++ b/src/test/compile-fail/issue-2848.rs @@ -19,7 +19,8 @@ mod bar { fn main() { use bar::foo::{alpha, charlie}; match alpha { - alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1 + alpha | beta => {} //~ ERROR variable `beta` from pattern #2 isn't bound in pattern #1 charlie => {} //~| NOTE pattern doesn't bind `beta` + //~| NOTE variable not in all patterns } } diff --git a/src/test/compile-fail/issue-2849.rs b/src/test/compile-fail/issue-2849.rs index 48f4cac9711a8..828b8990363f9 100644 --- a/src/test/compile-fail/issue-2849.rs +++ b/src/test/compile-fail/issue-2849.rs @@ -13,6 +13,6 @@ enum foo { alpha, beta(isize) } fn main() { match foo::alpha { foo::alpha | foo::beta(i) => {} - //~^ ERROR variable `i` from pattern #2 is not bound in pattern #1 + //~^ ERROR variable `i` from pattern #2 isn't bound in pattern #1 } } diff --git a/src/test/compile-fail/resolve-inconsistent-names.rs b/src/test/compile-fail/resolve-inconsistent-names.rs index 1e2541502ace8..fbe106d66d2e5 100644 --- a/src/test/compile-fail/resolve-inconsistent-names.rs +++ b/src/test/compile-fail/resolve-inconsistent-names.rs @@ -11,9 +11,11 @@ fn main() { let y = 1; match y { - a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2 - //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1 + a | b => {} //~ ERROR variable `a` from pattern #1 isn't bound in pattern #2 + //~^ ERROR variable `b` from pattern #2 isn't bound in pattern #1 //~| NOTE pattern doesn't bind `a` //~| NOTE pattern doesn't bind `b` + //~| NOTE variable not in all patterns + //~| NOTE variable not in all patterns } } diff --git a/src/test/ui/span/issue-39698.rs b/src/test/ui/span/issue-39698.rs new file mode 100644 index 0000000000000..17b3f1c5a885e --- /dev/null +++ b/src/test/ui/span/issue-39698.rs @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +enum T { + T1(i32, i32), + T2(i32, i32), + T3(i32), + T4(i32), +} + +fn main() { + match T::T1(123, 456) { + T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + } +} diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr new file mode 100644 index 0000000000000..2aed3386d3b41 --- /dev/null +++ b/src/test/ui/span/issue-39698.stderr @@ -0,0 +1,29 @@ +error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4 + --> $DIR/issue-39698.rs:20:37 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` + | | | + | | pattern doesn't bind `d` + | variable not in all patterns + +error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 + --> $DIR/issue-39698.rs:20:23 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | - ^^^^^^^^^^^ ^^^^^^^^ pattern doesn't bind `a` + | | | + | | pattern doesn't bind `a` + | variable not in all patterns + +error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1 + --> $DIR/issue-39698.rs:20:32 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | ----------- ^ ^ variable not in all patterns + | | | + | | variable not in all patterns + | pattern doesn't bind `b`, `c` + +error: aborting due to 3 previous errors + From 0d46cfe08473bc0f58c6c940961c33aca944d161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Feb 2017 20:40:05 -0800 Subject: [PATCH 02/18] Have only one presentation for binding consistency errors --- src/librustc_resolve/lib.rs | 88 +++++++++-------------------- src/test/ui/span/issue-39698.stderr | 53 +++++++++++++---- 2 files changed, 68 insertions(+), 73 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9736bd9ae22d2..da5bc4701ed27 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -109,10 +109,8 @@ enum ResolutionError<'a> { TypeNotMemberOfTrait(Name, &'a str), /// error E0438: const is not a member of trait ConstNotMemberOfTrait(Name, &'a str), - /// error E0408: variable `{}` from pattern #{} is not bound in pattern #1 + /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} VariableNotBoundInPattern(Name, Span, Vec<(Span, usize)>), - /// error E0408: variable `{}` from pattern #1 is not bound in pattern #{} - VariableNotBoundInFirstPattern(Span, Vec<(Name, usize, Span)>), /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 VariableBoundWithDifferentMode(Name, usize, Span), /// error E0415: identifier is bound more than once in this parameter list @@ -228,33 +226,6 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(sp, &"variable not in all patterns"); err } - ResolutionError::VariableNotBoundInFirstPattern(sp, extra_vars) => { - let spans: Vec<_> = extra_vars.iter().map(|x| x.2).collect(); - let msp = MultiSpan::from_spans(spans.clone()); - // "variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern - // #1" - let msg = format!("{} {}n't bound in pattern #1", - extra_vars.iter() - .map(|x| format!("variable `{}` from pattern #{}", x.0, x.1)) - .collect::>() - .join(", "), - if spans.len() > 1 { - "are" - } else { - "is" - }); - let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); - for sp in spans { - err.span_label(sp, &"variable not in all patterns"); - } - err.span_label(sp, - &format!("pattern doesn't bind {}", - extra_vars.iter() - .map(|x| format!("`{}`", x.0)) - .collect::>() - .join(", "))); - err - } ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number, first_binding_span) => { @@ -1906,51 +1877,46 @@ impl<'a> Resolver<'a> { if arm.pats.is_empty() { return; } - let map_0 = self.binding_mode_map(&arm.pats[0]); let mut missing_vars = FxHashMap(); - let mut extra_vars = vec![]; - for (i, p) in arm.pats.iter().enumerate() { let map_i = self.binding_mode_map(&p); - for (&key, &binding_0) in &map_0 { - match map_i.get(&key) { - None => { - let spans = missing_vars - .entry((key.name, binding_0.span)) - .or_insert(vec![]); - spans.push((p.span, i + 1)); - } - Some(binding_i) => { - if binding_0.binding_mode != binding_i.binding_mode { - resolve_error(self, - binding_i.span, - ResolutionError::VariableBoundWithDifferentMode( - key.name, - i + 1, - binding_0.span)); - } - } + for (j, q) in arm.pats.iter().enumerate() { + if i == j { + continue; } - } - for (&key, &binding) in &map_i { - if !map_0.contains_key(&key) { - extra_vars.push((key.name, i + 1, binding.span)); + let map_j = self.binding_mode_map(&q); + for (&key, &binding_i) in &map_i { + for (&key_j, &binding_j) in &map_j { + match map_i.get(&key_j) { + None => { // missing binding + let spans = missing_vars + .entry((key_j.name, binding_j.span)) + .or_insert(FxHashMap()); + spans.entry((p.span, i + 1)).or_insert(Some(())); + } + Some(binding_j) => { // check consistent binding + if binding_i.binding_mode != binding_j.binding_mode { + resolve_error(self, + binding_i.span, + ResolutionError::VariableBoundWithDifferentMode( + key.name, + i + 1, + binding_i.span)); + } + } + } + } } } } for (k, v) in missing_vars { let (name, sp) = k; + let v = v.iter().map(|x| *x.0).collect::>(); resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v)); } - if extra_vars.len() > 0 { - resolve_error(self, - arm.pats[0].span, - ResolutionError::VariableNotBoundInFirstPattern(arm.pats[0].span, - extra_vars)); - } } fn resolve_arm(&mut self, arm: &Arm) { diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr index 2aed3386d3b41..3e10f26aa8743 100644 --- a/src/test/ui/span/issue-39698.stderr +++ b/src/test/ui/span/issue-39698.stderr @@ -1,11 +1,11 @@ -error[E0408]: variable `d` from pattern #1 isn't bound in patterns #3, #4 - --> $DIR/issue-39698.rs:20:37 +error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 + --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` - | | | - | | pattern doesn't bind `d` - | variable not in all patterns + | ^^^^^^^^^^^ ^^^^^^^^ - variable not in all patterns + | | | + | | pattern doesn't bind `a` + | pattern doesn't bind `a` error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 --> $DIR/issue-39698.rs:20:23 @@ -16,14 +16,43 @@ error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 | | pattern doesn't bind `a` | variable not in all patterns -error[E0408]: variable `b` from pattern #2, variable `c` from pattern #3 aren't bound in pattern #1 - --> $DIR/issue-39698.rs:20:32 +error[E0408]: variable `c` from pattern #1 isn't bound in patterns #2, #4, #1 + --> $DIR/issue-39698.rs:20:23 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` + | | | | + | | | variable not in all patterns + | | pattern doesn't bind `c` + | pattern doesn't bind `c` + +error[E0408]: variable `d` from pattern #1 isn't bound in patterns #4, #3 + --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ----------- ^ ^ variable not in all patterns - | | | + | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` + | | | + | | pattern doesn't bind `d` + | variable not in all patterns + +error[E0408]: variable `b` from pattern #1 isn't bound in patterns #4, #3, #1 + --> $DIR/issue-39698.rs:20:48 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `b` + | | | | + | | | pattern doesn't bind `b` | | variable not in all patterns - | pattern doesn't bind `b`, `c` + | pattern doesn't bind `b` + +error[E0408]: variable `d` from pattern #1 isn't bound in patterns #4, #3 + --> $DIR/issue-39698.rs:20:48 + | +20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } + | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` + | | | + | | pattern doesn't bind `d` + | variable not in all patterns -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors From fa3e19f4e3627cac2ca674c56c555b92f7cd8736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Feb 2017 21:16:49 -0800 Subject: [PATCH 03/18] fix --- src/librustc_resolve/lib.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index da5bc4701ed27..eff4087aa1124 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1879,6 +1879,7 @@ impl<'a> Resolver<'a> { } let mut missing_vars = FxHashMap(); + let mut inconsistent_vars = FxHashMap(); for (i, p) in arm.pats.iter().enumerate() { let map_i = self.binding_mode_map(&p); @@ -1889,22 +1890,27 @@ impl<'a> Resolver<'a> { let map_j = self.binding_mode_map(&q); for (&key, &binding_i) in &map_i { + if map_j.len() == 0 { // Account for missing bindings when + let spans = missing_vars // map_j has none. + .entry((key.name, binding_i.span)) + .or_insert(FxHashSet()); + spans.insert((q.span, i + 1)); + } for (&key_j, &binding_j) in &map_j { match map_i.get(&key_j) { None => { // missing binding let spans = missing_vars .entry((key_j.name, binding_j.span)) - .or_insert(FxHashMap()); - spans.entry((p.span, i + 1)).or_insert(Some(())); + .or_insert(FxHashSet()); + spans.insert((p.span, i + 1)); } - Some(binding_j) => { // check consistent binding + Some(binding_i) => { // check consistent binding if binding_i.binding_mode != binding_j.binding_mode { - resolve_error(self, - binding_i.span, - ResolutionError::VariableBoundWithDifferentMode( - key.name, - i + 1, - binding_i.span)); + inconsistent_vars + .entry(key.name) + .or_insert((binding_j.span, + binding_i.span, + i + 1)); } } } @@ -1914,9 +1920,12 @@ impl<'a> Resolver<'a> { } for (k, v) in missing_vars { let (name, sp) = k; - let v = v.iter().map(|x| *x.0).collect::>(); + let v = v.iter().map(|x| *x).collect::>(); resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v)); } + for (k, v) in inconsistent_vars { + resolve_error(self,v.0, ResolutionError::VariableBoundWithDifferentMode(k, v.2, v.1)); + } } fn resolve_arm(&mut self, arm: &Arm) { From 0e6248d815eb0221d588558516b9623e1c12b495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Feb 2017 14:05:59 -0800 Subject: [PATCH 04/18] Point to same binding in multiple patterns when possible --- src/librustc_resolve/lib.rs | 78 ++++++++++++++++++----------- src/test/ui/span/issue-39698.stderr | 62 +++++++++-------------- 2 files changed, 71 insertions(+), 69 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index eff4087aa1124..fe88eb9fd9283 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -96,6 +96,12 @@ enum AssocSuggestion { AssocItem, } +struct BindingError { + name: Name, + origin: FxHashSet<(Span, usize)>, + target: FxHashSet<(Span, usize)>, +} + enum ResolutionError<'a> { /// error E0401: can't use type parameters from outer function TypeParametersFromOuterFunction, @@ -110,7 +116,7 @@ enum ResolutionError<'a> { /// error E0438: const is not a member of trait ConstNotMemberOfTrait(Name, &'a str), /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} - VariableNotBoundInPattern(Name, Span, Vec<(Span, usize)>), + VariableNotBoundInPattern(BindingError), /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 VariableBoundWithDifferentMode(Name, usize, Span), /// error E0415: identifier is bound more than once in this parameter list @@ -204,26 +210,28 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } - ResolutionError::VariableNotBoundInPattern(variable_name, sp, missing_vars) => { - let spans: Vec<_> = missing_vars.iter().map(|x| x.0).collect(); - let msp = MultiSpan::from_spans(spans.clone()); - // "variable `a` from pattern #1 is not bound in patterns #2, #3" - let msg = format!("variable `{}` from pattern #1 isn't bound in pattern{} {}", - variable_name, - if spans.len() > 1 { - "s" - } else { - "" - }, - missing_vars.iter() + ResolutionError::VariableNotBoundInPattern(binding_error) => { + let msp = MultiSpan::from_spans(binding_error.target.iter().map(|x| x.0).collect()); + // "variable `a` from patterns #1, #4 isn't bound in patterns #2, #3" + let msg = format!("variable `{}` from pattern{} {} isn't bound in pattern{} {}", + binding_error.name, + if binding_error.origin.len() > 1 { "s" } else { "" }, + binding_error.origin.iter() + .map(|x| format!("#{}", x.1)) + .collect::>() + .join(", "), + if binding_error.target.len() > 1 { "s" } else { "" }, + binding_error.target.iter() .map(|x| format!("#{}", x.1)) .collect::>() .join(", ")); let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); - for sp in spans { - err.span_label(sp, &format!("pattern doesn't bind `{}`", variable_name)); + for (sp, _) in binding_error.target { + err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name)); + } + for (sp, _) in binding_error.origin { + err.span_label(sp, &"variable not in all patterns"); } - err.span_label(sp, &"variable not in all patterns"); err } ResolutionError::VariableBoundWithDifferentMode(variable_name, @@ -1890,19 +1898,29 @@ impl<'a> Resolver<'a> { let map_j = self.binding_mode_map(&q); for (&key, &binding_i) in &map_i { - if map_j.len() == 0 { // Account for missing bindings when - let spans = missing_vars // map_j has none. - .entry((key.name, binding_i.span)) - .or_insert(FxHashSet()); - spans.insert((q.span, i + 1)); + if map_j.len() == 0 { // Account for missing bindings when + let binding_error = missing_vars // map_j has none. + .entry(key.name) + .or_insert(BindingError { + name: key.name, + origin: FxHashSet(), + target: FxHashSet(), + }); + binding_error.origin.insert((binding_i.span, i + 1)); + binding_error.target.insert((q.span, j + 1)); } for (&key_j, &binding_j) in &map_j { match map_i.get(&key_j) { None => { // missing binding - let spans = missing_vars - .entry((key_j.name, binding_j.span)) - .or_insert(FxHashSet()); - spans.insert((p.span, i + 1)); + let binding_error = missing_vars + .entry(key_j.name) + .or_insert(BindingError { + name: key.name, + origin: FxHashSet(), + target: FxHashSet(), + }); + binding_error.origin.insert((binding_j.span, j + 1)); + binding_error.target.insert((p.span, i + 1)); } Some(binding_i) => { // check consistent binding if binding_i.binding_mode != binding_j.binding_mode { @@ -1918,13 +1936,13 @@ impl<'a> Resolver<'a> { } } } - for (k, v) in missing_vars { - let (name, sp) = k; - let v = v.iter().map(|x| *x).collect::>(); - resolve_error(self, sp, ResolutionError::VariableNotBoundInPattern(name, sp, v)); + for (_, v) in missing_vars { + resolve_error(self, + v.origin.iter().next().unwrap().0, + ResolutionError::VariableNotBoundInPattern(v)); } for (k, v) in inconsistent_vars { - resolve_error(self,v.0, ResolutionError::VariableBoundWithDifferentMode(k, v.2, v.1)); + resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(k, v.2, v.1)); } } diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr index 3e10f26aa8743..c2a212e94db53 100644 --- a/src/test/ui/span/issue-39698.stderr +++ b/src/test/ui/span/issue-39698.stderr @@ -1,58 +1,42 @@ -error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 - --> $DIR/issue-39698.rs:20:23 - | -20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ ^^^^^^^^ - variable not in all patterns - | | | - | | pattern doesn't bind `a` - | pattern doesn't bind `a` - -error[E0408]: variable `a` from pattern #1 isn't bound in patterns #2, #3 - --> $DIR/issue-39698.rs:20:23 +error[E0408]: variable `c` from patterns #2, #1 isn't bound in patterns #4, #3 + --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | - ^^^^^^^^^^^ ^^^^^^^^ pattern doesn't bind `a` - | | | - | | pattern doesn't bind `a` - | variable not in all patterns + | - - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `c` + | | | | + | | | pattern doesn't bind `c` + | | variable not in all patterns + | variable not in all patterns -error[E0408]: variable `c` from pattern #1 isn't bound in patterns #2, #4, #1 +error[E0408]: variable `d` from pattern #3 isn't bound in patterns #2, #4, #1 --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` + | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `d` | | | | | | | variable not in all patterns - | | pattern doesn't bind `c` - | pattern doesn't bind `c` + | | pattern doesn't bind `d` + | pattern doesn't bind `d` -error[E0408]: variable `d` from pattern #1 isn't bound in patterns #4, #3 - --> $DIR/issue-39698.rs:20:48 +error[E0408]: variable `b` from patterns #1, #4 isn't bound in patterns #2, #3 + --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` - | | | - | | pattern doesn't bind `d` - | variable not in all patterns + | - ^^^^^^^^^^^ ^^^^^^^^ - variable not in all patterns + | | | | + | | | pattern doesn't bind `b` + | | pattern doesn't bind `b` + | variable not in all patterns -error[E0408]: variable `b` from pattern #1 isn't bound in patterns #4, #3, #1 +error[E0408]: variable `d` from pattern #2 isn't bound in patterns #4, #3, #1 --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `b` + | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` | | | | - | | | pattern doesn't bind `b` + | | | pattern doesn't bind `d` | | variable not in all patterns - | pattern doesn't bind `b` - -error[E0408]: variable `d` from pattern #1 isn't bound in patterns #4, #3 - --> $DIR/issue-39698.rs:20:48 - | -20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` - | | | - | | pattern doesn't bind `d` - | variable not in all patterns + | pattern doesn't bind `d` -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors From 2a45c0a194b46388f9918a948dffe06ddccf8f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Feb 2017 14:13:39 -0800 Subject: [PATCH 05/18] Sort patterns by pattern number --- src/librustc_resolve/lib.rs | 28 ++++++++++++++++++++-------- src/test/ui/span/issue-39698.stderr | 6 +++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fe88eb9fd9283..2a73e5557eed1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -212,19 +212,31 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, } ResolutionError::VariableNotBoundInPattern(binding_error) => { let msp = MultiSpan::from_spans(binding_error.target.iter().map(|x| x.0).collect()); + + let mut origin_patterns = binding_error.origin.iter() + .map(|x| x.1) + .collect::>(); + origin_patterns.sort(); + let origin_patterns = origin_patterns.iter() + .map(|x| format!("#{}", x)) + .collect::>() + .join(", "); + let mut target_patterns = binding_error.target.iter() + .map(|x| x.1) + .collect::>(); + target_patterns.sort(); + let target_patterns = target_patterns.iter() + .map(|x| format!("#{}", x)) + .collect::>() + .join(", "); + // "variable `a` from patterns #1, #4 isn't bound in patterns #2, #3" let msg = format!("variable `{}` from pattern{} {} isn't bound in pattern{} {}", binding_error.name, if binding_error.origin.len() > 1 { "s" } else { "" }, - binding_error.origin.iter() - .map(|x| format!("#{}", x.1)) - .collect::>() - .join(", "), + origin_patterns, if binding_error.target.len() > 1 { "s" } else { "" }, - binding_error.target.iter() - .map(|x| format!("#{}", x.1)) - .collect::>() - .join(", ")); + target_patterns); let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); for (sp, _) in binding_error.target { err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name)); diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr index c2a212e94db53..9692689576513 100644 --- a/src/test/ui/span/issue-39698.stderr +++ b/src/test/ui/span/issue-39698.stderr @@ -1,4 +1,4 @@ -error[E0408]: variable `c` from patterns #2, #1 isn't bound in patterns #4, #3 +error[E0408]: variable `c` from patterns #1, #2 isn't bound in patterns #3, #4 --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } @@ -8,7 +8,7 @@ error[E0408]: variable `c` from patterns #2, #1 isn't bound in patterns #4, #3 | | variable not in all patterns | variable not in all patterns -error[E0408]: variable `d` from pattern #3 isn't bound in patterns #2, #4, #1 +error[E0408]: variable `d` from pattern #3 isn't bound in patterns #1, #2, #4 --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } @@ -28,7 +28,7 @@ error[E0408]: variable `b` from patterns #1, #4 isn't bound in patterns #2, #3 | | pattern doesn't bind `b` | variable not in all patterns -error[E0408]: variable `d` from pattern #2 isn't bound in patterns #4, #3, #1 +error[E0408]: variable `d` from pattern #2 isn't bound in patterns #1, #3, #4 --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } From 4e43853f78af8dac580916c652ca86c806e9cd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Feb 2017 15:02:22 -0800 Subject: [PATCH 06/18] fix --- src/librustc_resolve/lib.rs | 2 +- src/test/ui/span/issue-39698.stderr | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2a73e5557eed1..0b0d798d08e76 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1927,7 +1927,7 @@ impl<'a> Resolver<'a> { let binding_error = missing_vars .entry(key_j.name) .or_insert(BindingError { - name: key.name, + name: key_j.name, origin: FxHashSet(), target: FxHashSet(), }); diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr index 9692689576513..c4c1f805db428 100644 --- a/src/test/ui/span/issue-39698.stderr +++ b/src/test/ui/span/issue-39698.stderr @@ -1,42 +1,42 @@ -error[E0408]: variable `c` from patterns #1, #2 isn't bound in patterns #3, #4 +error[E0408]: variable `d` from patterns #1, #2 isn't bound in patterns #3, #4 --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | - - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `c` + | - - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` | | | | - | | | pattern doesn't bind `c` + | | | pattern doesn't bind `d` | | variable not in all patterns | variable not in all patterns -error[E0408]: variable `d` from pattern #3 isn't bound in patterns #1, #2, #4 +error[E0408]: variable `c` from pattern #3 isn't bound in patterns #1, #2, #4 --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `d` + | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` | | | | | | | variable not in all patterns - | | pattern doesn't bind `d` - | pattern doesn't bind `d` + | | pattern doesn't bind `c` + | pattern doesn't bind `c` -error[E0408]: variable `b` from patterns #1, #4 isn't bound in patterns #2, #3 +error[E0408]: variable `a` from patterns #1, #4 isn't bound in patterns #2, #3 --> $DIR/issue-39698.rs:20:23 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | - ^^^^^^^^^^^ ^^^^^^^^ - variable not in all patterns | | | | - | | | pattern doesn't bind `b` - | | pattern doesn't bind `b` + | | | pattern doesn't bind `a` + | | pattern doesn't bind `a` | variable not in all patterns -error[E0408]: variable `d` from pattern #2 isn't bound in patterns #1, #3, #4 +error[E0408]: variable `b` from pattern #2 isn't bound in patterns #1, #3, #4 --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } - | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` + | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `b` | | | | - | | | pattern doesn't bind `d` + | | | pattern doesn't bind `b` | | variable not in all patterns - | pattern doesn't bind `d` + | pattern doesn't bind `b` error: aborting due to 4 previous errors From 39de12f6f492047417ce703d10d901a4325dec10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Feb 2017 16:13:45 -0800 Subject: [PATCH 07/18] Check inconsistent bindings in all arms --- src/librustc_resolve/lib.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0b0d798d08e76..1c1abfdb77ee4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -118,7 +118,7 @@ enum ResolutionError<'a> { /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} VariableNotBoundInPattern(BindingError), /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 - VariableBoundWithDifferentMode(Name, usize, Span), + VariableBoundWithDifferentMode(Name, usize, Span, usize), /// error E0415: identifier is bound more than once in this parameter list IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern @@ -248,14 +248,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, } ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number, - first_binding_span) => { + first_binding_span, + origin_pattern_number) => { let mut err = struct_span_err!(resolver.session, span, E0409, "variable `{}` is bound with different mode in pattern #{} than in \ - pattern #1", + pattern #{}", variable_name, - pattern_number); + pattern_number, + origin_pattern_number); err.span_label(span, &format!("bound in different ways")); err.span_label(first_binding_span, &format!("first binding")); err @@ -1940,6 +1942,7 @@ impl<'a> Resolver<'a> { .entry(key.name) .or_insert((binding_j.span, binding_i.span, + j + 1, i + 1)); } } @@ -1953,8 +1956,10 @@ impl<'a> Resolver<'a> { v.origin.iter().next().unwrap().0, ResolutionError::VariableNotBoundInPattern(v)); } - for (k, v) in inconsistent_vars { - resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(k, v.2, v.1)); + for (name, v) in inconsistent_vars { + resolve_error(self, + v.0, + ResolutionError::VariableBoundWithDifferentMode(name, v.2, v.1, v.3)); } } From c8292fcd6ad2a06d2529f5dcea4b9133930211b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Wed, 15 Feb 2017 13:44:52 +0100 Subject: [PATCH 08/18] Correct a typo in procedural macros chapter of the Book. --- src/doc/book/src/procedural-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index d286c3b7bdc63..334f5e8d6567b 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -169,7 +169,7 @@ So this is where quotes comes in. The `ast` argument is a struct that gives us a representation of our type (which can be either a `struct` or an `enum`). Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), there is some useful information there. We are able to get the name of the -type using `ast.ident`. The `quote!` macro let's us write up the Rust code +type using `ast.ident`. The `quote!` macro let us write up the Rust code that we wish to return and convert it into `Tokens`. `quote!` let's us use some really cool templating mechanics; we simply write `#name` and `quote!` will replace it with the variable named `name`. You can even do some repetition From f313646a3b5732be29226326889f85b4f4d4b599 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Feb 2017 08:53:18 -0800 Subject: [PATCH 09/18] test: Verify all sysroot crates are unstable As we continue to add more crates to the compiler and use them to implement various features we want to be sure we're not accidentally expanding the API surface area of the compiler! To that end this commit adds a new `run-make` test which will attempt to `extern crate foo` all crates in the sysroot, verifying that they're all unstable. This commit discovered that the `std_shim` and `test_shim` crates were accidentally stable and fixes the situation by deleting those shims. The shims are no longer necessary due to changes in Cargo that have happened since they were originally incepted. --- src/Cargo.lock | 15 ------ src/Cargo.toml | 4 +- src/bootstrap/README.md | 4 +- src/bootstrap/check.rs | 4 +- src/bootstrap/compile.rs | 4 +- src/bootstrap/doc.rs | 4 +- src/bootstrap/metadata.rs | 4 +- src/bootstrap/step.rs | 50 +++++++++---------- src/liballoc_jemalloc/lib.rs | 12 ----- src/rustc/std_shim/Cargo.toml | 46 ----------------- src/rustc/std_shim/lib.rs | 17 ------- src/rustc/test_shim/Cargo.toml | 16 ------ src/rustc/test_shim/lib.rs | 15 ------ .../sysroot-crates-are-unstable/Makefile | 28 +++++++++++ 14 files changed, 65 insertions(+), 158 deletions(-) delete mode 100644 src/rustc/std_shim/Cargo.toml delete mode 100644 src/rustc/std_shim/lib.rs delete mode 100644 src/rustc/test_shim/Cargo.toml delete mode 100644 src/rustc/test_shim/lib.rs create mode 100644 src/test/run-make/sysroot-crates-are-unstable/Makefile diff --git a/src/Cargo.lock b/src/Cargo.lock index 51d45c06fcb49..1d1d63c9ee463 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -762,14 +762,6 @@ dependencies = [ "unwind 0.0.0", ] -[[package]] -name = "std_shim" -version = "0.0.0" -dependencies = [ - "core 0.0.0", - "std 0.0.0", -] - [[package]] name = "std_unicode" version = "0.0.0" @@ -835,13 +827,6 @@ dependencies = [ "term 0.0.0", ] -[[package]] -name = "test_shim" -version = "0.0.0" -dependencies = [ - "test 0.0.0", -] - [[package]] name = "thread-id" version = "2.0.0" diff --git a/src/Cargo.toml b/src/Cargo.toml index d8dedd11f357d..0dafbb8428e3e 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -2,8 +2,8 @@ members = [ "bootstrap", "rustc", - "rustc/std_shim", - "rustc/test_shim", + "libstd", + "libtest", "tools/cargotest", "tools/compiletest", "tools/error_index_generator", diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index ac84edb403847..2f7757fb1d5ba 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -267,8 +267,8 @@ build/ The current build is unfortunately not quite as simple as `cargo build` in a directory, but rather the compiler is split into three different Cargo projects: -* `src/rustc/std_shim` - a project which builds and compiles libstd -* `src/rustc/test_shim` - a project which builds and compiles libtest +* `src/libstd` - the standard library +* `src/libtest` - testing support, depends on libstd * `src/rustc` - the actual compiler itself Each "project" has a corresponding Cargo.lock file with all dependencies, and diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 00758460becc5..dfe96b51799c0 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -346,10 +346,10 @@ pub fn krate(build: &Build, krate: Option<&str>) { let (name, path, features, root) = match mode { Mode::Libstd => { - ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim") + ("libstd", "src/libstd", build.std_features(), "std") } Mode::Libtest => { - ("libtest", "src/rustc/test_shim", String::new(), "test_shim") + ("libtest", "src/libtest", String::new(), "test") } Mode::Librustc => { ("librustc", "src/rustc", build.rustc_features(), "rustc-main") diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0b1a1f39d8d42..00904bc776aa9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -64,7 +64,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) { } cargo.arg("--features").arg(features) .arg("--manifest-path") - .arg(build.src.join("src/rustc/std_shim/Cargo.toml")); + .arg(build.src.join("src/libstd/Cargo.toml")); if let Some(target) = build.config.target_config.get(target) { if let Some(ref jemalloc) = target.jemalloc { @@ -162,7 +162,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) { build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); cargo.arg("--manifest-path") - .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); + .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); update_mtime(build, &libtest_stamp(build, compiler, target)); } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 74b13144f2ff0..3fcc15b35b541 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -152,7 +152,7 @@ pub fn std(build: &Build, stage: u32, target: &str) { let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc"); cargo.arg("--manifest-path") - .arg(build.src.join("src/rustc/std_shim/Cargo.toml")) + .arg(build.src.join("src/libstd/Cargo.toml")) .arg("--features").arg(build.std_features()); // We don't want to build docs for internal std dependencies unless @@ -198,7 +198,7 @@ pub fn test(build: &Build, stage: u32, target: &str) { let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc"); cargo.arg("--manifest-path") - .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); + .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); cp_r(&out_dir, &out) } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 8befb105ff618..5ab542b6a2489 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -43,8 +43,8 @@ struct ResolveNode { } pub fn build(build: &mut Build) { - build_krate(build, "src/rustc/std_shim"); - build_krate(build, "src/rustc/test_shim"); + build_krate(build, "src/libstd"); + build_krate(build, "src/libtest"); build_krate(build, "src/rustc"); } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index ee5b61062fed8..ef84693b5b319 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -246,14 +246,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { crate_rule(build, &mut rules, "libstd-link", - "build-crate-std_shim", + "build-crate-std", compile::std_link) .dep(|s| s.name("startup-objects")) .dep(|s| s.name("create-sysroot").target(s.host)); crate_rule(build, &mut rules, "libtest-link", - "build-crate-test_shim", + "build-crate-test", compile::test_link) .dep(|s| s.name("libstd-link")); crate_rule(build, @@ -263,13 +263,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { compile::rustc_link) .dep(|s| s.name("libtest-link")); - for (krate, path, _default) in krates("std_shim") { + for (krate, path, _default) in krates("std") { rules.build(&krate.build_step, path) .dep(|s| s.name("startup-objects")) .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host)) .run(move |s| compile::std(build, s.target, &s.compiler())); } - for (krate, path, _default) in krates("test_shim") { + for (krate, path, _default) in krates("test") { rules.build(&krate.build_step, path) .dep(|s| s.name("libstd-link")) .run(move |s| compile::test(build, s.target, &s.compiler())); @@ -384,7 +384,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { "pretty", "run-fail-fulldeps"); } - for (krate, path, _default) in krates("std_shim") { + for (krate, path, _default) in krates("std") { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) .dep(|s| s.name("emulator-copy-libs")) @@ -400,7 +400,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { Mode::Libstd, TestKind::Test, None)); // std benchmarks - for (krate, path, _default) in krates("std_shim") { + for (krate, path, _default) in krates("std") { rules.bench(&krate.bench_step, path) .dep(|s| s.name("libtest")) .dep(|s| s.name("emulator-copy-libs")) @@ -415,7 +415,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, TestKind::Bench, None)); - for (krate, path, _default) in krates("test_shim") { + for (krate, path, _default) in krates("test") { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) .dep(|s| s.name("emulator-copy-libs")) @@ -583,13 +583,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(build.config.docs) .host(true) .run(move |s| doc::error_index(build, s.target)); - for (krate, path, default) in krates("std_shim") { + for (krate, path, default) in krates("std") { rules.doc(&krate.doc_step, path) .dep(|s| s.name("libstd-link")) .default(default && build.config.docs) .run(move |s| doc::std(build, s.stage, s.target)); } - for (krate, path, default) in krates("test_shim") { + for (krate, path, default) in krates("test") { rules.doc(&krate.doc_step, path) .dep(|s| s.name("libtest-link")) .default(default && build.config.compiler_docs) @@ -1154,23 +1154,23 @@ mod tests { let mut build = Build::new(flags, config); let cwd = env::current_dir().unwrap(); - build.crates.insert("std_shim".to_string(), ::Crate { - name: "std_shim".to_string(), + build.crates.insert("std".to_string(), ::Crate { + name: "std".to_string(), deps: Vec::new(), - path: cwd.join("src/std_shim"), - doc_step: "doc-std_shim".to_string(), - build_step: "build-crate-std_shim".to_string(), - test_step: "test-std_shim".to_string(), - bench_step: "bench-std_shim".to_string(), + path: cwd.join("src/std"), + doc_step: "doc-std".to_string(), + build_step: "build-crate-std".to_string(), + test_step: "test-std".to_string(), + bench_step: "bench-std".to_string(), }); - build.crates.insert("test_shim".to_string(), ::Crate { - name: "test_shim".to_string(), + build.crates.insert("test".to_string(), ::Crate { + name: "test".to_string(), deps: Vec::new(), - path: cwd.join("src/test_shim"), - doc_step: "doc-test_shim".to_string(), - build_step: "build-crate-test_shim".to_string(), - test_step: "test-test_shim".to_string(), - bench_step: "bench-test_shim".to_string(), + path: cwd.join("src/test"), + doc_step: "doc-test".to_string(), + build_step: "build-crate-test".to_string(), + test_step: "test-test".to_string(), + bench_step: "bench-test".to_string(), }); build.crates.insert("rustc-main".to_string(), ::Crate { name: "rustc-main".to_string(), @@ -1360,7 +1360,7 @@ mod tests { let all = rules.expand(&plan); println!("all rules: {:#?}", all); assert!(!all.contains(&step.name("rustc"))); - assert!(!all.contains(&step.name("build-crate-std_shim").stage(1))); + assert!(!all.contains(&step.name("build-crate-std").stage(1))); // all stage0 compiles should be for the build target, A for step in all.iter().filter(|s| s.stage == 0) { @@ -1425,7 +1425,7 @@ mod tests { assert!(!plan.iter().any(|s| s.name.contains("rustc"))); assert!(plan.iter().all(|s| { - !s.name.contains("test_shim") || s.target == "C" + !s.name.contains("test") || s.target == "C" })); } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 8d81a09f5af0f..a496ab870c63b 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -122,18 +122,6 @@ mod imp { let flags = align_to_flags(align); unsafe { nallocx(size as size_t, flags) as usize } } - - // These symbols are used by jemalloc on android but the really old android - // we're building on doesn't have them defined, so just make sure the symbols - // are available. - #[no_mangle] - #[cfg(all(target_os = "android", not(cargobuild)))] - pub extern "C" fn pthread_atfork(_prefork: *mut u8, - _postfork_parent: *mut u8, - _postfork_child: *mut u8) - -> i32 { - 0 - } } #[cfg(dummy_jemalloc)] diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml deleted file mode 100644 index db96079d3e916..0000000000000 --- a/src/rustc/std_shim/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -# This is a shim Cargo.toml which serves as a proxy for building the standard -# library. The reason for this is a little subtle, as one might reasonably -# expect that we just `cargo build` the standard library itself. -# -# One of the output artifacts for the standard library is a dynamic library, and -# on platforms like OSX the name of the output artifact is actually encoded into -# the library itself (similar to a soname on Linux). When the library is linked -# against, this encoded name is what's literally looked for at runtime when the -# dynamic loader is probing for libraries. -# -# Cargo, however, by default will not mangle the output filename of the -# top-level target. If we were to run `cargo build` on libstd itself, we would -# generate a file `libstd.so`. When installing, however, this file is called -# something like `libstd-abcdef0123.so`. On OSX at least this causes a failure -# at runtime because the encoded "soname" is `libstd.so`, not what the file is -# actually called. -# -# By using this shim library to build the standard library by proxy we sidestep -# this problem. The standard library is built with mangled hex already in its -# name so there's nothing extra we need to do. - -[package] -name = "std_shim" -version = "0.0.0" -authors = ["The Rust Project Developers"] - -[lib] -name = "std_shim" -path = "lib.rs" -doc = false - -[dependencies] -std = { path = "../../libstd" } -core = { path = "../../libcore" } - -# Reexport features from std -[features] -asan = ["std/asan"] -backtrace = ["std/backtrace"] -debug-jemalloc = ["std/debug-jemalloc"] -jemalloc = ["std/jemalloc"] -force_alloc_system = ["std/force_alloc_system"] -lsan = ["std/lsan"] -msan = ["std/msan"] -panic-unwind = ["std/panic-unwind"] -tsan = ["std/tsan"] diff --git a/src/rustc/std_shim/lib.rs b/src/rustc/std_shim/lib.rs deleted file mode 100644 index 2fc5d8d6e5321..0000000000000 --- a/src/rustc/std_shim/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2015 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. - -// See comments in Cargo.toml for why this exists - -// There's a bug right now where if we pass --extern std=... and we're cross -// compiling then this doesn't work with `#[macro_use] extern crate std;`. Work -// around this by not having `#[macro_use] extern crate std;` -#![no_std] -extern crate std; diff --git a/src/rustc/test_shim/Cargo.toml b/src/rustc/test_shim/Cargo.toml deleted file mode 100644 index 6ef613eee0628..0000000000000 --- a/src/rustc/test_shim/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -# This is a shim Cargo.toml which serves as a proxy for building libtest. -# -# The reason this shim exists is basically the same reason that `std_shim` -# exists, and more documentation can be found in that `Cargo.toml` as to why. - -[package] -name = "test_shim" -version = "0.0.0" -authors = ["The Rust Project Developers"] - -[lib] -name = "test_shim" -path = "lib.rs" - -[dependencies] -test = { path = "../../libtest" } diff --git a/src/rustc/test_shim/lib.rs b/src/rustc/test_shim/lib.rs deleted file mode 100644 index d614d967e3b07..0000000000000 --- a/src/rustc/test_shim/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 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. - -// See comments in Cargo.toml for why this exists - -#![feature(test)] - -extern crate test; diff --git a/src/test/run-make/sysroot-crates-are-unstable/Makefile b/src/test/run-make/sysroot-crates-are-unstable/Makefile new file mode 100644 index 0000000000000..f08b62ad3aafe --- /dev/null +++ b/src/test/run-make/sysroot-crates-are-unstable/Makefile @@ -0,0 +1,28 @@ +# This is a whitelist of crates which are stable, we don't check for the +# instability of these crates as they're all stable! +STABLE_CRATES := \ + std \ + core \ + proc_macro + +# Generate a list of all crates in the sysroot. To do this we list all files in +# rustc's sysroot, look at the filename, strip everything after the `-`, and +# strip the leading `lib` (if present) +SYSROOT := $(shell $(RUSTC) --print sysroot) +LIBS := $(wildcard $(SYSROOT)/lib/rustlib/$(TARGET)/lib/*) +LIBS := $(foreach lib,$(LIBS),$(notdir $(lib))) +LIBS := $(foreach lib,$(LIBS),$(word 1,$(subst -, ,$(lib)))) +LIBS := $(foreach lib,$(LIBS),$(patsubst lib%,%,$(lib))) +LIBS := $(filter-out $(STABLE_CRATES),$(LIBS)) + +all: $(foreach lib,$(LIBS),check-crate-$(lib)-is-unstable) + +check-crate-%-is-unstable: + @echo verifying $* is an unstable crate + @echo 'extern crate $*;' | \ + $(RUSTC) - --crate-type rlib 2>&1 | cat > $(TMPDIR)/$*; \ + true + @grep -q 'use of unstable library feature' $(TMPDIR)/$* || \ + (echo crate $* is not unstable && \ + cat $(TMPDIR)/$* && \ + false) From 4a3c66ad2f4211137fcb98a31d1e1033d5765e22 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 15 Feb 2017 21:21:36 +0200 Subject: [PATCH 10/18] [MIR] Make InlineAsm a Statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously InlineAsm was an Rvalue, but its semantics doesn’t really match the semantics of an Rvalue – rather it behaves more like a Statement. --- src/librustc/mir/mod.rs | 21 +++++++++---------- src/librustc/mir/tcx.rs | 1 - src/librustc/mir/visit.rs | 21 +++++++++---------- .../borrowck/mir/dataflow/impls.rs | 1 + .../borrowck/mir/dataflow/sanity_check.rs | 1 + .../borrowck/mir/gather_moves.rs | 4 ++-- src/librustc_borrowck/borrowck/mir/mod.rs | 1 + src/librustc_mir/build/expr/as_rvalue.rs | 16 +------------- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 17 +++++++++++++++ src/librustc_mir/transform/qualify_consts.rs | 5 +---- src/librustc_mir/transform/type_check.rs | 5 +++-- src/librustc_passes/mir_stats.rs | 2 +- src/librustc_trans/mir/constant.rs | 3 ++- src/librustc_trans/mir/rvalue.rs | 21 ++----------------- src/librustc_trans/mir/statement.rs | 14 +++++++++++++ 16 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d8212807eb277..3403cf0477450 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -777,6 +777,12 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Lvalue<'tcx>), + InlineAsm { + asm: InlineAsm, + outputs: Vec>, + inputs: Vec> + }, + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } @@ -790,7 +796,10 @@ impl<'tcx> Debug for Statement<'tcx> { StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv), SetDiscriminant{lvalue: ref lv, variant_index: index} => { write!(fmt, "discriminant({:?}) = {:?}", lv, index) - } + }, + InlineAsm { ref asm, ref outputs, ref inputs } => { + write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) + }, Nop => write!(fmt, "nop"), } } @@ -1004,12 +1013,6 @@ pub enum Rvalue<'tcx> { /// that `Foo` has a destructor. These rvalues can be optimized /// away after type-checking and before lowering. Aggregate(AggregateKind<'tcx>, Vec>), - - InlineAsm { - asm: InlineAsm, - outputs: Vec>, - inputs: Vec> - } } #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] @@ -1111,10 +1114,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval), Box(ref t) => write!(fmt, "Box({:?})", t), - InlineAsm { ref asm, ref outputs, ref inputs } => { - write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) - } - Ref(_, borrow_kind, ref lv) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 7b0863b4c42bc..5c8d031caf60d 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -207,7 +207,6 @@ impl<'tcx> Rvalue<'tcx> { } } } - Rvalue::InlineAsm { .. } => None } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index be3c43db7badd..7cdbd5cae061f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -333,6 +333,16 @@ macro_rules! make_mir_visitor { StatementKind::StorageDead(ref $($mutability)* lvalue) => { self.visit_lvalue(lvalue, LvalueContext::StorageDead, location); } + StatementKind::InlineAsm { ref $($mutability)* outputs, + ref $($mutability)* inputs, + asm: _ } => { + for output in & $($mutability)* outputs[..] { + self.visit_lvalue(output, LvalueContext::Store, location); + } + for input in & $($mutability)* inputs[..] { + self.visit_operand(input, location); + } + } StatementKind::Nop => {} } } @@ -526,17 +536,6 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); } } - - Rvalue::InlineAsm { ref $($mutability)* outputs, - ref $($mutability)* inputs, - asm: _ } => { - for output in & $($mutability)* outputs[..] { - self.visit_lvalue(output, LvalueContext::Store, location); - } - for input in & $($mutability)* inputs[..] { - self.visit_operand(input, location); - } - } } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 1fa4da94dd6bf..7888a56d39dfb 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -473,6 +473,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { } mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | + mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index ea6ef423c92ce..940dd5433a0d9 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -104,6 +104,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | + mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Nop => continue, mir::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 0c7e922c48ab4..35ace6628cfed 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -412,6 +412,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } + StatementKind::InlineAsm { .. } | StatementKind::Nop => {} } } @@ -436,8 +437,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } Rvalue::Ref(..) | Rvalue::Discriminant(..) | - Rvalue::Len(..) | - Rvalue::InlineAsm { .. } => {} + Rvalue::Len(..) => {} Rvalue::Box(..) => { // This returns an rvalue with uninitialized contents. We can't // move out of it here because it is an rvalue - assignments always diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index a0c36139ddcd2..d9283e7037f50 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -378,6 +378,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | + mir::StatementKind::InlineAsm { .. } | mir::StatementKind::Nop => {} }, None => { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index dad1d713168cd..7adcc0e730b15 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -49,21 +49,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Scope { extent, value } => { this.in_scope(extent, block, |this| this.as_rvalue(block, value)) } - ExprKind::InlineAsm { asm, outputs, inputs } => { - let outputs = outputs.into_iter().map(|output| { - unpack!(block = this.as_lvalue(block, output)) - }).collect(); - - let inputs = inputs.into_iter().map(|input| { - unpack!(block = this.as_operand(block, input)) - }).collect(); - - block.and(Rvalue::InlineAsm { - asm: asm.clone(), - outputs: outputs, - inputs: inputs - }) - } ExprKind::Repeat { value, count } => { let value_operand = unpack!(block = this.as_operand(block, value)); block.and(Rvalue::Repeat(value_operand, count)) @@ -238,6 +223,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } | + ExprKind::InlineAsm { .. } | ExprKind::StaticRef { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 35841c2cbdf01..e66f2b4e2bfc0 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -232,6 +232,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::AssignOp { .. } | ExprKind::Continue { .. } | ExprKind::Break { .. } | + ExprKind::InlineAsm { .. } | ExprKind::Return {.. } => { this.stmt_expr(block, expr) } @@ -257,7 +258,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Literal { .. } | - ExprKind::InlineAsm { .. } | ExprKind::Field { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { Category::Rvalue(RvalueFunc::Into) => false, diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index f04d630379a35..c577aab40dbeb 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -117,6 +117,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.exit_scope(expr_span, extent, block, return_block); this.cfg.start_new_block().unit() } + ExprKind::InlineAsm { asm, outputs, inputs } => { + let outputs = outputs.into_iter().map(|output| { + unpack!(block = this.as_lvalue(block, output)) + }).collect(); + let inputs = inputs.into_iter().map(|input| { + unpack!(block = this.as_operand(block, input)) + }).collect(); + this.cfg.push(block, Statement { + source_info: source_info, + kind: StatementKind::InlineAsm { + asm: asm.clone(), + outputs: outputs, + inputs: inputs + }, + }); + block.unit() + } _ => { let expr_ty = expr.ty; let temp = this.temp(expr.ty.clone()); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 922521726c626..4459142cfb274 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -774,10 +774,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } } - - Rvalue::InlineAsm {..} => { - self.not_const(); - } } } @@ -933,6 +929,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { StatementKind::SetDiscriminant { .. } | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | + StatementKind::InlineAsm {..} | StatementKind::Nop => {} } }); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 8ede7aaab5f68..8d108815e0f3c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -361,9 +361,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}", lv_ty, rv_ty, terr); } - // FIXME: rvalue with undeterminable type - e.g. inline - // asm. } + // FIXME: rvalue with undeterminable type - e.g. AggregateKind::Array branch that + // returns `None`. } StatementKind::SetDiscriminant{ ref lvalue, variant_index } => { let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); @@ -392,6 +392,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } + StatementKind::InlineAsm { .. } | StatementKind::Nop => {} } } diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 517a472056334..33b7089c38214 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -128,6 +128,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", StatementKind::StorageLive(..) => "StatementKind::StorageLive", StatementKind::StorageDead(..) => "StatementKind::StorageDead", + StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm", StatementKind::Nop => "StatementKind::Nop", }, &statement.kind); self.super_statement(block, statement, location); @@ -198,7 +199,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { "Rvalue::Aggregate" } - Rvalue::InlineAsm { .. } => "Rvalue::InlineAsm", }; self.record(rvalue_kind, rvalue); self.super_rvalue(rvalue, location); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 19139301bb0c4..7e17ae5f1d389 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -287,8 +287,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { .. } | mir::StatementKind::SetDiscriminant{ .. } => { - span_bug!(span, "SetDiscriminant should not appear in constants?"); + span_bug!(span, "{:?} should not appear in constants?", statement.kind); } } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 38ee67796c6de..7d4f542addbb1 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -16,7 +16,6 @@ use rustc::mir::tcx::LvalueTy; use rustc::mir; use middle::lang_items::ExchangeMallocFnLangItem; -use asm; use base; use builder::Builder; use callee::Callee; @@ -156,20 +155,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx } - mir::Rvalue::InlineAsm { ref asm, ref outputs, ref inputs } => { - let outputs = outputs.iter().map(|output| { - let lvalue = self.trans_lvalue(&bcx, output); - (lvalue.llval, lvalue.ty.to_ty(bcx.tcx())) - }).collect(); - - let input_vals = inputs.iter().map(|input| { - self.trans_operand(&bcx, input).immediate() - }).collect(); - - asm::trans_inline_asm(&bcx, asm, outputs, input_vals); - bcx - } - _ => { assert!(rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); @@ -468,8 +453,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { (bcx, operand) } mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) | - mir::Rvalue::InlineAsm { .. } => { + mir::Rvalue::Aggregate(..) => { bug!("cannot generate operand from rvalue {:?}", rvalue); } @@ -669,8 +653,7 @@ pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { mir::Rvalue::Use(..) => true, mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) | - mir::Rvalue::InlineAsm { .. } => + mir::Rvalue::Aggregate(..) => false, } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 48fc9720e4b83..29a0648c8f8f8 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -11,6 +11,7 @@ use rustc::mir; use base; +use asm; use common; use builder::Builder; @@ -73,6 +74,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::StatementKind::StorageDead(ref lvalue) => { self.trans_storage_liveness(bcx, lvalue, base::Lifetime::End) } + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + let outputs = outputs.iter().map(|output| { + let lvalue = self.trans_lvalue(&bcx, output); + (lvalue.llval, lvalue.ty.to_ty(bcx.tcx())) + }).collect(); + + let input_vals = inputs.iter().map(|input| { + self.trans_operand(&bcx, input).immediate() + }).collect(); + + asm::trans_inline_asm(&bcx, asm, outputs, input_vals); + bcx + } mir::StatementKind::Nop => bcx, } } From 1fbbe79bcb97cc85dfe5f6c431b7aca9784a9bd4 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 15 Feb 2017 23:26:29 +0100 Subject: [PATCH 11/18] Fix wording in LocalKey documentation --- src/libstd/sync/once.rs | 2 +- src/libstd/thread/local.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index ba99375139139..1e7394c0b09e7 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -316,7 +316,7 @@ impl Once { } // Once we've enqueued ourselves, wait in a loop. - // Aftewards reload the state and continue with what we + // Afterwards reload the state and continue with what we // were doing from before. while !node.signaled.load(Ordering::SeqCst) { thread::park(); diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 5166ddf8a21b6..66f09a7069c13 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -28,8 +28,8 @@ use mem; /// # Initialization and Destruction /// /// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values support destructors which will be run when a -/// thread exits. +/// within a thread, and values that implement `Drop` get destructed when a +/// thread exits. Some caveats apply, which are explained below. /// /// # Examples /// From ab57e7b86817b8ca9b7e6afb2f689ae67274ec7c Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Thu, 16 Feb 2017 02:16:41 +0100 Subject: [PATCH 12/18] std::io::cursor Added test for seeking beyond i64. --- src/libstd/io/cursor.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 0cff8661d8871..9427e4afa2142 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -526,6 +526,43 @@ mod tests { assert_eq!(r.write(&[3]).unwrap(), 0); } + #[test] + fn seek_past_i64() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + } + #[test] fn seek_before_0() { let buf = [0xff]; From a2d176e8f4774b84db22540a45eed7b29482f154 Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Thu, 16 Feb 2017 02:21:08 +0100 Subject: [PATCH 13/18] std::io::cursor: Fixed Seek so test passes. --- src/libstd/io/cursor.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 9427e4afa2142..60767ea478661 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -200,18 +200,20 @@ impl Cursor { #[stable(feature = "rust1", since = "1.0.0")] impl io::Seek for Cursor where T: AsRef<[u8]> { fn seek(&mut self, style: SeekFrom) -> io::Result { - let pos = match style { - SeekFrom::Start(n) => { self.pos = n; return Ok(n) } - SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n, - SeekFrom::Current(n) => self.pos as i64 + n, + let (base_pos, offset) = match style { + SeekFrom::Start(n) => { self.pos = n; return Ok(n); } + SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), + SeekFrom::Current(n) => (self.pos, n), }; - - if pos < 0 { - Err(Error::new(ErrorKind::InvalidInput, - "invalid seek to a negative position")) + let new_pos = if offset >= 0 { + base_pos.checked_add(offset as u64) } else { - self.pos = pos as u64; - Ok(self.pos) + base_pos.checked_sub((offset.wrapping_neg()) as u64) + }; + match new_pos { + Some(n) => {self.pos = n; Ok(self.pos)} + None => Err(Error::new(ErrorKind::InvalidInput, + "invalid seek to a negative or overflowing position")) } } } From a7f63d12a701f8d2c7b975ef605a50bb83318b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 Feb 2017 21:46:23 -0800 Subject: [PATCH 14/18] Remove noop method `Substs::params()` Re: 48b3dd11f59f48819031206ee2b3ab98ceae1550 --- src/librustc/traits/select.rs | 4 ++-- src/librustc/ty/relate.rs | 2 +- src/librustc/ty/subst.rs | 6 ------ src/librustc_typeck/check/method/confirm.rs | 6 +++--- src/librustc_typeck/check/method/probe.rs | 4 ++-- src/librustc_typeck/check/writeback.rs | 2 +- 6 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 41f3f825c3d19..40c62762c3cf3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2547,7 +2547,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // TyError and ensure they do not affect any other fields. // This could be checked after type collection for any struct // with a potentially unsized trailing field. - let params = substs_a.params().iter().enumerate().map(|(i, &k)| { + let params = substs_a.iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { Kind::from(tcx.types.err) } else { @@ -2567,7 +2567,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Check that the source structure with the target's // type parameters is a subtype of the target. - let params = substs_a.params().iter().enumerate().map(|(i, &k)| { + let params = substs_a.iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { Kind::from(substs_b.type_at(i)) } else { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index adedf78bba7c0..2e3009b4ed6db 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -143,7 +143,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, { let tcx = relation.tcx(); - let params = a_subst.params().iter().zip(b_subst.params()).enumerate().map(|(i, (a, b))| { + let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) { Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?)) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index d6f61a12a3c6e..c0a529b936b0f 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -254,12 +254,6 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { self.is_empty() } - #[inline] - pub fn params(&self) -> &[Kind<'tcx>] { - // FIXME (dikaiosune) this should be removed, and corresponding compilation errors fixed - self - } - #[inline] pub fn types(&'a self) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| k.as_type()) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index ff9eaa012ba41..2d90394025d21 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -309,17 +309,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let supplied_start = substs.params().len() + method_generics.regions.len(); + let supplied_start = substs.len() + method_generics.regions.len(); Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; - if i < substs.params().len() { + if i < substs.len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.params().len() { + if i < substs.len() { substs.type_at(i) } else if supplied_method_types.is_empty() { self.type_var_for_def(self.span, def, cur_substs) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 201a223c15f15..fd29ff0be43b4 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1326,7 +1326,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { let substs = Substs::for_item(self.tcx, method, |def, _| { let i = def.index as usize; - if i < substs.params().len() { + if i < substs.len() { substs.region_at(i) } else { // In general, during probe we erase regions. See @@ -1335,7 +1335,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.params().len() { + if i < substs.len() { substs.type_at(i) } else { self.type_var_for_def(self.span, def, cur_substs) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 28156dd616b3a..a292227058379 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -100,7 +100,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let gcx = fcx.tcx.global_tcx(); let free_substs = fcx.parameter_environment.free_substs; - for (i, k) in free_substs.params().iter().enumerate() { + for (i, k) in free_substs.iter().enumerate() { let r = if let Some(r) = k.as_region() { r } else { From 36b00cf217f354b9169cc5c529642bfd958295a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20CORTIER?= Date: Thu, 16 Feb 2017 09:18:19 +0100 Subject: [PATCH 15/18] Correct a typo in procedural macros chapter of the Book. (fixup [c8292fcd6ad2a06d2529f5]) --- src/doc/book/src/procedural-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index 334f5e8d6567b..df49c70aada73 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -169,7 +169,7 @@ So this is where quotes comes in. The `ast` argument is a struct that gives us a representation of our type (which can be either a `struct` or an `enum`). Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), there is some useful information there. We are able to get the name of the -type using `ast.ident`. The `quote!` macro let us write up the Rust code +type using `ast.ident`. The `quote!` macro lets us write up the Rust code that we wish to return and convert it into `Tokens`. `quote!` let's us use some really cool templating mechanics; we simply write `#name` and `quote!` will replace it with the variable named `name`. You can even do some repetition From 01cb5873acf4e193980243ea35be51e5c87469b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 15 Feb 2017 19:11:25 -0800 Subject: [PATCH 16/18] Simplify wording of diagnostic message --- src/librustc_resolve/lib.rs | 73 +++++-------------- src/test/compile-fail/E0408.rs | 2 +- src/test/compile-fail/issue-2848.rs | 2 +- src/test/compile-fail/issue-2849.rs | 2 +- .../resolve-inconsistent-binding-mode.rs | 6 +- .../resolve-inconsistent-names.rs | 4 +- src/test/ui/mismatched_types/E0409.stderr | 2 +- src/test/ui/span/issue-39698.stderr | 16 ++-- 8 files changed, 37 insertions(+), 70 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1c1abfdb77ee4..7a64e0f098c81 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -98,8 +98,8 @@ enum AssocSuggestion { struct BindingError { name: Name, - origin: FxHashSet<(Span, usize)>, - target: FxHashSet<(Span, usize)>, + origin: FxHashSet, + target: FxHashSet, } enum ResolutionError<'a> { @@ -115,10 +115,10 @@ enum ResolutionError<'a> { TypeNotMemberOfTrait(Name, &'a str), /// error E0438: const is not a member of trait ConstNotMemberOfTrait(Name, &'a str), - /// error E0408: variable `{}` from pattern #{} is not bound in pattern #{} + /// error E0408: variable `{}` is not bound in all patterns VariableNotBoundInPattern(BindingError), - /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 - VariableBoundWithDifferentMode(Name, usize, Span, usize), + /// error E0409: variable `{}` is bound in inconsistent ways within the same match arm + VariableBoundWithDifferentMode(Name, Span), /// error E0415: identifier is bound more than once in this parameter list IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern @@ -211,53 +211,25 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err } ResolutionError::VariableNotBoundInPattern(binding_error) => { - let msp = MultiSpan::from_spans(binding_error.target.iter().map(|x| x.0).collect()); - - let mut origin_patterns = binding_error.origin.iter() - .map(|x| x.1) - .collect::>(); - origin_patterns.sort(); - let origin_patterns = origin_patterns.iter() - .map(|x| format!("#{}", x)) - .collect::>() - .join(", "); - let mut target_patterns = binding_error.target.iter() - .map(|x| x.1) - .collect::>(); - target_patterns.sort(); - let target_patterns = target_patterns.iter() - .map(|x| format!("#{}", x)) - .collect::>() - .join(", "); - - // "variable `a` from patterns #1, #4 isn't bound in patterns #2, #3" - let msg = format!("variable `{}` from pattern{} {} isn't bound in pattern{} {}", - binding_error.name, - if binding_error.origin.len() > 1 { "s" } else { "" }, - origin_patterns, - if binding_error.target.len() > 1 { "s" } else { "" }, - target_patterns); + let msp = MultiSpan::from_spans(binding_error.target.iter().map(|x| *x).collect()); + let msg = format!("variable `{}` is not bound in all patterns", binding_error.name); let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408"); - for (sp, _) in binding_error.target { + for sp in binding_error.target { err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name)); } - for (sp, _) in binding_error.origin { + for sp in binding_error.origin { err.span_label(sp, &"variable not in all patterns"); } err } ResolutionError::VariableBoundWithDifferentMode(variable_name, - pattern_number, - first_binding_span, - origin_pattern_number) => { + first_binding_span) => { let mut err = struct_span_err!(resolver.session, span, E0409, - "variable `{}` is bound with different mode in pattern #{} than in \ - pattern #{}", - variable_name, - pattern_number, - origin_pattern_number); + "variable `{}` is bound in inconsistent \ + ways within the same match arm", + variable_name); err.span_label(span, &format!("bound in different ways")); err.span_label(first_binding_span, &format!("first binding")); err @@ -1920,8 +1892,8 @@ impl<'a> Resolver<'a> { origin: FxHashSet(), target: FxHashSet(), }); - binding_error.origin.insert((binding_i.span, i + 1)); - binding_error.target.insert((q.span, j + 1)); + binding_error.origin.insert(binding_i.span); + binding_error.target.insert(q.span); } for (&key_j, &binding_j) in &map_j { match map_i.get(&key_j) { @@ -1933,17 +1905,14 @@ impl<'a> Resolver<'a> { origin: FxHashSet(), target: FxHashSet(), }); - binding_error.origin.insert((binding_j.span, j + 1)); - binding_error.target.insert((p.span, i + 1)); + binding_error.origin.insert(binding_j.span); + binding_error.target.insert(p.span); } Some(binding_i) => { // check consistent binding if binding_i.binding_mode != binding_j.binding_mode { inconsistent_vars .entry(key.name) - .or_insert((binding_j.span, - binding_i.span, - j + 1, - i + 1)); + .or_insert((binding_j.span, binding_i.span)); } } } @@ -1953,13 +1922,11 @@ impl<'a> Resolver<'a> { } for (_, v) in missing_vars { resolve_error(self, - v.origin.iter().next().unwrap().0, + *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v)); } for (name, v) in inconsistent_vars { - resolve_error(self, - v.0, - ResolutionError::VariableBoundWithDifferentMode(name, v.2, v.1, v.3)); + resolve_error(self, v.0, ResolutionError::VariableBoundWithDifferentMode(name, v.1)); } } diff --git a/src/test/compile-fail/E0408.rs b/src/test/compile-fail/E0408.rs index 4d96ff30c0b7b..ce77a537e263d 100644 --- a/src/test/compile-fail/E0408.rs +++ b/src/test/compile-fail/E0408.rs @@ -12,7 +12,7 @@ fn main() { let x = Some(0); match x { - Some(y) | None => {} //~ ERROR variable `y` from pattern #1 isn't bound in pattern #2 + Some(y) | None => {} //~ ERROR variable `y` is not bound in all patterns _ => () //~| NOTE pattern doesn't bind `y` //~| NOTE variable not in all patterns } diff --git a/src/test/compile-fail/issue-2848.rs b/src/test/compile-fail/issue-2848.rs index e7644952f23e2..38bd7adefd91f 100644 --- a/src/test/compile-fail/issue-2848.rs +++ b/src/test/compile-fail/issue-2848.rs @@ -19,7 +19,7 @@ mod bar { fn main() { use bar::foo::{alpha, charlie}; match alpha { - alpha | beta => {} //~ ERROR variable `beta` from pattern #2 isn't bound in pattern #1 + alpha | beta => {} //~ ERROR variable `beta` is not bound in all patterns charlie => {} //~| NOTE pattern doesn't bind `beta` //~| NOTE variable not in all patterns } diff --git a/src/test/compile-fail/issue-2849.rs b/src/test/compile-fail/issue-2849.rs index 828b8990363f9..203b28bd5e417 100644 --- a/src/test/compile-fail/issue-2849.rs +++ b/src/test/compile-fail/issue-2849.rs @@ -13,6 +13,6 @@ enum foo { alpha, beta(isize) } fn main() { match foo::alpha { foo::alpha | foo::beta(i) => {} - //~^ ERROR variable `i` from pattern #2 isn't bound in pattern #1 + //~^ ERROR variable `i` is not bound in all patterns } } diff --git a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs index 284c08ef09b28..63d33a9e5fa6f 100644 --- a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs +++ b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs @@ -15,7 +15,7 @@ enum opts { fn matcher1(x: opts) { match x { opts::a(ref i) | opts::b(i) => {} - //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm //~^^ ERROR mismatched types opts::c(_) => {} } @@ -24,7 +24,7 @@ fn matcher1(x: opts) { fn matcher2(x: opts) { match x { opts::a(ref i) | opts::b(i) => {} - //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm //~^^ ERROR mismatched types opts::c(_) => {} } @@ -33,7 +33,7 @@ fn matcher2(x: opts) { fn matcher4(x: opts) { match x { opts::a(ref mut i) | opts::b(ref i) => {} - //~^ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 + //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm //~^^ ERROR mismatched types opts::c(_) => {} } diff --git a/src/test/compile-fail/resolve-inconsistent-names.rs b/src/test/compile-fail/resolve-inconsistent-names.rs index fbe106d66d2e5..7fee5aedb06ed 100644 --- a/src/test/compile-fail/resolve-inconsistent-names.rs +++ b/src/test/compile-fail/resolve-inconsistent-names.rs @@ -11,8 +11,8 @@ fn main() { let y = 1; match y { - a | b => {} //~ ERROR variable `a` from pattern #1 isn't bound in pattern #2 - //~^ ERROR variable `b` from pattern #2 isn't bound in pattern #1 + a | b => {} //~ ERROR variable `a` is not bound in all patterns + //~^ ERROR variable `b` is not bound in all patterns //~| NOTE pattern doesn't bind `a` //~| NOTE pattern doesn't bind `b` //~| NOTE variable not in all patterns diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr index 251e247fa28ba..45a42b1c271f8 100644 --- a/src/test/ui/mismatched_types/E0409.stderr +++ b/src/test/ui/mismatched_types/E0409.stderr @@ -1,4 +1,4 @@ -error[E0409]: variable `y` is bound with different mode in pattern #2 than in pattern #1 +error[E0409]: variable `y` is bound in inconsistent ways within the same match arm --> $DIR/E0409.rs:15:23 | 15 | (0, ref y) | (y, 0) => {} //~ ERROR E0409 diff --git a/src/test/ui/span/issue-39698.stderr b/src/test/ui/span/issue-39698.stderr index c4c1f805db428..3d8bfbf5ee8a4 100644 --- a/src/test/ui/span/issue-39698.stderr +++ b/src/test/ui/span/issue-39698.stderr @@ -1,5 +1,5 @@ -error[E0408]: variable `d` from patterns #1, #2 isn't bound in patterns #3, #4 - --> $DIR/issue-39698.rs:20:48 +error[E0408]: variable `d` is not bound in all patterns + --> $DIR/issue-39698.rs:20:37 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | - - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `d` @@ -8,8 +8,8 @@ error[E0408]: variable `d` from patterns #1, #2 isn't bound in patterns #3, #4 | | variable not in all patterns | variable not in all patterns -error[E0408]: variable `c` from pattern #3 isn't bound in patterns #1, #2, #4 - --> $DIR/issue-39698.rs:20:23 +error[E0408]: variable `c` is not bound in all patterns + --> $DIR/issue-39698.rs:20:48 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^^^^ ^^^^^^^^^^^ - ^^^^^^^^ pattern doesn't bind `c` @@ -18,8 +18,8 @@ error[E0408]: variable `c` from pattern #3 isn't bound in patterns #1, #2, #4 | | pattern doesn't bind `c` | pattern doesn't bind `c` -error[E0408]: variable `a` from patterns #1, #4 isn't bound in patterns #2, #3 - --> $DIR/issue-39698.rs:20:23 +error[E0408]: variable `a` is not bound in all patterns + --> $DIR/issue-39698.rs:20:37 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | - ^^^^^^^^^^^ ^^^^^^^^ - variable not in all patterns @@ -28,8 +28,8 @@ error[E0408]: variable `a` from patterns #1, #4 isn't bound in patterns #2, #3 | | pattern doesn't bind `a` | variable not in all patterns -error[E0408]: variable `b` from pattern #2 isn't bound in patterns #1, #3, #4 - --> $DIR/issue-39698.rs:20:48 +error[E0408]: variable `b` is not bound in all patterns + --> $DIR/issue-39698.rs:20:37 | 20 | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?}", a); } | ^^^^^^^^^^^ - ^^^^^^^^ ^^^^^^^^ pattern doesn't bind `b` From 0e45a5ed3f79338656b19a41172d3a7761586ebc Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 16 Feb 2017 20:52:56 +0200 Subject: [PATCH 17/18] [rustbuild] add a way to run command after failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a simple way to workaround the debugging issues caused by the rustc wrapper used in the bootstrap process. Namely, it uses some obscure environment variables and you can’t just copy the failed command and run it in the shell or debugger to examine the failure more closely. With `--on-fail` its possible to run an arbitrary command within exactly the same environment under which rustc failed. Theres’s multiple ways to use this new flag: $ python x.py build --stage=1 --on-fail=env would print a list of environment variables and the failed command, so a few copy-pastes and you now can run the same rust in your shell outside the bootstrap system. $ python x.py build --stage=1 --on-fail=bash Is a more useful variation of the command above in that it launches a whole shell with environment already in place! All that’s left to do is copy-paste the command just above the shell prompt! Fixes #38686 Fixes #38221 --- src/bootstrap/bin/rustc.rs | 18 +++++++++++++++--- src/bootstrap/flags.rs | 3 +++ src/bootstrap/lib.rs | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 90fd31ecbdd73..bf1da57607d5f 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -68,6 +68,7 @@ fn main() { }; let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); + let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc)); let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir)); @@ -212,9 +213,20 @@ fn main() { } // Actually run the compiler! - std::process::exit(match exec_cmd(&mut cmd) { - Ok(s) => s.code().unwrap_or(0xfe), - Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + std::process::exit(if let Some(ref mut on_fail) = on_fail { + match cmd.status() { + Ok(s) if s.success() => 0, + _ => { + println!("\nDid not run successfully:\n{:?}\n-------------", cmd); + exec_cmd(on_fail).expect("could not run the backup command"); + 1 + } + } + } else { + std::process::exit(match exec_cmd(&mut cmd) { + Ok(s) => s.code().unwrap_or(0xfe), + Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + }) }) } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c5bbfd89b2787..b55f3d710ca7b 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -28,6 +28,7 @@ use step; /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose + pub on_fail: Option, pub stage: Option, pub keep_stage: Option, pub build: String, @@ -81,6 +82,7 @@ impl Flags { opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); + opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optopt("", "stage", "stage to build", "N"); opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); @@ -283,6 +285,7 @@ To learn more about a subcommand, run `./x.py -h` Flags { verbose: m.opt_count("v"), stage: stage, + on_fail: m.opt_str("on-fail"), keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), build: m.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 7bd611eb53e3c..a28cb24a8166f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -499,6 +499,10 @@ impl Build { cargo.env("RUSTC_INCREMENTAL", incr_dir); } + if let Some(ref on_fail) = self.flags.on_fail { + cargo.env("RUSTC_ON_FAIL", on_fail); + } + let verbose = cmp::max(self.config.verbose, self.flags.verbose); cargo.env("RUSTC_VERBOSE", format!("{}", verbose)); From 047a215b4d9cf762d3704ee02b76467897bbbe21 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Feb 2017 22:47:11 +0100 Subject: [PATCH 18/18] Set rustdoc --test files' path relative to the current directory --- src/librustdoc/test.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1c37067d7f69d..c7000ee1e40e7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -12,7 +12,7 @@ use std::env; use std::ffi::OsString; use std::io::prelude::*; use std::io; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::panic::{self, AssertUnwindSafe}; use std::process::Command; use std::rc::Rc; @@ -485,7 +485,15 @@ impl Collector { pub fn get_filename(&self) -> String { if let Some(ref codemap) = self.codemap { - codemap.span_to_filename(self.position) + let filename = codemap.span_to_filename(self.position); + if let Ok(cur_dir) = env::current_dir() { + if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) { + if let Some(path) = path.to_str() { + return path.to_owned(); + } + } + } + filename } else if let Some(ref filename) = self.filename { filename.clone() } else {