From f3e9b1a703203be4f375dc5fa3950b642a156ec7 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 10 Nov 2018 20:46:05 -0800 Subject: [PATCH 01/42] in which the E0618 "expected function" diagnostic gets a makeover Now the main span focuses on the erroneous not-a-function callee, while showing the entire call expression is relegated to a secondary span. In the case where the erroneous callee is itself a call, we point out the definition, and, if the call expression spans multiple lines, tentatively suggest a semicolon (because we suspect that the "outer" call is actually supposed to be a tuple). The new `bug!` assertion is, in fact, safe (`confirm_builtin_call` is only called by `check_call`, which is only called with a first arg of kind `ExprKind::Call` in `check_expr_kind`). Resolves #51055. --- src/librustc_typeck/check/callee.rs | 95 ++++++++++++------- src/test/ui/block-result/issue-20862.stderr | 12 ++- .../ui/empty/empty-struct-unit-expr.stderr | 16 +++- src/test/ui/error-codes/E0618.stderr | 8 +- src/test/ui/issues/issue-10969.stderr | 8 +- src/test/ui/issues/issue-18532.stderr | 4 +- src/test/ui/issues/issue-20714.stderr | 4 +- src/test/ui/issues/issue-21701.stderr | 8 +- src/test/ui/issues/issue-22468.stderr | 4 +- src/test/ui/issues/issue-26237.rs | 3 +- src/test/ui/issues/issue-26237.stderr | 6 +- src/test/ui/issues/issue-45965.stderr | 4 +- src/test/ui/issues/issue-46771.stderr | 4 +- src/test/ui/issues/issue-5100.stderr | 4 +- src/test/ui/parse-error-correct.stderr | 4 +- src/test/ui/resolve/privacy-enum-ctor.stderr | 12 ++- ...issing-semicolon-between-call-and-tuple.rs | 8 ++ ...ng-semicolon-between-call-and-tuple.stderr | 16 ++++ 18 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs create mode 100644 src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index de4293aaaea..9b78351c3e1 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -218,35 +218,62 @@ fn confirm_builtin_call(&self, } } - let mut err = type_error_struct!( - self.tcx.sess, - call_expr.span, - callee_ty, - E0618, - "expected function, found {}", - match unit_variant { - Some(ref path) => format!("enum variant `{}`", path), - None => format!("`{}`", callee_ty), - }); + if let hir::ExprKind::Call(ref callee, _) = call_expr.node { + let mut err = type_error_struct!( + self.tcx.sess, + callee.span, + callee_ty, + E0618, + "expected function, found {}", + match unit_variant { + Some(ref path) => format!("enum variant `{}`", path), + None => format!("`{}`", callee_ty), + }); - err.span_label(call_expr.span, "not a function"); + if let Some(ref path) = unit_variant { + err.span_suggestion_with_applicability( + call_expr.span, + &format!("`{}` is a unit variant, you need to write it \ + without the parenthesis", path), + path.to_string(), + Applicability::MachineApplicable + ); + } - if let Some(ref path) = unit_variant { - err.span_suggestion_with_applicability( - call_expr.span, - &format!("`{}` is a unit variant, you need to write it \ - without the parenthesis", path), - path.to_string(), - Applicability::MachineApplicable - ); - } - - if let hir::ExprKind::Call(ref expr, _) = call_expr.node { - let def = if let hir::ExprKind::Path(ref qpath) = expr.node { - self.tables.borrow().qpath_def(qpath, expr.hir_id) - } else { - Def::Err + let mut inner_callee_path = None; + let def = match callee.node { + hir::ExprKind::Path(ref qpath) => { + self.tables.borrow().qpath_def(qpath, callee.hir_id) + }, + hir::ExprKind::Call(ref inner_callee, _) => { + // If the call spans more than one line and the callee kind is + // itself another `ExprCall`, that's a clue that we might just be + // missing a semicolon (Issue #51055) + let call_is_multiline = self.tcx.sess.source_map() + .is_multiline(call_expr.span); + if call_is_multiline { + let span = self.tcx.sess.source_map().next_point(callee.span); + err.span_suggestion_with_applicability( + span, + "try adding a semicolon", + ";".to_owned(), + Applicability::MaybeIncorrect + ); + } + if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.node { + inner_callee_path = Some(inner_qpath); + self.tables.borrow().qpath_def(inner_qpath, inner_callee.hir_id) + } else { + Def::Err + } + }, + _ => { + Def::Err + } }; + + err.span_label(call_expr.span, "call expression requires function"); + let def_span = match def { Def::Err => None, Def::Local(id) | Def::Upvar(id, ..) => { @@ -255,16 +282,20 @@ fn confirm_builtin_call(&self, _ => self.tcx.hir.span_if_local(def.def_id()) }; if let Some(span) = def_span { - let name = match unit_variant { - Some(path) => path, - None => callee_ty.to_string(), + let label = match (unit_variant, inner_callee_path) { + (Some(path), _) => format!("`{}` defined here", path), + (_, Some(hir::QPath::Resolved(_, path))) => format!( + "`{}` defined here returns `{}`", path, callee_ty.to_string() + ), + _ => format!("`{}` defined here", callee_ty.to_string()), }; - err.span_label(span, format!("`{}` defined here", name)); + err.span_label(span, label); } + err.emit(); + } else { + bug!("call_expr.node should be an ExprKind::Call, got {:?}", call_expr.node); } - err.emit(); - // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index 990fb404c94..194cfab8527 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -12,8 +12,16 @@ LL | |y| x + y error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:17:13 | -LL | let x = foo(5)(2); - | ^^^^^^^^^ not a function +LL | / fn foo(x: i32) { +LL | | |y| x + y +LL | | //~^ ERROR: mismatched types +LL | | } + | |_- `foo` defined here returns `()` +... +LL | let x = foo(5)(2); + | ^^^^^^--- + | | + | call expression requires function error: aborting due to 2 previous errors diff --git a/src/test/ui/empty/empty-struct-unit-expr.stderr b/src/test/ui/empty/empty-struct-unit-expr.stderr index fff696fc80f..360e0c6f107 100644 --- a/src/test/ui/empty/empty-struct-unit-expr.stderr +++ b/src/test/ui/empty/empty-struct-unit-expr.stderr @@ -5,7 +5,9 @@ LL | struct Empty2; | -------------- `Empty2` defined here ... LL | let e2 = Empty2(); //~ ERROR expected function, found `Empty2` - | ^^^^^^^^ not a function + | ^^^^^^-- + | | + | call expression requires function error[E0618]: expected function, found enum variant `E::Empty4` --> $DIR/empty-struct-unit-expr.rs:26:14 @@ -14,7 +16,9 @@ LL | Empty4 | ------ `E::Empty4` defined here ... LL | let e4 = E::Empty4(); - | ^^^^^^^^^^^ not a function + | ^^^^^^^^^-- + | | + | call expression requires function help: `E::Empty4` is a unit variant, you need to write it without the parenthesis | LL | let e4 = E::Empty4; @@ -24,13 +28,17 @@ error[E0618]: expected function, found `empty_struct::XEmpty2` --> $DIR/empty-struct-unit-expr.rs:28:15 | LL | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` - | ^^^^^^^^^ not a function + | ^^^^^^^-- + | | + | call expression requires function error[E0618]: expected function, found enum variant `XE::XEmpty4` --> $DIR/empty-struct-unit-expr.rs:29:15 | LL | let xe4 = XE::XEmpty4(); - | ^^^^^^^^^^^^^ not a function + | ^^^^^^^^^^^-- + | | + | call expression requires function help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis | LL | let xe4 = XE::XEmpty4; diff --git a/src/test/ui/error-codes/E0618.stderr b/src/test/ui/error-codes/E0618.stderr index ef7ace44d59..3bcc83e01c1 100644 --- a/src/test/ui/error-codes/E0618.stderr +++ b/src/test/ui/error-codes/E0618.stderr @@ -5,7 +5,9 @@ LL | Entry, | ----- `X::Entry` defined here ... LL | X::Entry(); - | ^^^^^^^^^^ not a function + | ^^^^^^^^-- + | | + | call expression requires function help: `X::Entry` is a unit variant, you need to write it without the parenthesis | LL | X::Entry; @@ -17,7 +19,9 @@ error[E0618]: expected function, found `i32` LL | let x = 0i32; | - `i32` defined here LL | x(); - | ^^^ not a function + | ^-- + | | + | call expression requires function error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-10969.stderr b/src/test/ui/issues/issue-10969.stderr index edc4ecbab52..d04108ca39e 100644 --- a/src/test/ui/issues/issue-10969.stderr +++ b/src/test/ui/issues/issue-10969.stderr @@ -4,7 +4,9 @@ error[E0618]: expected function, found `i32` LL | fn func(i: i32) { | - `i32` defined here LL | i(); //~ERROR expected function, found `i32` - | ^^^ not a function + | ^-- + | | + | call expression requires function error[E0618]: expected function, found `i32` --> $DIR/issue-10969.rs:16:5 @@ -12,7 +14,9 @@ error[E0618]: expected function, found `i32` LL | let i = 0i32; | - `i32` defined here LL | i(); //~ERROR expected function, found `i32` - | ^^^ not a function + | ^-- + | | + | call expression requires function error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-18532.stderr b/src/test/ui/issues/issue-18532.stderr index 8f10cb0f7b0..c297c20069e 100644 --- a/src/test/ui/issues/issue-18532.stderr +++ b/src/test/ui/issues/issue-18532.stderr @@ -2,7 +2,9 @@ error[E0618]: expected function, found `!` --> $DIR/issue-18532.rs:16:5 | LL | (return)((),()); //~ ERROR expected function, found `!` - | ^^^^^^^^^^^^^^^ not a function + | ^^^^^^^^------- + | | + | call expression requires function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20714.stderr b/src/test/ui/issues/issue-20714.stderr index 1ea85ee440e..70a9736d2a2 100644 --- a/src/test/ui/issues/issue-20714.stderr +++ b/src/test/ui/issues/issue-20714.stderr @@ -5,7 +5,9 @@ LL | struct G; | --------- `G` defined here ... LL | let g = G(); //~ ERROR: expected function, found `G` - | ^^^ not a function + | ^-- + | | + | call expression requires function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21701.stderr b/src/test/ui/issues/issue-21701.stderr index 9fb9a7b51f2..b94e0833a58 100644 --- a/src/test/ui/issues/issue-21701.stderr +++ b/src/test/ui/issues/issue-21701.stderr @@ -4,7 +4,9 @@ error[E0618]: expected function, found `U` LL | fn foo(t: U) { | - `U` defined here LL | let y = t(); - | ^^^ not a function + | ^-- + | | + | call expression requires function error[E0618]: expected function, found `Bar` --> $DIR/issue-21701.rs:19:13 @@ -13,7 +15,9 @@ LL | struct Bar; | ----------- `Bar` defined here ... LL | let f = Bar(); - | ^^^^^ not a function + | ^^^-- + | | + | call expression requires function error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-22468.stderr b/src/test/ui/issues/issue-22468.stderr index 034a076fbfe..af32c0e20ce 100644 --- a/src/test/ui/issues/issue-22468.stderr +++ b/src/test/ui/issues/issue-22468.stderr @@ -4,7 +4,9 @@ error[E0618]: expected function, found `&str` LL | let foo = "bar"; | --- `&str` defined here LL | let x = foo("baz"); - | ^^^^^^^^^^ not a function + | ^^^------- + | | + | call expression requires function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26237.rs b/src/test/ui/issues/issue-26237.rs index 22772e596b1..ffffe6d3ab5 100644 --- a/src/test/ui/issues/issue-26237.rs +++ b/src/test/ui/issues/issue-26237.rs @@ -11,7 +11,6 @@ macro_rules! macro_panic { ($not_a_function:expr, $some_argument:ident) => { $not_a_function($some_argument) - //~^ ERROR expected function, found `{integer}` } } @@ -19,5 +18,5 @@ fn main() { let mut value_a = 0; let mut value_b = 0; macro_panic!(value_a, value_b); - //~^ in this expansion of macro_panic! + //~^ ERROR expected function, found `{integer}` } diff --git a/src/test/ui/issues/issue-26237.stderr b/src/test/ui/issues/issue-26237.stderr index ae6fda8b932..7f481c230ba 100644 --- a/src/test/ui/issues/issue-26237.stderr +++ b/src/test/ui/issues/issue-26237.stderr @@ -1,14 +1,14 @@ error[E0618]: expected function, found `{integer}` - --> $DIR/issue-26237.rs:13:9 + --> $DIR/issue-26237.rs:20:18 | LL | $not_a_function($some_argument) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a function + | ------------------------------- call expression requires function ... LL | let mut value_a = 0; | ----------- `{integer}` defined here LL | let mut value_b = 0; LL | macro_panic!(value_a, value_b); - | ------------------------------- in this macro invocation + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-45965.stderr b/src/test/ui/issues/issue-45965.stderr index 2b3870feef3..b7b5f76395a 100644 --- a/src/test/ui/issues/issue-45965.stderr +++ b/src/test/ui/issues/issue-45965.stderr @@ -2,7 +2,9 @@ error[E0618]: expected function, found `{float}` --> $DIR/issue-45965.rs:12:30 | LL | let a = |r: f64| if r != 0.0(r != 0.0) { 1.0 } else { 0.0 }; - | ^^^^^^^^^^^^^ not a function + | ^^^---------- + | | + | call expression requires function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-46771.stderr b/src/test/ui/issues/issue-46771.stderr index 0d57d61e9ff..90adb3ed73f 100644 --- a/src/test/ui/issues/issue-46771.stderr +++ b/src/test/ui/issues/issue-46771.stderr @@ -4,7 +4,9 @@ error[E0618]: expected function, found `main::Foo` LL | struct Foo; | ----------- `main::Foo` defined here LL | (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo` - | ^^^^^^ not a function + | ^^^--- + | | + | call expression requires function error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index 6f5a84966bf..305ee2f5471 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -47,9 +47,9 @@ error[E0618]: expected function, found `(char, char)` --> $DIR/issue-5100.rs:58:14 | LL | let v = [('a', 'b') //~ ERROR expected function, found `(char, char)` - | ______________^ + | ______________-^^^^^^^^^ LL | | ('c', 'd'), - | |_______________________^ not a function + | |_______________________- call expression requires function error[E0308]: mismatched types --> $DIR/issue-5100.rs:65:19 diff --git a/src/test/ui/parse-error-correct.stderr b/src/test/ui/parse-error-correct.stderr index 3eb0b19a6aa..9c87806da9e 100644 --- a/src/test/ui/parse-error-correct.stderr +++ b/src/test/ui/parse-error-correct.stderr @@ -17,7 +17,9 @@ LL | let y = 42; | - `{integer}` defined here LL | let x = y.; //~ ERROR unexpected token LL | let x = y.(); //~ ERROR unexpected token - | ^^^^ not a function + | ^--- + | | + | call expression requires function error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/parse-error-correct.rs:21:15 diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 8e08f124d68..01e6488de53 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -171,7 +171,9 @@ LL | Unit, | ---- `Z::Unit` defined here ... LL | let _ = Z::Unit(); - | ^^^^^^^^^ not a function + | ^^^^^^^-- + | | + | call expression requires function help: `Z::Unit` is a unit variant, you need to write it without the parenthesis | LL | let _ = Z::Unit; @@ -193,7 +195,9 @@ LL | Unit, | ---- `m::E::Unit` defined here ... LL | let _: E = m::E::Unit(); - | ^^^^^^^^^^^^ not a function + | ^^^^^^^^^^-- + | | + | call expression requires function help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis | LL | let _: E = m::E::Unit; @@ -215,7 +219,9 @@ LL | Unit, | ---- `E::Unit` defined here ... LL | let _: E = E::Unit(); - | ^^^^^^^^^ not a function + | ^^^^^^^-- + | | + | call expression requires function help: `E::Unit` is a unit variant, you need to write it without the parenthesis | LL | let _: E = E::Unit; diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs new file mode 100644 index 00000000000..37f078285d6 --- /dev/null +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs @@ -0,0 +1,8 @@ +fn vindictive() -> bool { true } + +fn perfidy() -> (i32, i32) { + vindictive() //~ ERROR expected function, found `bool` + (1, 2) +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr new file mode 100644 index 00000000000..40ddb5ec53c --- /dev/null +++ b/src/test/ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.stderr @@ -0,0 +1,16 @@ +error[E0618]: expected function, found `bool` + --> $DIR/issue-51055-missing-semicolon-between-call-and-tuple.rs:4:5 + | +LL | fn vindictive() -> bool { true } + | -------------------------------- `vindictive` defined here returns `bool` +... +LL | vindictive() //~ ERROR expected function, found `bool` + | -^^^^^^^^^^^- help: try adding a semicolon: `;` + | _____| + | | +LL | | (1, 2) + | |__________- call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. From b7c319c56ae8380aa2ab03d2b9b6702ae43d49b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:43:33 +0100 Subject: [PATCH 02/42] do not panic just because cargo failed --- src/bootstrap/compile.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cef0849937b..71b204b2de9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -22,7 +22,7 @@ use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Stdio, exit}; use std::str; use build_helper::{output, mtime, up_to_date}; @@ -1098,7 +1098,7 @@ pub fn run_cargo(builder: &Builder, }); if !ok { - panic!("cargo must succeed"); + exit(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've From 0671bdb1ebf61a2d8528738392e0a01c1436d49f Mon Sep 17 00:00:00 2001 From: giacomo Date: Sun, 11 Nov 2018 21:17:47 +0100 Subject: [PATCH 03/42] reword #[test] attribute error on fn items --- src/libsyntax_ext/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index be3485cfa7c..b8a171b52ad 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -53,7 +53,7 @@ pub fn expand_test_or_bench( if let Annotatable::Item(i) = item { i } else { cx.parse_sess.span_diagnostic.span_fatal(item.span(), - "#[test] attribute is only allowed on fn items").raise(); + "#[test] attribute is only allowed on non associated functions").raise(); }; if let ast::ItemKind::Mac(_) = item.node { From 0c085299344d9af4e9bfd892a15d746b116ebe00 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Mon, 5 Nov 2018 15:30:04 +0100 Subject: [PATCH 04/42] A few tweaks to iterations/collecting --- src/librustc/cfg/graphviz.rs | 3 +-- src/librustc/hir/lowering.rs | 3 +-- src/librustc/ty/query/on_disk_cache.rs | 2 +- src/libserialize/hex.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 18 ++++++++---------- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs index cc4f3f95d07..650aa39114f 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc/cfg/graphviz.rs @@ -106,8 +106,7 @@ impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { type Node = Node<'a>; type Edge = Edge<'a>; fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { - let mut v = Vec::new(); - self.graph.each_node(|i, nd| { v.push((i, nd)); true }); + let v: Vec<_> = self.graph.enumerated_nodes().collect(); v.into() } fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd5d4b8f6af..4f94b427ec1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1062,8 +1062,7 @@ fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec { attrs .iter() .map(|a| self.lower_attr(a)) - .collect::>() - .into() + .collect() } fn lower_attr(&mut self, attr: &Attribute) -> Attribute { diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 54550b8a205..7d3ae64f4fc 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -281,7 +281,7 @@ pub fn serialize<'a, 'tcx, E>(&self, // otherwise, abort break; } - interpret_alloc_index.reserve(new_n); + interpret_alloc_index.reserve(new_n - n); for idx in n..new_n { let id = encoder.interpret_allocs_inverse[idx]; let pos = encoder.position() as u32; diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 7f3736e82ca..5604729d2f8 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -146,7 +146,7 @@ fn from_hex(&self) -> Result, FromHexError> { } match modulus { - 0 => Ok(b.into_iter().collect()), + 0 => Ok(b), _ => Err(InvalidHexLength), } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index dd90ef06c39..bfdb53a9d9e 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1200,16 +1200,14 @@ fn build_enum_match_tuple<'b>(&self, let sp = trait_.span; let variants = &enum_def.variants; - let self_arg_names = self_args.iter() - .enumerate() - .map(|(arg_count, _self_arg)| { - if arg_count == 0 { - "__self".to_string() - } else { + let self_arg_names = iter::once("__self".to_string()).chain( + self_args.iter() + .enumerate() + .skip(1) + .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count) - } - }) - .collect::>(); + ) + ).collect::>(); let self_arg_idents = self_arg_names.iter() .map(|name| cx.ident_of(&name[..])) @@ -1218,7 +1216,7 @@ fn build_enum_match_tuple<'b>(&self, // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. - let vi_idents: Vec = self_arg_names.iter() + let vi_idents = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); cx.ident_of(&vi_suffix[..]).gensym() From 562be7e1a1955742d61320d0855550794c4b6c22 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 8 Nov 2018 20:12:05 +0100 Subject: [PATCH 05/42] Forward the ABI of the non-zero sized fields of an union if they have the same ABI This is supposed to fix the performence regression of using MaybeUninit in https://github.com/rust-lang/rust/pull/54668 --- src/librustc/ty/layout.rs | 35 ++++++++++++++- src/librustc/ty/mod.rs | 6 +++ src/test/codegen/union-abi.rs | 80 +++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/union-abi.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 877bd5a82e6..0b00cfc2d7f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -697,7 +697,9 @@ enum StructKind { Align::from_bytes(repr_align, repr_align).unwrap()); } + let optimize = !def.repr.inhibit_union_abi_opt(); let mut size = Size::ZERO; + let mut abi = Abi::Aggregate { sized: true }; let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); @@ -708,13 +710,44 @@ enum StructKind { } else { align = align.max(field.align); } + + // If all non-ZST fields have the same ABI, forward this ABI + if optimize && !field.is_zst() { + // Normalize scalar_unit to the maximal valid range + let field_abi = match &field.abi { + Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), + Abi::ScalarPair(x, y) => { + Abi::ScalarPair( + scalar_unit(x.value), + scalar_unit(y.value), + ) + } + Abi::Vector { element: x, count } => { + Abi::Vector { + element: scalar_unit(x.value), + count: *count, + } + } + Abi::Uninhabited | + Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + }; + + if size == Size::ZERO { + // first non ZST: initialize 'abi' + abi = field_abi; + } else if abi != field_abi { + // different fields have different ABI: reset to Aggregate + abi = Abi::Aggregate { sized: true }; + } + } + size = cmp::max(size, field.size); } return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), - abi: Abi::Aggregate { sized: true }, + abi, align, size: size.abi_align(align) })); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 83feadd50d7..9553d124483 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1994,6 +1994,12 @@ pub fn inhibit_enum_layout_opt(&self) -> bool { pub fn inhibit_struct_field_reordering_opt(&self) -> bool { !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) } + + /// Returns true if this `#[repr()]` should inhibit union abi optimisations + pub fn inhibit_union_abi_opt(&self) -> bool { + self.c() + } + } impl<'a, 'gcx, 'tcx> AdtDef { diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs new file mode 100644 index 00000000000..0fa06fa777b --- /dev/null +++ b/src/test/codegen/union-abi.rs @@ -0,0 +1,80 @@ +// 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. + +// compile-flags: -C no-prepopulate-passes + +// This test that using union forward the abi of the inner type, as +// discussed in #54668 + +#![crate_type="lib"] +#![feature(repr_simd)] + +#[derive(Copy, Clone)] +pub enum Unhab {} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i64x4(i64, i64, i64, i64); + +#[derive(Copy, Clone)] +pub union UnionI64x4{ a:(), b: i64x4 } + +// CHECK: define <4 x i64> @test_UnionI64x4(<4 x i64> %arg0) +#[no_mangle] +pub extern fn test_UnionI64x4(_: UnionI64x4) -> UnionI64x4 { loop {} } + +pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } + +// CHECK: define <4 x i64> @test_UnionI64x4_(<4 x i64> %arg0) +#[no_mangle] +pub extern fn test_UnionI64x4_(_: UnionI64x4_) -> UnionI64x4_ { loop {} } + +pub union UnionI64x4I64{ a: i64x4, b: i64 } + +// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} } + +pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) } + +// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} } + + +pub union UnionF32{a:f32} + +// CHECK: define float @test_UnionF32(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } + +pub union UnionF32F32{a:f32, b:f32} + +// CHECK: define float @test_UnionF32F32(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } + +pub union UnionF32U32{a:f32, b:u32} + +// CHECK: define i32 @test_UnionF32U32(i32) +#[no_mangle] +pub extern fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } + +pub union UnionU128{a:u128} +// CHECK: define i128 @test_UnionU128(i128 %arg0) +#[no_mangle] +pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } + +#[repr(C)] +pub union CUnionU128{a:u128} +// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0) +#[no_mangle] +pub fn test_CUnionU128(_: CUnionU128) { loop {} } + From cfbae3e1940f75fa1f5f99bf60f68ed9756a202b Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 13:19:24 +0100 Subject: [PATCH 06/42] core/tests/num: Simplify `test_int_from_str_overflow()` test code This commit changes the test code to compare against easier-to-read, static values instead of relying on the result of `wrapping_add()` which may or may not result in the value that we expect. --- src/libcore/tests/num/mod.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index ab96d3126bb..0928f7560e1 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -82,36 +82,28 @@ fn from_str_issue7588() { #[test] fn test_int_from_str_overflow() { - let mut i8_val: i8 = 127; - assert_eq!("127".parse::().ok(), Some(i8_val)); + assert_eq!("127".parse::().ok(), Some(127i8)); assert_eq!("128".parse::().ok(), None); - i8_val = i8_val.wrapping_add(1); - assert_eq!("-128".parse::().ok(), Some(i8_val)); + assert_eq!("-128".parse::().ok(), Some(-128i8)); assert_eq!("-129".parse::().ok(), None); - let mut i16_val: i16 = 32_767; - assert_eq!("32767".parse::().ok(), Some(i16_val)); + assert_eq!("32767".parse::().ok(), Some(32_767i16)); assert_eq!("32768".parse::().ok(), None); - i16_val = i16_val.wrapping_add(1); - assert_eq!("-32768".parse::().ok(), Some(i16_val)); + assert_eq!("-32768".parse::().ok(), Some(-32_768i16)); assert_eq!("-32769".parse::().ok(), None); - let mut i32_val: i32 = 2_147_483_647; - assert_eq!("2147483647".parse::().ok(), Some(i32_val)); + assert_eq!("2147483647".parse::().ok(), Some(2_147_483_647i32)); assert_eq!("2147483648".parse::().ok(), None); - i32_val = i32_val.wrapping_add(1); - assert_eq!("-2147483648".parse::().ok(), Some(i32_val)); + assert_eq!("-2147483648".parse::().ok(), Some(-2_147_483_648i32)); assert_eq!("-2147483649".parse::().ok(), None); - let mut i64_val: i64 = 9_223_372_036_854_775_807; - assert_eq!("9223372036854775807".parse::().ok(), Some(i64_val)); + assert_eq!("9223372036854775807".parse::().ok(), Some(9_223_372_036_854_775_807i64)); assert_eq!("9223372036854775808".parse::().ok(), None); - i64_val = i64_val.wrapping_add(1); - assert_eq!("-9223372036854775808".parse::().ok(), Some(i64_val)); + assert_eq!("-9223372036854775808".parse::().ok(), Some(-9_223_372_036_854_775_808i64)); assert_eq!("-9223372036854775809".parse::().ok(), None); } From 57a7c85f93d78b507c3779944b2978c617f91c5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 17:25:06 +0100 Subject: [PATCH 07/42] miri: backtraces with instances --- src/librustc/ich/impls_ty.rs | 4 +-- src/librustc/mir/interpret/error.rs | 33 +++++++++++++++++----- src/librustc_mir/interpret/eval_context.rs | 15 ++-------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9..d8b207fa25a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -387,10 +387,10 @@ fn hash_stable( TooGeneric }); -impl_stable_hash_for!(struct mir::interpret::FrameInfo { +impl_stable_hash_for!(struct mir::interpret::FrameInfo<'tcx> { span, lint_root, - location + instance }); impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed42..c30d41f3403 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -10,8 +10,9 @@ use std::{fmt, env}; +use hir::map::definitions::DefPathData; use mir; -use ty::{Ty, layout}; +use ty::{self, Ty, layout}; use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; @@ -19,7 +20,6 @@ use backtrace::Backtrace; -use ty; use ty::query::TyCtxtAt; use errors::DiagnosticBuilder; @@ -52,16 +52,30 @@ pub fn assert_reported(self) { pub struct ConstEvalErr<'tcx> { pub span: Span, pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>, - pub stacktrace: Vec, + pub stacktrace: Vec>, } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct FrameInfo { +pub struct FrameInfo<'tcx> { pub span: Span, - pub location: String, + pub instance: ty::Instance<'tcx>, pub lint_root: Option, } +impl<'tcx> fmt::Display for FrameInfo<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(|tcx| { + if tcx.def_key(self.instance.def_id()).disambiguated_data.data + == DefPathData::ClosureExpr + { + write!(f, "inside call to closure") + } else { + write!(f, "inside call to `{}`", self.instance) + } + }) + } +} + impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { pub fn struct_error(&self, tcx: TyCtxtAt<'a, 'gcx, 'tcx>, @@ -135,8 +149,13 @@ fn struct_generic( struct_error(tcx, message) }; err.span_label(self.span, self.error.to_string()); - for FrameInfo { span, location, .. } in &self.stacktrace { - err.span_label(*span, format!("inside call to `{}`", location)); + // Skip the last, which is just the environment of the constant. The stacktrace + // is sometimes empty because we create "fake" eval contexts in CTFE to do work + // on constant values. + if self.stacktrace.len() > 0 { + for frame_info in &self.stacktrace[..self.stacktrace.len()-1] { + err.span_label(frame_info.span, frame_info.to_string()); + } } Ok(err) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6267012dc2..279955fba17 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,7 +14,6 @@ use syntax::source_map::{self, Span, DUMMY_SP}; use rustc::hir::def_id::DefId; use rustc::hir::def::Def; -use rustc::hir::map::definitions::DefPathData; use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout @@ -654,11 +653,10 @@ pub fn dump_place(&self, place: Place) { } } - pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec { + pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec> { let mut last_span = None; let mut frames = Vec::new(); - // skip 1 because the last frame is just the environment of the constant - for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() { + for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().rev() { // make sure we don't emit frames that are duplicates of the previous if explicit_span == Some(span) { last_span = Some(span); @@ -671,13 +669,6 @@ pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec } else { last_span = Some(span); } - let location = if self.tcx.def_key(instance.def_id()).disambiguated_data.data - == DefPathData::ClosureExpr - { - "closure".to_owned() - } else { - instance.to_string() - }; let block = &mir.basic_blocks()[block]; let source_info = if stmt < block.statements.len() { block.statements[stmt].source_info @@ -688,7 +679,7 @@ pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root), mir::ClearCrossCrate::Clear => None, }; - frames.push(FrameInfo { span, location, lint_root }); + frames.push(FrameInfo { span, instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames From 2ec6f340cd29f289fea1c5a672195ceeaf44c475 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Nov 2018 17:41:54 +0100 Subject: [PATCH 08/42] Update CI-clang to 7.0.0 for Linux dists. --- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/build-clang.sh | 2 +- src/ci/docker/scripts/musl.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8df49f364a3..b087ea7899f 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 0a2dae72f73..a1a778c2b2c 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh index 4595eacb310..2762f0bf7ec 100755 --- a/src/ci/docker/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -13,7 +13,7 @@ set -ex source shared.sh -LLVM=6.0.0 +LLVM=7.0.0 mkdir clang cd clang diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index fcebfb93247..11d85471b7c 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -51,7 +51,7 @@ hide_output make clean cd .. -LLVM=60 +LLVM=70 # may have been downloaded in a previous run if [ ! -d libunwind-release_$LLVM ]; then From f6b8eb7987fd824d576598c152de1b3144c137bb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Nov 2018 17:42:53 +0100 Subject: [PATCH 09/42] Update CI-clang to 7.0.0 for macOS dists. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b208e760d95..14fb17aeedd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -227,9 +227,9 @@ install: chmod +x /usr/local/bin/sccache && travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp && - travis_retry curl -f http://releases.llvm.org/6.0.0/clang+llvm-6.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && - export CC=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang && - export CXX=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang++ && + travis_retry curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && + export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang && + export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++ && export AR=ar ;; esac From fb5135a6fc7e1517c562ea182827533354ae327d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 17:48:17 +0100 Subject: [PATCH 10/42] prettier miri backtrace printing --- src/librustc/mir/interpret/error.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index c30d41f3403..e1b22c64ed6 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -191,16 +191,23 @@ fn print_backtrace(backtrace: &mut Backtrace) -> String { write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap(); 'frames: for (i, frame) in backtrace.frames().iter().enumerate() { if frame.symbols().is_empty() { - write!(trace_text, "{}: no symbols\n", i).unwrap(); + write!(trace_text, " {}: no symbols\n", i).unwrap(); } + let mut first = true; for symbol in frame.symbols() { - write!(trace_text, "{}: ", i).unwrap(); + if first { + write!(trace_text, " {}: ", i).unwrap(); + first = false; + } else { + let len = i.to_string().len(); + write!(trace_text, " {} ", " ".repeat(len)).unwrap(); + } if let Some(name) = symbol.name() { write!(trace_text, "{}\n", name).unwrap(); } else { write!(trace_text, "\n").unwrap(); } - write!(trace_text, "\tat ").unwrap(); + write!(trace_text, " at ").unwrap(); if let Some(file_path) = symbol.filename() { write!(trace_text, "{}", file_path.display()).unwrap(); } else { From 1ca505a30adb1d392d3166a34ec40b0bf584acf9 Mon Sep 17 00:00:00 2001 From: Blitzerr Date: Wed, 14 Nov 2018 08:41:16 -0800 Subject: [PATCH 11/42] capture_disjoint_fields(rust-lang#53488) Just running RustFmt on upvar.rs --- src/librustc_typeck/check/upvar.rs | 146 ++++++++++++++--------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index df994ad9e55..ef29e13d9fe 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,14 +45,14 @@ use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; -use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; -use rustc::infer::UpvarRegion; -use syntax::ast; -use syntax_pos::Span; use rustc::hir; +use rustc::hir::def_id::DefId; use rustc::hir::def_id::LocalDefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc::infer::UpvarRegion; +use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use syntax::ast; +use syntax_pos::Span; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -121,7 +121,7 @@ fn analyze_closure( } }; - let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs{ + let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { if self.closure_kind(closure_def_id, closure_substs).is_none() { Some(closure_substs) } else { @@ -213,12 +213,11 @@ fn analyze_closure( let final_upvar_tys = self.final_upvar_tys(closure_node_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", - closure_node_id, - substs, - final_upvar_tys + closure_node_id, substs, final_upvar_tys ); - for (upvar_ty, final_upvar_ty) in substs.upvar_tys(closure_def_id, self.tcx) - .zip(final_upvar_tys) + for (upvar_ty, final_upvar_ty) in substs + .upvar_tys(closure_def_id, self.tcx) + .zip(final_upvar_tys) { self.demand_suptype(span, upvar_ty, final_upvar_ty); } @@ -256,9 +255,7 @@ fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { debug!( "var_id={:?} freevar_ty={:?} capture={:?}", - var_node_id, - freevar_ty, - capture + var_node_id, freevar_ty, capture ); match capture { @@ -271,8 +268,7 @@ fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { }, ), } - }) - .collect() + }).collect() }) } } @@ -301,12 +297,14 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { - fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn adjust_upvar_borrow_kind_for_consume( + &mut self, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!( "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", - cmt, - mode + cmt, mode ); // we only care about moves @@ -381,9 +379,9 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is // mutable, so iterate to the base. self.adjust_upvar_borrow_kind_for_mut(&base); @@ -399,12 +397,12 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::cmt_<'tcx>) { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => { + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => { return; } } @@ -414,9 +412,9 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is // unique. self.adjust_upvar_borrow_kind_for_unique(&base); @@ -430,18 +428,20 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::cmt_<'tcx>) { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => {} + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => {} } } - fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::BorrowKind) - -> bool - { + fn try_adjust_upvar_deref( + &mut self, + cmt: &mc::cmt_<'tcx>, + borrow_kind: ty::BorrowKind, + ) -> bool { assert!(match borrow_kind { ty::MutBorrow => true, ty::UniqueImmBorrow => true, @@ -493,15 +493,14 @@ fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::Borr /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { - let upvar_capture = self.adjust_upvar_captures + let upvar_capture = self + .adjust_upvar_captures .get(&upvar_id) .cloned() .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); debug!( "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", - upvar_id, - upvar_capture, - kind + upvar_id, upvar_capture, kind ); match upvar_capture { @@ -511,18 +510,18 @@ fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKi ty::UpvarCapture::ByRef(mut upvar_borrow) => { match (upvar_borrow.kind, kind) { // Take RHS: - (ty::ImmBorrow, ty::UniqueImmBorrow) | - (ty::ImmBorrow, ty::MutBorrow) | - (ty::UniqueImmBorrow, ty::MutBorrow) => { + (ty::ImmBorrow, ty::UniqueImmBorrow) + | (ty::ImmBorrow, ty::MutBorrow) + | (ty::UniqueImmBorrow, ty::MutBorrow) => { upvar_borrow.kind = kind; self.adjust_upvar_captures .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); } // Take LHS: - (ty::ImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::UniqueImmBorrow) | - (ty::MutBorrow, _) => {} + (ty::ImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) + | (ty::MutBorrow, _) => {} } } } @@ -537,10 +536,7 @@ fn adjust_closure_kind( ) { debug!( "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", - closure_id, - new_kind, - upvar_span, - var_name + closure_id, new_kind, upvar_span, var_name ); // Is this the closure whose kind is currently being inferred? @@ -554,22 +550,20 @@ fn adjust_closure_kind( debug!( "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", - closure_id, - existing_kind, - new_kind + closure_id, existing_kind, new_kind ); match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) + | (ty::ClosureKind::FnOnce, _) => { // no change needed } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) + | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind self.current_closure_kind = new_kind; self.current_origin = Some((upvar_span, var_name)); @@ -590,12 +584,20 @@ fn consume( self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } - fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: &mc::cmt_<'tcx>, - _mode: euv::MatchMode) { + fn matched_pat( + &mut self, + _matched_pat: &hir::Pat, + _cmt: &mc::cmt_<'tcx>, + _mode: euv::MatchMode, + ) { } - fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn consume_pat( + &mut self, + _consume_pat: &hir::Pat, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } @@ -611,9 +613,7 @@ fn borrow( ) { debug!( "borrow(borrow_id={}, cmt={:?}, bk={:?})", - borrow_id, - cmt, - bk + borrow_id, cmt, bk ); match bk { From c040a483bcb522b60865130ea5e94e2ef2915f94 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 14 Nov 2018 18:09:54 +0100 Subject: [PATCH 12/42] Remove extern and some return value as an attempt to make the test pass on more platforms --- src/test/codegen/union-abi.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index 0fa06fa777b..786968128ec 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -26,15 +26,15 @@ pub enum Unhab {} #[derive(Copy, Clone)] pub union UnionI64x4{ a:(), b: i64x4 } -// CHECK: define <4 x i64> @test_UnionI64x4(<4 x i64> %arg0) +// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0) #[no_mangle] -pub extern fn test_UnionI64x4(_: UnionI64x4) -> UnionI64x4 { loop {} } +pub fn test_UnionI64x4(_: UnionI64x4) { loop {} } pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } -// CHECK: define <4 x i64> @test_UnionI64x4_(<4 x i64> %arg0) +// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0) #[no_mangle] -pub extern fn test_UnionI64x4_(_: UnionI64x4_) -> UnionI64x4_ { loop {} } +pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} } pub union UnionI64x4I64{ a: i64x4, b: i64 } @@ -53,19 +53,19 @@ pub union UnionF32{a:f32} // CHECK: define float @test_UnionF32(float %arg0) #[no_mangle] -pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } +pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } pub union UnionF32F32{a:f32, b:f32} // CHECK: define float @test_UnionF32F32(float %arg0) #[no_mangle] -pub extern fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } +pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } pub union UnionF32U32{a:f32, b:u32} // CHECK: define i32 @test_UnionF32U32(i32) #[no_mangle] -pub extern fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } +pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } pub union UnionU128{a:u128} // CHECK: define i128 @test_UnionU128(i128 %arg0) From b396505425ab0b0efbc5f399767c6983fc3511e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 23:14:57 +0100 Subject: [PATCH 13/42] put file and line into miri backtrace --- src/librustc/mir/interpret/error.rs | 11 +- .../infinite-recursion-const-fn.stderr | 102 +++++++++--------- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index e1b22c64ed6..d375e62b27c 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -23,7 +23,7 @@ use ty::query::TyCtxtAt; use errors::DiagnosticBuilder; -use syntax_pos::Span; +use syntax_pos::{Pos, Span}; use syntax::ast; use syntax::symbol::Symbol; @@ -68,10 +68,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::ClosureExpr { - write!(f, "inside call to closure") + write!(f, "inside call to closure")?; } else { - write!(f, "inside call to `{}`", self.instance) + write!(f, "inside call to `{}`", self.instance)?; } + if !self.span.is_dummy() { + let lo = tcx.sess.source_map().lookup_char_pos_adj(self.span.lo()); + write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?; + } + Ok(()) }) } } diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index ef35bb6d98d..4246ec2dad3 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -5,61 +5,61 @@ LL | const fn a() -> usize { b() } //~ ERROR evaluation of constant value failed | ^^^ | | | reached the configured maximum number of stack frames - | inside call to `b` + | inside call to `b` at $DIR/infinite-recursion-const-fn.rs:13:25 LL | const fn b() -> usize { a() } | --- | | - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` - | inside call to `a` + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 + | inside call to `a` at $DIR/infinite-recursion-const-fn.rs:14:25 LL | const ARR: [i32; a()] = [5; 6]; - | --- inside call to `a` + | --- inside call to `a` at $DIR/infinite-recursion-const-fn.rs:15:18 error: aborting due to previous error From aa3d7a4e6e62aad4f96d7f0b547853641d980eca Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 14 Nov 2018 18:14:31 -0600 Subject: [PATCH 14/42] properly calculate spans for intra-doc link resolution errors --- .../passes/collect_intra_doc_links.rs | 2 +- .../rustdoc-ui/intra-link-span-ice-55723.rs | 24 +++++++++++++++++++ .../intra-link-span-ice-55723.stderr | 13 ++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc-ui/intra-link-span-ice-55723.rs create mode 100644 src/test/rustdoc-ui/intra-link-span-ice-55723.stderr diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a780322e85e..f25aa000d80 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -527,7 +527,7 @@ fn resolution_failure( doc_comment_padding + // Each subsequent leading whitespace and `///` code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| { - sum + doc_comment_padding + line.len() - line.trim().len() + sum + doc_comment_padding + line.len() - line.trim_start().len() }) }; diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs new file mode 100644 index 00000000000..12e59a4813f --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-end-whitespace + +#![deny(intra_doc_link_resolution_failure)] + +// An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to +// attempt to slice in the middle of a multibyte character. See +// https://github.com/rust-lang/rust/issues/55723 + +/// ## For example: +/// +/// (arr[i]) +pub fn test_ice() { + unimplemented!(); +} diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr new file mode 100644 index 00000000000..7ae6af4a75e --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -0,0 +1,13 @@ +error: `[i]` cannot be resolved, ignoring it... + --> $DIR/intra-link-span-ice-55723.rs:21:10 + | +LL | /// (arr[i]) + | ^ cannot be resolved, ignoring + | +note: lint level defined here + --> $DIR/intra-link-span-ice-55723.rs:13:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + From a1f83e75afefad37b1eed868c0aefba99563969d Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 15 Nov 2018 00:18:19 +0000 Subject: [PATCH 15/42] Stress test for MPSC `concurrent_recv_timeout_and_upgrade` reproduces a problem 100% times on my MacBook with command: ``` ./x.py test --stage 0 ./src/test/run-pass/mpsc_stress.rs ``` Thus it is commented out. Other tests cases were useful for catching another test cases which may arise during the fix. This diff is a part of my previous rewrite attempt: #42883 CC #39364 --- src/test/run-pass/mpsc_stress.rs | 172 +++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/test/run-pass/mpsc_stress.rs diff --git a/src/test/run-pass/mpsc_stress.rs b/src/test/run-pass/mpsc_stress.rs new file mode 100644 index 00000000000..aa369bb17fe --- /dev/null +++ b/src/test/run-pass/mpsc_stress.rs @@ -0,0 +1,172 @@ +// 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. + +// compile-flags:--test +// ignore-emscripten + +use std::sync::mpsc::channel; +use std::sync::mpsc::TryRecvError; +use std::sync::mpsc::RecvError; +use std::sync::mpsc::RecvTimeoutError; +use std::sync::Arc; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use std::thread; +use std::time::Duration; + + +/// Simple thread synchronization utility +struct Barrier { + // Not using mutex/condvar for precision + shared: Arc, + count: usize, +} + +impl Barrier { + fn new(count: usize) -> Vec { + let shared = Arc::new(AtomicUsize::new(0)); + (0..count).map(|_| Barrier { shared: shared.clone(), count: count }).collect() + } + + fn new2() -> (Barrier, Barrier) { + let mut v = Barrier::new(2); + (v.pop().unwrap(), v.pop().unwrap()) + } + + /// Returns when `count` threads enter `wait` + fn wait(self) { + self.shared.fetch_add(1, Ordering::SeqCst); + while self.shared.load(Ordering::SeqCst) != self.count { + } + } +} + + +fn shared_close_sender_does_not_lose_messages_iter() { + let (tb, rb) = Barrier::new2(); + + let (tx, rx) = channel(); + let _ = tx.clone(); // convert to shared + + thread::spawn(move || { + tb.wait(); + thread::sleep(Duration::from_micros(1)); + tx.send(17).expect("send"); + drop(tx); + }); + + let i = rx.into_iter(); + rb.wait(); + // Make sure it doesn't return disconnected before returning an element + assert_eq!(vec![17], i.collect::>()); +} + +#[test] +fn shared_close_sender_does_not_lose_messages() { + for _ in 0..10000 { + shared_close_sender_does_not_lose_messages_iter(); + } +} + + +// https://github.com/rust-lang/rust/issues/39364 +fn concurrent_recv_timeout_and_upgrade_iter() { + // 1 us + let sleep = Duration::new(0, 1_000); + + let (a, b) = Barrier::new2(); + let (tx, rx) = channel(); + let th = thread::spawn(move || { + a.wait(); + loop { + match rx.recv_timeout(sleep) { + Ok(_) => { + break; + }, + Err(_) => {}, + } + } + }); + b.wait(); + thread::sleep(sleep); + tx.clone().send(()).expect("send"); + th.join().unwrap(); +} + +#[test] +fn concurrent_recv_timeout_and_upgrade() { + // FIXME: fix and enable + if true { return } + + // at the moment of writing this test fails like this: + // thread '' panicked at 'assertion failed: `(left == right)` + // left: `4561387584`, + // right: `0`', libstd/sync/mpsc/shared.rs:253:13 + + for _ in 0..10000 { + concurrent_recv_timeout_and_upgrade_iter(); + } +} + + +fn concurrent_writes_iter() { + const THREADS: usize = 4; + const PER_THR: usize = 100; + + let mut bs = Barrier::new(THREADS + 1); + let (tx, rx) = channel(); + + let mut threads = Vec::new(); + for j in 0..THREADS { + let tx = tx.clone(); + let b = bs.pop().unwrap(); + threads.push(thread::spawn(move || { + b.wait(); + for i in 0..PER_THR { + tx.send(j * 1000 + i).expect("send"); + } + })); + } + + let b = bs.pop().unwrap(); + b.wait(); + + let mut v: Vec<_> = rx.iter().take(THREADS * PER_THR).collect(); + v.sort(); + + for j in 0..THREADS { + for i in 0..PER_THR { + assert_eq!(j * 1000 + i, v[j * PER_THR + i]); + } + } + + for t in threads { + t.join().unwrap(); + } + + let one_us = Duration::new(0, 1000); + + assert_eq!(TryRecvError::Empty, rx.try_recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Timeout, rx.recv_timeout(one_us).unwrap_err()); + + drop(tx); + + assert_eq!(RecvError, rx.recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Disconnected, rx.recv_timeout(one_us).unwrap_err()); + assert_eq!(TryRecvError::Disconnected, rx.try_recv().unwrap_err()); +} + +#[test] +fn concurrent_writes() { + for _ in 0..100 { + concurrent_writes_iter(); + } +} From 7f4bc2247a5fbfd8010ae1a799c3a6b2d173ec82 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 15 Oct 2018 18:43:57 -0700 Subject: [PATCH 16/42] Clean up some non-mod-rs stuff. --- src/libsyntax/parse/lexer/mod.rs | 1 - src/libsyntax/parse/mod.rs | 4 ---- src/libsyntax/parse/parser.rs | 11 +---------- src/test/run-pass/non_modrs_mods/foors_mod.rs | 4 ++++ .../non_modrs_mods/foors_mod/inline/somename.rs | 1 + .../non_modrs_mods/modrs_mod/inline/somename.rs | 1 + .../run-pass/non_modrs_mods/modrs_mod/mod.rs | 4 ++++ .../run-pass/non_modrs_mods/non_modrs_mods.rs | 16 ++++++++++++++++ .../invalid-module-declaration.rs | 1 - src/test/ui/missing_non_modrs_mod/foo_inline.rs | 5 +++++ .../missing_non_modrs_mod.rs | 2 -- .../missing_non_modrs_mod_inline.rs | 2 ++ .../missing_non_modrs_mod_inline.stderr | 11 +++++++++++ src/test/ui/non_modrs_mods/foors_mod.rs | 14 -------------- .../foors_mod/compiletest-ignore-dir | 0 .../non_modrs_mods/foors_mod/inner_foors_mod.rs | 11 ----------- .../foors_mod/inner_foors_mod/innest.rs | 11 ----------- .../foors_mod/inner_modrs_mod/innest.rs | 11 ----------- .../foors_mod/inner_modrs_mod/mod.rs | 11 ----------- .../modrs_mod/compiletest-ignore-dir | 0 .../non_modrs_mods/modrs_mod/inner_foors_mod.rs | 11 ----------- .../modrs_mod/inner_foors_mod/innest.rs | 11 ----------- .../modrs_mod/inner_modrs_mod/innest.rs | 11 ----------- .../modrs_mod/inner_modrs_mod/mod.rs | 11 ----------- src/test/ui/non_modrs_mods/modrs_mod/mod.rs | 12 ------------ .../some_crazy_attr_mod_dir/arbitrary_name.rs | 11 ----------- .../compiletest-ignore-dir | 0 .../inner_modrs_mod/innest.rs | 11 ----------- .../inner_modrs_mod/mod.rs | 11 ----------- 29 files changed, 45 insertions(+), 165 deletions(-) create mode 100644 src/test/run-pass/non_modrs_mods/foors_mod/inline/somename.rs create mode 100644 src/test/run-pass/non_modrs_mods/modrs_mod/inline/somename.rs create mode 100644 src/test/run-pass/non_modrs_mods/non_modrs_mods.rs create mode 100644 src/test/ui/missing_non_modrs_mod/foo_inline.rs create mode 100644 src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs create mode 100644 src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr delete mode 100644 src/test/ui/non_modrs_mods/foors_mod.rs delete mode 100644 src/test/ui/non_modrs_mods/foors_mod/compiletest-ignore-dir delete mode 100644 src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod.rs delete mode 100644 src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod/innest.rs delete mode 100644 src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/innest.rs delete mode 100644 src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/mod.rs delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/compiletest-ignore-dir delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod.rs delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod/innest.rs delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/innest.rs delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/mod.rs delete mode 100644 src/test/ui/non_modrs_mods/modrs_mod/mod.rs delete mode 100644 src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/arbitrary_name.rs delete mode 100644 src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/compiletest-ignore-dir delete mode 100644 src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/innest.rs delete mode 100644 src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/mod.rs diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 590506566dd..0584cd5a3df 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1890,7 +1890,6 @@ fn mk_sess(sm: Lrc) -> ParseSess { missing_fragment_specifiers: Lock::new(FxHashSet::default()), raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), - non_modrs_mods: Lock::new(vec![]), buffered_lints: Lock::new(vec![]), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fd66bf55a74..ac972f20f94 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -52,9 +52,6 @@ pub struct ParseSess { pub raw_identifier_spans: Lock>, /// The registered diagnostics codes crate registered_diagnostics: Lock, - // Spans where a `mod foo;` statement was included in a non-mod.rs file. - // These are used to issue errors if the non_modrs_mods feature is not enabled. - pub non_modrs_mods: Lock>, /// Used to determine and report recursive mod inclusions included_mod_stack: Lock>, source_map: Lrc, @@ -81,7 +78,6 @@ pub fn with_span_handler(handler: Handler, source_map: Lrc) -> ParseS registered_diagnostics: Lock::new(ErrorMap::new()), included_mod_stack: Lock::new(vec![]), source_map, - non_modrs_mods: Lock::new(vec![]), buffered_lints: Lock::new(vec![]), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d90ec4ea081..b4fc9c2c6fc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6591,16 +6591,7 @@ fn submod_path(&mut self, } let relative = match self.directory.ownership { - DirectoryOwnership::Owned { relative } => { - // Push the usage onto the list of non-mod.rs mod uses. - // This is used later for feature-gate error reporting. - if let Some(cur_file_ident) = relative { - self.sess - .non_modrs_mods.borrow_mut() - .push((cur_file_ident, id_sp)); - } - relative - }, + DirectoryOwnership::Owned { relative } => relative, DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod(_) => None, }; diff --git a/src/test/run-pass/non_modrs_mods/foors_mod.rs b/src/test/run-pass/non_modrs_mods/foors_mod.rs index 7d37c6d9399..b2fea9b5e53 100644 --- a/src/test/run-pass/non_modrs_mods/foors_mod.rs +++ b/src/test/run-pass/non_modrs_mods/foors_mod.rs @@ -12,3 +12,7 @@ pub mod inner_modrs_mod; pub mod inner_foors_mod; +pub mod inline { + #[path="somename.rs"] + pub mod innie; +} diff --git a/src/test/run-pass/non_modrs_mods/foors_mod/inline/somename.rs b/src/test/run-pass/non_modrs_mods/foors_mod/inline/somename.rs new file mode 100644 index 00000000000..b76b4321d62 --- /dev/null +++ b/src/test/run-pass/non_modrs_mods/foors_mod/inline/somename.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/src/test/run-pass/non_modrs_mods/modrs_mod/inline/somename.rs b/src/test/run-pass/non_modrs_mods/modrs_mod/inline/somename.rs new file mode 100644 index 00000000000..b76b4321d62 --- /dev/null +++ b/src/test/run-pass/non_modrs_mods/modrs_mod/inline/somename.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/src/test/run-pass/non_modrs_mods/modrs_mod/mod.rs b/src/test/run-pass/non_modrs_mods/modrs_mod/mod.rs index 9e3f10f12ed..99684c86d2e 100644 --- a/src/test/run-pass/non_modrs_mods/modrs_mod/mod.rs +++ b/src/test/run-pass/non_modrs_mods/modrs_mod/mod.rs @@ -10,3 +10,7 @@ pub mod inner_modrs_mod; pub mod inner_foors_mod; +pub mod inline { + #[path="somename.rs"] + pub mod innie; +} diff --git a/src/test/run-pass/non_modrs_mods/non_modrs_mods.rs b/src/test/run-pass/non_modrs_mods/non_modrs_mods.rs new file mode 100644 index 00000000000..f664b0166d8 --- /dev/null +++ b/src/test/run-pass/non_modrs_mods/non_modrs_mods.rs @@ -0,0 +1,16 @@ +// run-pass +// +// ignore-pretty issue #37195 +pub mod modrs_mod; +pub mod foors_mod; +#[path = "some_crazy_attr_mod_dir/arbitrary_name.rs"] +pub mod attr_mod; +pub fn main() { + modrs_mod::inner_modrs_mod::innest::foo(); + modrs_mod::inner_foors_mod::innest::foo(); + modrs_mod::inline::innie::foo(); + foors_mod::inner_modrs_mod::innest::foo(); + foors_mod::inner_foors_mod::innest::foo(); + foors_mod::inline::innie::foo(); + attr_mod::inner_modrs_mod::innest::foo(); +} diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs index c0a10fe3e60..229b005ec7d 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs @@ -9,7 +9,6 @@ // except according to those terms. // ignore-tidy-linelength -// ignore-windows mod auxiliary { mod foo; diff --git a/src/test/ui/missing_non_modrs_mod/foo_inline.rs b/src/test/ui/missing_non_modrs_mod/foo_inline.rs new file mode 100644 index 00000000000..df60629eca1 --- /dev/null +++ b/src/test/ui/missing_non_modrs_mod/foo_inline.rs @@ -0,0 +1,5 @@ +// ignore-test this is just a helper for the real test in this dir + +mod inline { + mod missing; +} diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs index 9c95f459393..84fa1f032d7 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.rs @@ -8,7 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-windows - mod foo; fn main() {} diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs new file mode 100644 index 00000000000..9ebb4f1bdbd --- /dev/null +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.rs @@ -0,0 +1,2 @@ +mod foo_inline; +fn main() {} diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr new file mode 100644 index 00000000000..457e8fcccbf --- /dev/null +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -0,0 +1,11 @@ +error[E0583]: file not found for module `missing` + --> $DIR/foo_inline.rs:4:9 + | +LL | mod missing; + | ^^^^^^^ + | + = help: name the file either missing.rs or missing/mod.rs inside the directory "$DIR/foo_inline/inline" + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/non_modrs_mods/foors_mod.rs b/src/test/ui/non_modrs_mods/foors_mod.rs deleted file mode 100644 index 7d37c6d9399..00000000000 --- a/src/test/ui/non_modrs_mods/foors_mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. -// -// ignore-test: not a test, used by non_modrs_mods.rs - -pub mod inner_modrs_mod; -pub mod inner_foors_mod; diff --git a/src/test/ui/non_modrs_mods/foors_mod/compiletest-ignore-dir b/src/test/ui/non_modrs_mods/foors_mod/compiletest-ignore-dir deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod.rs b/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod.rs deleted file mode 100644 index 77cab972352..00000000000 --- a/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod innest; diff --git a/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod/innest.rs b/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod/innest.rs deleted file mode 100644 index b61667cfd88..00000000000 --- a/src/test/ui/non_modrs_mods/foors_mod/inner_foors_mod/innest.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub fn foo() {} diff --git a/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/innest.rs b/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/innest.rs deleted file mode 100644 index b61667cfd88..00000000000 --- a/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/innest.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub fn foo() {} diff --git a/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/mod.rs b/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/mod.rs deleted file mode 100644 index 77cab972352..00000000000 --- a/src/test/ui/non_modrs_mods/foors_mod/inner_modrs_mod/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod innest; diff --git a/src/test/ui/non_modrs_mods/modrs_mod/compiletest-ignore-dir b/src/test/ui/non_modrs_mods/modrs_mod/compiletest-ignore-dir deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod.rs b/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod.rs deleted file mode 100644 index 77cab972352..00000000000 --- a/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod innest; diff --git a/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod/innest.rs b/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod/innest.rs deleted file mode 100644 index b61667cfd88..00000000000 --- a/src/test/ui/non_modrs_mods/modrs_mod/inner_foors_mod/innest.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub fn foo() {} diff --git a/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/innest.rs b/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/innest.rs deleted file mode 100644 index b61667cfd88..00000000000 --- a/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/innest.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub fn foo() {} diff --git a/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/mod.rs b/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/mod.rs deleted file mode 100644 index 77cab972352..00000000000 --- a/src/test/ui/non_modrs_mods/modrs_mod/inner_modrs_mod/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod innest; diff --git a/src/test/ui/non_modrs_mods/modrs_mod/mod.rs b/src/test/ui/non_modrs_mods/modrs_mod/mod.rs deleted file mode 100644 index 9e3f10f12ed..00000000000 --- a/src/test/ui/non_modrs_mods/modrs_mod/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// 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. - -pub mod inner_modrs_mod; -pub mod inner_foors_mod; diff --git a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/arbitrary_name.rs b/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/arbitrary_name.rs deleted file mode 100644 index 226e6fda0a4..00000000000 --- a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/arbitrary_name.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod inner_modrs_mod; diff --git a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/compiletest-ignore-dir b/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/compiletest-ignore-dir deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/innest.rs b/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/innest.rs deleted file mode 100644 index b61667cfd88..00000000000 --- a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/innest.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub fn foo() {} diff --git a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/mod.rs b/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/mod.rs deleted file mode 100644 index 77cab972352..00000000000 --- a/src/test/ui/non_modrs_mods/some_crazy_attr_mod_dir/inner_modrs_mod/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub mod innest; From 6779bb485c7fb3af47278d7eeefce34eeeb5eaf8 Mon Sep 17 00:00:00 2001 From: Blitzerr Date: Wed, 14 Nov 2018 21:14:46 -0800 Subject: [PATCH 17/42] capture_disjoint_fields(rust-lang#53488) Refactoring out the HirId of the UpvarId in another struct. --- src/librustc/ich/impls_ty.rs | 4 +++- src/librustc/infer/error_reporting/mod.rs | 2 +- src/librustc/infer/error_reporting/note.rs | 4 ++-- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/ty/context.rs | 6 +++--- src/librustc/ty/mod.rs | 7 ++++++- src/librustc/util/ppaux.rs | 4 ++-- .../borrowck/gather_loans/mod.rs | 4 ++-- .../borrowck/gather_loans/move_error.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 10 +++++----- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 ++-- src/librustc_typeck/check/upvar.rs | 16 ++++++++++------ src/librustc_typeck/check/writeback.rs | 2 +- 15 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9..928a6accf2d 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -216,7 +216,9 @@ fn hash_stable(&self, } } -impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarPath { hir_id }); + +impl_stable_hash_for!(struct ty::UpvarId { var_path, closure_expr_id }); impl_stable_hash_for!(enum ty::BorrowKind { ImmBorrow, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f833ebc7ca7..59a490f4a01 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1315,7 +1315,7 @@ fn report_inference_failure( format!(" for lifetime parameter `{}` in coherence check", name) } infer::UpvarRegion(ref upvar_id, _) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); format!(" for capture of `{}` by closure", var_name) } diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 54d01a035a8..a539c321af3 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -41,7 +41,7 @@ pub(super) fn note_region_origin(&self, "...so that reference does not outlive borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); err.span_note(span, &format!("...so that closure can access `{}`", var_name)); @@ -174,7 +174,7 @@ pub(super) fn report_concrete_failure(&self, err } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); let mut err = struct_span_err!(self.tcx.sess, span, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 7e9b26bbf72..5b92bfe6ad3 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -938,7 +938,7 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) { let var_hir_id = self.tcx().hir.node_to_hir_id(freevar.var_id()); let closure_def_id = self.tcx().hir.local_def_id(closure_expr.id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 59ef8fa1448..cadf0c42d22 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -818,7 +818,7 @@ fn cat_upvar(&self, let closure_expr_def_id = self.tcx.hir.local_def_id(fn_node_id); let var_hir_id = self.tcx.hir.node_to_hir_id(var_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_expr_def_id.to_local(), }; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index cdfe8f53b85..923d362c234 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -789,7 +789,7 @@ fn hash_stable(&self, pat_adjustments.hash_stable(hcx, hasher); hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| { let ty::UpvarId { - var_id, + var_path, closure_expr_id } = *up_var_id; @@ -798,14 +798,14 @@ fn hash_stable(&self, let var_owner_def_id = DefId { krate: local_id_root.krate, - index: var_id.owner, + index: var_path.hir_id.owner, }; let closure_def_id = DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index, }; (hcx.def_path_hash(var_owner_def_id), - var_id.local_id, + var_path.hir_id.local_id, hcx.def_path_hash(closure_def_id)) }); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8197136d189..d1497c42af7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -731,12 +731,17 @@ pub fn empty<'a>() -> &'a List { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UpvarPath { + pub hir_id: hir::HirId, +} + /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UpvarId { - pub var_id: hir::HirId, + pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e44c0c05bb1..d53370d242b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -678,8 +678,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "UpvarId({:?};`{}`;{:?})", - self.var_id, - ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), + self.var_path.hir_id, + ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_path.hir_id))), self.closure_expr_id) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 78a31ed668f..21fb0cdf90a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -453,8 +453,8 @@ pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath) { } None } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { - self.bccx.used_mut_nodes.borrow_mut().insert(var_id); + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { + self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); None } LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index e1a4473539c..cfd530b7e3d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -97,7 +97,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr } } if let NoteClosureEnv(upvar_id) = error.move_from.note { - let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); err.span_label(bccx.tcx.hir.span(var_node_id), "captured outer variable"); } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index d52d78181b7..d189460d088 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -846,7 +846,7 @@ fn report_bckerr(&self, err: &BckError<'a, 'tcx>) { MutabilityViolation => { let mut db = self.cannot_assign(error_span, &descr, Origin::Ast); if let mc::NoteClosureEnv(upvar_id) = err.cmt.note { - let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let sp = self.tcx.hir.span(node_id); let fn_closure_msg = "`Fn` closures cannot capture their enclosing \ environment for modifications"; @@ -1415,7 +1415,7 @@ pub fn append_loan_path_to_string(&self, loan_path: &LoanPath<'tcx>, out: &mut String) { match loan_path.kind { - LpUpvar(ty::UpvarId { var_id: id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id}, closure_expr_id: _ }) => { out.push_str(&self.tcx.hir.name(self.tcx.hir.hir_to_node_id(id)).as_str()); } LpVar(id) => { @@ -1533,7 +1533,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => { let s = ty::tls::with(|tcx| { let var_node_id = tcx.hir.hir_to_node_id(var_id); tcx.hir.node_to_string(var_node_id) @@ -1568,9 +1568,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_user_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { let s = ty::tls::with(|tcx| { - let var_node_id = tcx.hir.hir_to_node_id(var_id); + let var_node_id = tcx.hir.hir_to_node_id(hir_id); tcx.hir.node_to_string(var_node_id) }); write!(f, "$({} captured by closure)", s) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5b4001f0652..94d1874e9c9 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -612,7 +612,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let var_hir_id = tcx.hir.node_to_hir_id(var_id); let closure_expr_id = tcx.hir.local_def_id(fn_id); let capture = hir.tables().upvar_capture(ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_expr_id), }); let by_ref = match capture { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 656a467fb49..2e9edf20c57 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -1061,7 +1061,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; match cx.tables().upvar_capture(upvar_id) { @@ -1178,7 +1178,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> ExprRef<'tcx> { let var_hir_id = cx.tcx.hir.node_to_hir_id(freevar.var_id()); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).to_local(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index ef29e13d9fe..312ce402775 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -134,7 +134,9 @@ fn analyze_closure( self.tcx.with_freevars(closure_node_id, |freevars| { for freevar in freevars { let upvar_id = ty::UpvarId { - var_id: self.tcx.hir.node_to_hir_id(freevar.var_id()), + var_path: ty::UpvarPath { + hir_id : self.tcx.hir.node_to_hir_id(freevar.var_id()), + }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); @@ -248,7 +250,9 @@ fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { let var_hir_id = tcx.hir.node_to_hir_id(var_node_id); let freevar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { + hir_id: var_hir_id, + }, closure_expr_id: LocalDefId::from_def_id(closure_def_index), }; let capture = self.tables.borrow().upvar_capture(upvar_id); @@ -347,7 +351,7 @@ fn adjust_upvar_borrow_kind_for_consume( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); self.adjust_upvar_captures @@ -364,7 +368,7 @@ fn adjust_upvar_borrow_kind_for_consume( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); } mc::NoteIndex | mc::NoteNone => {} @@ -465,7 +469,7 @@ fn try_adjust_upvar_deref( upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true @@ -478,7 +482,7 @@ fn try_adjust_upvar_deref( upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d968bf222aa..4460d5f64ce 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -306,7 +306,7 @@ fn visit_upvar_borrow_map(&mut self) { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, &upvar_id.var_id); + let r = self.resolve(&r, &upvar_id.var_path.hir_id); ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, region: r, From c5bc83b60d10492f8e71461b03f5adb8505e53d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 11:14:18 +0100 Subject: [PATCH 18/42] expose MutValueVisitor --- src/librustc_mir/interpret/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 82fe08fa038..96ea0d50949 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -39,6 +39,6 @@ pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy}; -pub use self::visitor::ValueVisitor; +pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; From e4d03f82b582824d2b6c3fb68420883d26598178 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 12:44:40 +0100 Subject: [PATCH 19/42] miri value visitor: provide place when visiting a primitive --- src/librustc_mir/interpret/validity.rs | 5 +++-- src/librustc_mir/interpret/visitor.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c3554512806..229f48381ea 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -21,7 +21,7 @@ }; use super::{ - OpTy, MPlaceTy, ImmTy, Machine, EvalContext, ValueVisitor + OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor }; macro_rules! validation_failure { @@ -281,8 +281,9 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> } } - fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { + let value = self.ecx.read_immediate(value)?; // Go over all the primitive types let ty = value.layout.ty; match ty.sty { diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 4a470456432..f0a71242599 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ }; use super::{ - Machine, EvalContext, MPlaceTy, OpTy, ImmTy, + Machine, EvalContext, MPlaceTy, OpTy, }; // A thing that we can project into, and that has a layout. @@ -201,9 +201,11 @@ fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult< { Ok(()) } /// Called whenever we reach a value of primitive type. There can be no recursion - /// below such a value. This is the leave function. + /// below such a value. This is the leaf function. + /// We do *not* provide an `ImmTy` here because some implementations might want + /// to write to the place this primitive lives in. #[inline(always)] - fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx> { Ok(()) } // Default recursors. Not meant to be overloaded. @@ -279,9 +281,7 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> _ => v.layout().ty.builtin_deref(true).is_some(), }; if primitive { - let op = v.to_op(self.ecx())?; - let val = self.ecx().read_immediate(op)?; - return self.visit_primitive(val); + return self.visit_primitive(v); } // Proceed into the fields. From 62cf9abcf6611c598894e9a8abac6c54a72d862d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 08:59:49 +0100 Subject: [PATCH 20/42] rename FrameInfo span field to call_site --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/mir/interpret/error.rs | 8 ++++---- src/librustc_mir/interpret/eval_context.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index d8b207fa25a..f3b58ee5cf1 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -388,7 +388,7 @@ fn hash_stable( }); impl_stable_hash_for!(struct mir::interpret::FrameInfo<'tcx> { - span, + call_site, lint_root, instance }); diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index d375e62b27c..8700f5d6e43 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -57,7 +57,7 @@ pub struct ConstEvalErr<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct FrameInfo<'tcx> { - pub span: Span, + pub call_site: Span, // this span is in the caller! pub instance: ty::Instance<'tcx>, pub lint_root: Option, } @@ -72,8 +72,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } else { write!(f, "inside call to `{}`", self.instance)?; } - if !self.span.is_dummy() { - let lo = tcx.sess.source_map().lookup_char_pos_adj(self.span.lo()); + if !self.call_site.is_dummy() { + let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo()); write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?; } Ok(()) @@ -159,7 +159,7 @@ fn struct_generic( // on constant values. if self.stacktrace.len() > 0 { for frame_info in &self.stacktrace[..self.stacktrace.len()-1] { - err.span_label(frame_info.span, frame_info.to_string()); + err.span_label(frame_info.call_site, frame_info.to_string()); } } Ok(err) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 279955fba17..dbda506d115 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -679,7 +679,7 @@ pub fn generate_stacktrace(&self, explicit_span: Option) -> Vec Some(ivs[source_info.scope].lint_root), mir::ClearCrossCrate::Clear => None, }; - frames.push(FrameInfo { span, instance, lint_root }); + frames.push(FrameInfo { call_site: span, instance, lint_root }); } trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); frames From e6e56357308d1e20b56f1be9af2c2dfc73c49d0d Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 14 Nov 2018 15:00:57 +0100 Subject: [PATCH 21/42] ty: return impl Iterator from Predicate::walk_tys --- src/librustc/ty/mod.rs | 78 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8197136d189..c801cb99a1e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -49,7 +49,6 @@ use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; -use std::vec::IntoIter; use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; @@ -1343,49 +1342,88 @@ fn to_predicate(&self) -> Predicate<'tcx> { } } +// A custom iterator used by Predicate::walk_tys. +enum WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + None, + One(Ty<'tcx>), + Two(Ty<'tcx>, Ty<'tcx>), + Types(I), + InputTypes(J), + ProjectionTypes(K) +} + +impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + type Item = Ty<'tcx>; + + fn next(&mut self) -> Option> { + match *self { + WalkTysIter::None => None, + WalkTysIter::One(item) => { + *self = WalkTysIter::None; + Some(item) + }, + WalkTysIter::Two(item1, item2) => { + *self = WalkTysIter::One(item2); + Some(item1) + }, + WalkTysIter::Types(ref mut iter) => { + iter.next() + }, + WalkTysIter::InputTypes(ref mut iter) => { + iter.next() + }, + WalkTysIter::ProjectionTypes(ref mut iter) => { + iter.next() + } + } + } +} + impl<'tcx> Predicate<'tcx> { /// Iterates over the types in this predicate. Note that in all /// cases this is skipping over a binder, so late-bound regions /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter> { - let vec: Vec<_> = match *self { + pub fn walk_tys(&'a self) -> impl Iterator> + 'a { + match *self { ty::Predicate::Trait(ref data) => { - data.skip_binder().input_types().collect() + WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - vec![a, b] + WalkTysIter::Two(a, b) } ty::Predicate::TypeOutlives(binder) => { - vec![binder.skip_binder().0] + WalkTysIter::One(binder.skip_binder().0) } ty::Predicate::RegionOutlives(..) => { - vec![] + WalkTysIter::None } ty::Predicate::Projection(ref data) => { let inner = data.skip_binder(); - inner.projection_ty.substs.types().chain(Some(inner.ty)).collect() + WalkTysIter::ProjectionTypes( + inner.projection_ty.substs.types().chain(Some(inner.ty))) } ty::Predicate::WellFormed(data) => { - vec![data] + WalkTysIter::One(data) } ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] + WalkTysIter::None } ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - closure_substs.substs.types().collect() + WalkTysIter::Types(closure_substs.substs.types()) } ty::Predicate::ConstEvaluatable(_, substs) => { - substs.types().collect() + WalkTysIter::Types(substs.types()) } - }; - - // FIXME: The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() + } } pub fn to_opt_poly_trait_ref(&self) -> Option> { From ffb6ba082897db55f7ab4e576175b144597aa38f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 10:32:23 +0100 Subject: [PATCH 22/42] validation: better error when the enum discriminant is Undef --- src/librustc/mir/interpret/error.rs | 4 ++-- src/librustc_mir/interpret/operand.rs | 8 +++++--- src/librustc_mir/interpret/validity.rs | 4 ++-- .../const-pointer-values-in-various-types.stderr | 14 +++++++------- src/test/ui/consts/const-eval/issue-52442.stderr | 2 +- .../ui/consts/const-eval/ref_to_int_match.stderr | 2 +- src/test/ui/consts/const-eval/ub-enum.stderr | 2 +- src/test/ui/consts/const-eval/ub-ref.stderr | 4 ++-- src/test/ui/consts/const-eval/union-ice.stderr | 2 +- 9 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed42..c51a655418c 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; -use super::{Pointer, Scalar}; +use super::{Pointer, ScalarMaybeUndef}; use backtrace::Backtrace; @@ -240,7 +240,7 @@ pub enum EvalErrorKind<'tcx, O> { InvalidMemoryAccess, InvalidFunctionPointer, InvalidBool, - InvalidDiscriminant(Scalar), + InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, access: bool, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 578bcdc0929..b3b4980beaf 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -601,7 +601,7 @@ pub fn read_discriminant( // read raw discriminant value let discr_op = self.operand_field(rval, 0)?; let discr_val = self.read_immediate(discr_op)?; - let raw_discr = discr_val.to_scalar()?; + let raw_discr = discr_val.to_scalar_or_undef(); trace!("discr value: {:?}", raw_discr); // post-process Ok(match rval.layout.variants { @@ -647,13 +647,13 @@ pub fn read_discriminant( let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; match raw_discr { - Scalar::Ptr(_) => { + ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) => { // The niche must be just 0 (which a pointer value never is) assert!(niche_start == 0); assert!(variants_start == variants_end); (dataful_variant.as_u32() as u128, dataful_variant) }, - Scalar::Bits { bits: raw_discr, size } => { + ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { assert_eq!(size as u64, discr_val.layout.size.bytes()); let discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); @@ -669,6 +669,8 @@ pub fn read_discriminant( (dataful_variant.as_u32() as u128, dataful_variant) } }, + ScalarMaybeUndef::Undef => + return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)), } } }) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c3554512806..10513f2ebba 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -274,7 +274,7 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> ), EvalErrorKind::ReadPointerAsBytes => validation_failure!( - "a pointer", self.path, "plain bytes" + "a pointer", self.path, "plain (non-pointer) bytes" ), _ => Err(err), } @@ -304,7 +304,7 @@ fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<' if self.const_mode { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous try_validation!(value.to_bits(size), - value, self.path, "initialized plain bits"); + value, self.path, "initialized plain (non-pointer) bytes"); } else { // At run-time, for now, we accept *anything* for these types, including // undef. We should fix that, but let's start low. diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index cc1db5db691..0126743eede 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:24:5 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:36:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -74,7 +74,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:51:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -96,7 +96,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:60:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -144,7 +144,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:78:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -184,7 +184,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:93:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:102:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 3075be9e28b..608094b179d 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52442.rs:12:11 | LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index d55c1c2c70b..c4bad73eb02 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ref_to_int_match.rs:33:1 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; //~ ERROR it is undefined behavior to use this value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d36e96b0817..b94a57d00a4 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:51:1 | LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at [0], but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index c3f5f4a26f5..fe969d40a2e 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:22:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:25:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index d5a20640771..98c2c1472aa 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -13,7 +13,7 @@ LL | / const FIELD_PATH: Struct = Struct { //~ ERROR it is undefined behavior to LL | | a: 42, LL | | b: unsafe { UNION.field3 }, LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain bits + | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior From a3770c2547dd163e0f5bfa07ec23b8b461fbe145 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 11:22:18 +0100 Subject: [PATCH 23/42] do not accept out-of-bounds pointers in enum discriminants, they might be NULL --- src/librustc/ich/impls_ty.rs | 7 ++- src/librustc/mir/interpret/allocation.rs | 8 ++++ src/librustc/mir/interpret/error.rs | 14 ++++-- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/memory.rs | 50 +++++++++++--------- src/librustc_mir/interpret/operand.rs | 23 +++++---- src/librustc_mir/interpret/validity.rs | 5 +- src/test/ui/consts/const-eval/ub-enum.rs | 5 ++ src/test/ui/consts/const-eval/ub-enum.stderr | 20 +++++--- 9 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9..9c1fb99cb73 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -451,7 +451,7 @@ impl<'tcx, O> for enum mir::interpret::EvalErrorKind<'tcx, O> FunctionRetMismatch(a, b), NoMirFor(s), UnterminatedCString(ptr), - PointerOutOfBounds { ptr, access, allocation_size }, + PointerOutOfBounds { ptr, check, allocation_size }, InvalidBoolOp(bop), Unimplemented(s), BoundsCheck { len, index }, @@ -471,6 +471,11 @@ impl<'tcx, O> for enum mir::interpret::EvalErrorKind<'tcx, O> } ); +impl_stable_hash_for!(enum mir::interpret::InboundsCheck { + Live, + MaybeDead +}); + impl_stable_hash_for!(enum mir::interpret::Lock { NoLock, WriteLock(dl), diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index cc92b63256c..02c0ebcec4f 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -19,6 +19,14 @@ use std::ops::{Deref, DerefMut}; use rustc_data_structures::sorted_map::SortedMap; +/// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds +/// or also inbounds of a *live* allocation. +#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum InboundsCheck { + Live, + MaybeDead, +} + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index c51a655418c..bf678db51c9 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; -use super::{Pointer, ScalarMaybeUndef}; +use super::{Pointer, InboundsCheck, ScalarMaybeUndef}; use backtrace::Backtrace; @@ -243,7 +243,7 @@ pub enum EvalErrorKind<'tcx, O> { InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, - access: bool, + check: InboundsCheck, allocation_size: Size, }, InvalidNullPointerUsage, @@ -457,9 +457,13 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::EvalErrorKind::*; match *self { - PointerOutOfBounds { ptr, access, allocation_size } => { - write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", - if access { "memory access" } else { "pointer computed" }, + PointerOutOfBounds { ptr, check, allocation_size } => { + write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \ + allocation {} which has size {}", + match check { + InboundsCheck::Live => " and live", + InboundsCheck::MaybeDead => "", + }, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, ValidationFailure(ref err) => { diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 40daf78f546..ec25431bd1f 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -28,7 +28,7 @@ macro_rules! err { pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef}; pub use self::allocation::{ - Allocation, AllocationExtra, + InboundsCheck, Allocation, AllocationExtra, Relocations, UndefMask, }; diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index e125927e7d2..c5a242f334c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -28,7 +28,7 @@ use syntax::ast::Mutability; use super::{ - Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, + Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, InboundsCheck, EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic, Machine, AllocMap, MayLeak, ScalarMaybeUndef, ErrorHandled, }; @@ -249,17 +249,11 @@ pub fn check_align( // Check non-NULL/Undef, extract offset let (offset, alloc_align) = match ptr { Scalar::Ptr(ptr) => { - let (size, align) = self.get_size_and_align(ptr.alloc_id); // check this is not NULL -- which we can ensure only if this is in-bounds // of some (potentially dead) allocation. - if ptr.offset > size { - return err!(PointerOutOfBounds { - ptr: ptr.erase_tag(), - access: true, - allocation_size: size, - }); - }; - // keep data for alignment check + self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?; + // data required for alignment check + let (_, align) = self.get_size_and_align(ptr.alloc_id); (ptr.offset.bytes(), align) } Scalar::Bits { bits, size } => { @@ -293,18 +287,28 @@ pub fn check_align( /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end /// of an allocation (i.e., at the first *inaccessible* location) *is* considered - /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used - /// for the error message. - /// If you want to check bounds before doing a memory access, be sure to - /// check the pointer one past the end of your access, then everything will - /// work out exactly. - pub fn check_bounds_ptr(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - let allocation_size = alloc.bytes.len() as u64; + /// in-bounds! This follows C's/LLVM's rules. `check` indicates whether we + /// additionally require the pointer to be pointing to a *live* (still allocated) + /// allocation. + /// If you want to check bounds before doing a memory access, better use `check_bounds`. + pub fn check_bounds_ptr( + &self, + ptr: Pointer, + check: InboundsCheck, + ) -> EvalResult<'tcx> { + let allocation_size = match check { + InboundsCheck::Live => { + let alloc = self.get(ptr.alloc_id)?; + alloc.bytes.len() as u64 + } + InboundsCheck::MaybeDead => { + self.get_size_and_align(ptr.alloc_id).0.bytes() + } + }; if ptr.offset.bytes() > allocation_size { return err!(PointerOutOfBounds { ptr: ptr.erase_tag(), - access, + check, allocation_size: Size::from_bytes(allocation_size), }); } @@ -317,10 +321,10 @@ pub fn check_bounds( &self, ptr: Pointer, size: Size, - access: bool + check: InboundsCheck, ) -> EvalResult<'tcx> { // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - self.check_bounds_ptr(ptr.offset(size, &*self)?, access) + self.check_bounds_ptr(ptr.offset(size, &*self)?, check) } } @@ -626,7 +630,7 @@ fn get_bytes_internal( ) -> EvalResult<'tcx, &[u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; if check_defined_and_ptr { self.check_defined(ptr, size)?; @@ -677,7 +681,7 @@ fn get_bytes_mut( ) -> EvalResult<'tcx, &mut [u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; self.mark_definedness(ptr, size, true)?; self.clear_relocations(ptr, size)?; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index b3b4980beaf..b7910ad3bce 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -19,7 +19,7 @@ use rustc::mir::interpret::{ GlobalId, AllocId, ConstValue, Pointer, Scalar, - EvalResult, EvalErrorKind + EvalResult, EvalErrorKind, InboundsCheck, }; use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind}; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -647,24 +647,27 @@ pub fn read_discriminant( let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; match raw_discr { - ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) => { - // The niche must be just 0 (which a pointer value never is) - assert!(niche_start == 0); - assert!(variants_start == variants_end); + ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => { + // The niche must be just 0 (which an inbounds pointer value never is) + let ptr_valid = niche_start == 0 && variants_start == variants_end && + self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok(); + if !ptr_valid { + return err!(InvalidDiscriminant(raw_discr.erase_tag())); + } (dataful_variant.as_u32() as u128, dataful_variant) }, ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { assert_eq!(size as u64, discr_val.layout.size.bytes()); - let discr = raw_discr.wrapping_sub(niche_start) + let adjusted_discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); - if variants_start <= discr && discr <= variants_end { - let index = discr as usize; - assert_eq!(index as u128, discr); + if variants_start <= adjusted_discr && adjusted_discr <= variants_end { + let index = adjusted_discr as usize; + assert_eq!(index as u128, adjusted_discr); assert!(index < rval.layout.ty .ty_adt_def() .expect("tagged layout for non adt") .variants.len()); - (discr, VariantIdx::from_usize(index)) + (adjusted_discr, VariantIdx::from_usize(index)) } else { (dataful_variant.as_u32() as u128, dataful_variant) } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 10513f2ebba..5d5c25e66a2 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -17,7 +17,7 @@ use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ - Scalar, AllocType, EvalResult, EvalErrorKind, + Scalar, AllocType, EvalResult, EvalErrorKind, InboundsCheck, }; use super::{ @@ -394,7 +394,8 @@ fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<' } // Maintain the invariant that the place we are checking is // already verified to be in-bounds. - try_validation!(self.ecx.memory.check_bounds(ptr, size, false), + try_validation!( + self.ecx.memory.check_bounds(ptr, size, InboundsCheck::Live), "dangling (not entirely in bounds) reference", self.path); } // Check if we have encountered this pointer+layout combination diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 0aa15c83938..89b44946441 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -39,6 +39,7 @@ union TransmuteEnum2 { in3: (), out1: Enum2, out2: Wrap, // something wrapping the enum so that we test layout first, not enum + out3: Option, } const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; //~^ ERROR is undefined behavior @@ -51,6 +52,10 @@ union TransmuteEnum2 { const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; //~^ ERROR is undefined behavior +// Pointer value in an enum with a niche that is not just 0. +const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; +//~^ ERROR is undefined behavior + // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). union TransmuteChar { diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index b94a57d00a4..5aae3a2f351 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -15,7 +15,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -23,7 +23,7 @@ LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:47:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2 @@ -31,7 +31,7 @@ LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:51:1 + --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at [0], but expected a valid enum discriminant @@ -39,13 +39,21 @@ LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:61:1 + --> $DIR/ub-enum.rs:56:1 + | +LL | const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:66:1 | LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0080`. From b8915f2ba83d2d7968a1615a086bde0d4bf20706 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 12:19:35 +0100 Subject: [PATCH 24/42] fix other affected tests --- src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index 03de0efd073..a4c22841614 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52023-array-size-pointer-cast.rs:12:17 | LL | let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior From 81303d7d90b483b8e2611cef09adc56c02ccfc50 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 10 Sep 2018 01:35:35 +0000 Subject: [PATCH 25/42] Add powerpc-unknown-linux-musl target --- src/librustc_target/spec/mod.rs | 1 + .../spec/powerpc_unknown_linux_musl.rs | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/librustc_target/spec/powerpc_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 16dc2a91030..792afc759e1 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -297,6 +297,7 @@ fn $module() { ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe), + ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), diff --git a/src/librustc_target/spec/powerpc_unknown_linux_musl.rs b/src/librustc_target/spec/powerpc_unknown_linux_musl.rs new file mode 100644 index 00000000000..1a4d0cb323f --- /dev/null +++ b/src/librustc_target/spec/powerpc_unknown_linux_musl.rs @@ -0,0 +1,31 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_musl_base::opts(); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.max_atomic_width = Some(32); + + Ok(Target { + llvm_target: "powerpc-unknown-linux-musl".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), + arch: "powerpc".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} From 346e97600bafd916c41c24d01ef8671511d691c2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 16 Sep 2018 16:34:15 +0000 Subject: [PATCH 26/42] Fix powerpc64 ELFv2 big-endian struct-passing ABI The requirements here are not "ELFv1" requirements, but big-endian requirements, as the extension or non-extension of the argument is necessary to put the argument in the correct half of the register. Parameter passing in the ELFv2 ABI needs these same transformations. Since this code makes no difference on little-endian machines, simplify it to use the same code path everywhere. --- src/librustc_target/abi/call/powerpc64.rs | 29 ++++++++++------------- src/librustc_target/abi/mod.rs | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs index 80a4d693dc3..56d09c07292 100644 --- a/src/librustc_target/abi/call/powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -75,7 +75,9 @@ fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>, abi: ABI) let size = ret.layout.size; let bits = size.bits(); if bits <= 128 { - let unit = if bits <= 8 { + let unit = if cx.data_layout().endian == Endian::Big { + Reg { kind: RegKind::Integer, size } + } else if bits <= 8 { Reg::i8() } else if bits <= 16 { Reg::i16() @@ -110,22 +112,15 @@ fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>, abi: ABI) } let size = arg.layout.size; - let (unit, total) = match abi { - ELFv1 => { - // In ELFv1, aggregates smaller than a doubleword should appear in - // the least-significant bits of the parameter doubleword. The rest - // should be padded at their tail to fill out multiple doublewords. - if size.bits() <= 64 { - (Reg { kind: RegKind::Integer, size }, size) - } else { - let align = Align::from_bits(64, 64).unwrap(); - (Reg::i64(), size.abi_align(align)) - } - }, - ELFv2 => { - // In ELFv2, we can just cast directly. - (Reg::i64(), size) - }, + let (unit, total) = if size.bits() <= 64 { + // Aggregates smaller than a doubleword should appear in + // the least-significant bits of the parameter doubleword. + (Reg { kind: RegKind::Integer, size }, size) + } else { + // Aggregates larger than a doubleword should be padded + // at the tail to fill out a whole number of doublewords. + let align = Align::from_bits(64, 64).unwrap(); + (Reg::i64(), size.abi_align(align)) }; arg.cast_to(Uniform { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 88f22912fa6..22afb0da05b 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -229,7 +229,7 @@ fn data_layout(&self) -> &TargetDataLayout { } /// Endianness of the target, which must match cfg(target-endian). -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum Endian { Little, Big From 2bb5029d748ceee2f0501fbba786944a3ead6019 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 8 Aug 2018 22:06:18 -0500 Subject: [PATCH 27/42] Use the ELFv2 ABI on powerpc64 musl --- src/librustc_target/abi/call/powerpc64.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs index 56d09c07292..f7ef1390f14 100644 --- a/src/librustc_target/abi/call/powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -14,11 +14,12 @@ use abi::call::{FnType, ArgType, Reg, RegKind, Uniform}; use abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use spec::HasTargetSpec; #[derive(Debug, Clone, Copy, PartialEq)] enum ABI { ELFv1, // original ABI used for powerpc64 (big-endian) - ELFv2, // newer ABI used for powerpc64le + ELFv2, // newer ABI used for powerpc64le and musl (both endians) } use self::ABI::*; @@ -131,11 +132,15 @@ fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>, abi: ABI) pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>) where Ty: TyLayoutMethods<'a, C> + Copy, - C: LayoutOf> + HasDataLayout + C: LayoutOf> + HasDataLayout + HasTargetSpec { - let abi = match cx.data_layout().endian { - Endian::Big => ELFv1, - Endian::Little => ELFv2, + let abi = if cx.target_spec().target_env == "musl" { + ELFv2 + } else { + match cx.data_layout().endian { + Endian::Big => ELFv1, + Endian::Little => ELFv2 + } }; if !fty.ret.is_ignore() { From 4f9c86038529880458195daafd97d4cbc8f9ee27 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Tue, 7 Aug 2018 21:59:15 -0500 Subject: [PATCH 28/42] Add powerpc64-unknown-linux-musl target --- src/librustc_target/spec/mod.rs | 1 + .../spec/powerpc64_unknown_linux_musl.rs | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/librustc_target/spec/powerpc64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 792afc759e1..f67152ee90b 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -299,6 +299,7 @@ fn $module() { ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe), ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), + ("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl), ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs b/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs new file mode 100644 index 00000000000..95e95510e1f --- /dev/null +++ b/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_musl_base::opts(); + base.cpu = "ppc64".to_string(); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.max_atomic_width = Some(64); + + Ok(Target { + llvm_target: "powerpc64-unknown-linux-musl".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "E-m:e-i64:64-n32:64".to_string(), + arch: "powerpc64".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} From 8c8ff6a4e14fc8c9ded15b37a910127bbce6cda2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 16 Sep 2018 16:35:41 +0000 Subject: [PATCH 29/42] test/linkage-visibility: Ignore on musl targets DynamicLibrary uses libc's dlsym() function internally to find symbols. Some implementations of dlsym(), like musl's, only look at dynamically- exported symbols, as found in shared libraries. To also export symbols from the main executable, we would need to pass --export-dynamic to the linker. Since this flag isn't available everywhere, ignore the test for now. --- src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs index 4ea3d0d0d0a..2aaa28341ad 100644 --- a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs +++ b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-musl - dlsym doesn't see symbols without "-C link-arg=-Wl,--export-dynamic" + #![feature(rustc_private)] // We're testing linkage visibility; the compiler warns us, but we want to From 03aaa4b659a546e11a94de476d0d43417b4719ce Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Sat, 10 Nov 2018 23:43:41 +0100 Subject: [PATCH 30/42] remove unused dependency --- src/Cargo.lock | 1 - src/librustc_data_structures/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index a0bb92867ff..2eaa937baa2 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2161,7 +2161,6 @@ dependencies = [ "graphviz 0.0.0", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 10820007629..79f073d643d 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -16,7 +16,6 @@ serialize = { path = "../libserialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" -parking_lot_core = "0.2.8" rustc-rayon = "0.1.1" rustc-rayon-core = "0.1.1" rustc-hash = "1.0.1" From 303dbccf040de2f61434dc7d716c5feed817fbdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 18:05:08 +0100 Subject: [PATCH 31/42] CTFE: dynamically make sure we do not call non-const-fn --- src/librustc_mir/const_eval.rs | 16 +++++++++++----- src/test/ui/consts/const-call.rs | 1 + src/test/ui/consts/const-call.stderr | 11 +++++++++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 7bff76f948e..51046399ec2 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -365,13 +365,19 @@ fn find_fn( ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { debug!("eval_fn_call: {:?}", instance); - if !ecx.tcx.is_const_fn(instance.def_id()) { + // Execution might have wandered off into other crates, so we cannot to a stability- + // sensitive check here. But we can at least rule out functions that are not const + // at all. + if !ecx.tcx.is_const_fn_raw(instance.def_id()) { // Some functions we support even if they are non-const -- but avoid testing - // that for const fn! - if ecx.hook_fn(instance, args, dest)? { + // that for const fn! We certainly do *not* want to actually call the fn + // though, so be sure we return here. + return if ecx.hook_fn(instance, args, dest)? { ecx.goto_block(ret)?; // fully evaluated and done - return Ok(None); - } + Ok(None) + } else { + err!(MachineError(format!("calling non-const function `{}`", instance))) + }; } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def) { diff --git a/src/test/ui/consts/const-call.rs b/src/test/ui/consts/const-call.rs index 18476494300..bd407192cd7 100644 --- a/src/test/ui/consts/const-call.rs +++ b/src/test/ui/consts/const-call.rs @@ -15,4 +15,5 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions + //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/consts/const-call.stderr b/src/test/ui/consts/const-call.stderr index 81be93e916e..219fcec51b3 100644 --- a/src/test/ui/consts/const-call.stderr +++ b/src/test/ui/consts/const-call.stderr @@ -4,6 +4,13 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let _ = [0; f(2)]; | ^^^^ -error: aborting due to previous error +error[E0080]: evaluation of constant value failed + --> $DIR/const-call.rs:16:17 + | +LL | let _ = [0; f(2)]; + | ^^^^ calling non-const function `f` -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 2 previous errors + +Some errors occurred: E0015, E0080. +For more information about an error, try `rustc --explain E0015`. From c1221e2072beebe90d6bbe8be99a51be1e6d11ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20C?= Date: Fri, 16 Nov 2018 15:34:12 -0500 Subject: [PATCH 32/42] Replace data.clone() by Arc::clone(&data) in mutex doc. Arc::clone(&from) is considered as more idiomatic because it conveys more explicitly the meaning of the code. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 54bfd8122b4..ec9207ea45b 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -69,7 +69,7 @@ /// /// let (tx, rx) = channel(); /// for _ in 0..N { -/// let (data, tx) = (data.clone(), tx.clone()); +/// let (data, tx) = (Arc::clone(&data), tx.clone()); /// thread::spawn(move || { /// // The shared state can only be accessed once the lock is held. /// // Our non-atomic increment is safe because we're the only thread From 0c0478d57a5bc3a85fb695b84c06d38494f70529 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 18:38:28 +0100 Subject: [PATCH 33/42] adjust remaining tests --- src/test/compile-fail/const-fn-error.rs | 1 + src/test/compile-fail/issue-52443.rs | 1 + src/test/ui/issues/issue-39559-2.rs | 2 ++ src/test/ui/issues/issue-39559-2.stderr | 19 ++++++++++++++++--- src/test/ui/issues/issue-43105.rs | 2 ++ src/test/ui/issues/issue-43105.stderr | 18 +++++++++++++++++- 6 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 83f2735aa9d..17dc9f94fe1 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -19,6 +19,7 @@ const fn f(x: usize) -> usize { for i in 0..x { //~^ ERROR E0015 //~| ERROR E0019 + //~| ERROR E0080 sum += i; } sum diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs index fc42f87ccbf..1ed513033fd 100644 --- a/src/test/compile-fail/issue-52443.rs +++ b/src/test/compile-fail/issue-52443.rs @@ -14,4 +14,5 @@ fn main() { [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions //~^ ERROR constant contains unimplemented expression type + //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/issues/issue-39559-2.rs b/src/test/ui/issues/issue-39559-2.rs index 2e480a29774..f01fd1fd8f1 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -23,6 +23,8 @@ fn dim() -> usize { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR E0015 + //~| ERROR E0080 = [0; Dim3::dim()]; //~^ ERROR E0015 + //~| ERROR E0080 } diff --git a/src/test/ui/issues/issue-39559-2.stderr b/src/test/ui/issues/issue-39559-2.stderr index ca9da096b6c..57e9f23e0b3 100644 --- a/src/test/ui/issues/issue-39559-2.stderr +++ b/src/test/ui/issues/issue-39559-2.stderr @@ -4,12 +4,25 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | let array: [usize; Dim3::dim()] | ^^^^^^^^^^^ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-39559-2.rs:24:24 + | +LL | let array: [usize; Dim3::dim()] + | ^^^^^^^^^^^ calling non-const function `::dim` + error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-39559-2.rs:26:15 + --> $DIR/issue-39559-2.rs:27:15 | LL | = [0; Dim3::dim()]; | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/issue-39559-2.rs:27:15 + | +LL | = [0; Dim3::dim()]; + | ^^^^^^^^^^^ calling non-const function `::dim` -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 4 previous errors + +Some errors occurred: E0015, E0080. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-43105.rs b/src/test/ui/issues/issue-43105.rs index 2bddc443d5b..60b18a66f1a 100644 --- a/src/test/ui/issues/issue-43105.rs +++ b/src/test/ui/issues/issue-43105.rs @@ -12,10 +12,12 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); //~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants +//~| ERROR any use of this value will cause an error [const_err] fn main() { match 1 { NUM => unimplemented!(), + //~^ ERROR could not evaluate constant pattern _ => unimplemented!(), } } diff --git a/src/test/ui/issues/issue-43105.stderr b/src/test/ui/issues/issue-43105.stderr index 67a6008cd8e..f26447ed2b9 100644 --- a/src/test/ui/issues/issue-43105.stderr +++ b/src/test/ui/issues/issue-43105.stderr @@ -4,6 +4,22 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct LL | const NUM: u8 = xyz(); | ^^^^^ -error: aborting due to previous error +error: any use of this value will cause an error + --> $DIR/issue-43105.rs:13:1 + | +LL | const NUM: u8 = xyz(); + | ^^^^^^^^^^^^^^^^-----^ + | | + | calling non-const function `xyz` + | + = note: #[deny(const_err)] on by default + +error: could not evaluate constant pattern + --> $DIR/issue-43105.rs:19:9 + | +LL | NUM => unimplemented!(), + | ^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0015`. From 41434e001be222a7ce70faf3c5a23d97f462dfb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 22:17:26 +0100 Subject: [PATCH 34/42] avoid shared ref in UnsafeCell::get --- src/libcore/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9cf42eff219..b1ef15b4513 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1509,7 +1509,7 @@ impl UnsafeCell { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn get(&self) -> *mut T { - &self.value as *const T as *mut T + self as *const UnsafeCell as *const T as *mut T } } From a7b312f8255db978f0446cf62383402fee02bae3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 09:08:30 +0100 Subject: [PATCH 35/42] erase the tag on casts involving (raw) pointers --- src/librustc_mir/interpret/cast.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 118539fc58e..7d636b77ced 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -44,16 +44,22 @@ pub fn cast( } Misc => { + let src_layout = src.layout; let src = self.read_immediate(src)?; - if self.type_is_fat_ptr(src.layout.ty) { - match (*src, self.type_is_fat_ptr(dest.layout.ty)) { + // There are no casts to references + assert!(!dest.layout.ty.is_region_ptr()); + // Hence we make all casts erase the tag + let src = src.erase_tag().with_default_tag(); + + if self.type_is_fat_ptr(src_layout.ty) { + match (src, self.type_is_fat_ptr(dest.layout.ty)) { // pointers to extern types (Immediate::Scalar(_),_) | // slices and trait objects to other slices/trait objects (Immediate::ScalarPair(..), true) => { // No change to immediate - self.write_immediate(*src, dest)?; + self.write_immediate(src, dest)?; } // slices and trait objects to thin pointers (dropping the metadata) (Immediate::ScalarPair(data, _), false) => { @@ -61,11 +67,11 @@ pub fn cast( } } } else { - match src.layout.variants { + match src_layout.variants { layout::Variants::Single { index } => { - if let Some(def) = src.layout.ty.ty_adt_def() { + if let Some(def) = src_layout.ty.ty_adt_def() { // Cast from a univariant enum - assert!(src.layout.is_zst()); + assert!(src_layout.is_zst()); let discr_val = def .discriminant_for_variant(*self.tcx, index) .val; @@ -78,7 +84,7 @@ pub fn cast( layout::Variants::NicheFilling { .. } => {}, } - let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?; + let dest_val = self.cast_scalar(src.to_scalar()?, src_layout, dest.layout)?; self.write_scalar(dest_val, dest)?; } } From 25d46f309130be1671d7e44d48e67b23f510bcdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:20:28 +0100 Subject: [PATCH 36/42] add comment explaining why what we do is legal --- src/libcore/cell.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b1ef15b4513..d8d51f53377 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1509,6 +1509,8 @@ impl UnsafeCell { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn get(&self) -> *mut T { + // We can just cast the pointer from `UnsafeCell` to `T` because of + // #[repr(transparent)] self as *const UnsafeCell as *const T as *mut T } } From 2b7c3fb725c4fe5ce968d62b3e07ebc74ffd82a3 Mon Sep 17 00:00:00 2001 From: giacomo Date: Sat, 17 Nov 2018 11:39:58 +0100 Subject: [PATCH 37/42] add test for #[test] attribute only allowed on non associated functions --- .../ui/test-attr-non-associated-functions.rs | 19 +++++++++++++++++++ .../test-attr-non-associated-functions.stderr | 11 +++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/ui/test-attr-non-associated-functions.rs create mode 100644 src/test/ui/test-attr-non-associated-functions.stderr diff --git a/src/test/ui/test-attr-non-associated-functions.rs b/src/test/ui/test-attr-non-associated-functions.rs new file mode 100644 index 00000000000..872dbd89770 --- /dev/null +++ b/src/test/ui/test-attr-non-associated-functions.rs @@ -0,0 +1,19 @@ +// #[test] attribute is not allowed on associated functions or methods +// reworded error message +// compile-flags:--test + +struct A {} + +impl A { + #[test] + fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions + A {} + } +} + +#[test] +fn test() { + let _ = A::new(); +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/test-attr-non-associated-functions.stderr b/src/test/ui/test-attr-non-associated-functions.stderr new file mode 100644 index 00000000000..780a119a666 --- /dev/null +++ b/src/test/ui/test-attr-non-associated-functions.stderr @@ -0,0 +1,11 @@ +error: #[test] attribute is only allowed on non associated functions + --> $DIR/test-attr-non-associated-functions.rs:9:2 + | +LL | fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions + | _____^ +LL | | A {} +LL | | } + | |_____^ + +error: aborting due to previous error + From 8e13e433c65f4755f43a527f8777a035f8b6a71b Mon Sep 17 00:00:00 2001 From: giacomo Date: Sat, 17 Nov 2018 12:28:04 +0100 Subject: [PATCH 38/42] tidy check fix --- .../ui/test-attr-non-associated-functions.rs | 24 +++++++++++++------ .../test-attr-non-associated-functions.stderr | 5 ++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/test/ui/test-attr-non-associated-functions.rs b/src/test/ui/test-attr-non-associated-functions.rs index 872dbd89770..348bc6b4e98 100644 --- a/src/test/ui/test-attr-non-associated-functions.rs +++ b/src/test/ui/test-attr-non-associated-functions.rs @@ -1,19 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + // #[test] attribute is not allowed on associated functions or methods -// reworded error message +// reworded error message // compile-flags:--test struct A {} impl A { - #[test] - fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions - A {} - } + #[test] + fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions + A {} + } } #[test] fn test() { - let _ = A::new(); + let _ = A::new(); } -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/ui/test-attr-non-associated-functions.stderr b/src/test/ui/test-attr-non-associated-functions.stderr index 780a119a666..491fcc01431 100644 --- a/src/test/ui/test-attr-non-associated-functions.stderr +++ b/src/test/ui/test-attr-non-associated-functions.stderr @@ -1,8 +1,7 @@ error: #[test] attribute is only allowed on non associated functions - --> $DIR/test-attr-non-associated-functions.rs:9:2 + --> $DIR/test-attr-non-associated-functions.rs:19:5 | -LL | fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions - | _____^ +LL | / fn new() -> A { //~ ERROR #[test] attribute is only allowed on non associated functions LL | | A {} LL | | } | |_____^ From 5fc63ce480c8a50911ba05c057789119de989df9 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Sat, 17 Nov 2018 17:40:58 +0100 Subject: [PATCH 39/42] docs: Add missing backtick in object_safety.rs docs Closes #56019. --- src/librustc/traits/object_safety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 715ce0d7e80..c79fa386123 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -470,7 +470,7 @@ fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> /// /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` /// for `self: Rc`, this means `Rc: DispatchFromDyn>` - /// for `self: Pin>, this means `Pin>: DispatchFromDyn>>` + /// for `self: Pin>`, this means `Pin>: DispatchFromDyn>>` // // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this // fallback query: `Receiver: Unsize U]>` to support receivers like From cdb1a799f8793c4c858abc05b437fa2e569f51e6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 17 Nov 2018 00:31:34 -0800 Subject: [PATCH 40/42] Add VecDeque::resize_with --- src/liballoc/collections/vec_deque.rs | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 88e76033f27..cbf104a8fcd 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -19,7 +19,7 @@ use core::cmp::Ordering; use core::fmt; -use core::iter::{repeat, FromIterator, FusedIterator}; +use core::iter::{repeat, repeat_with, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; @@ -1920,6 +1920,44 @@ pub fn resize(&mut self, new_len: usize, value: T) { self.truncate(new_len); } } + + /// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`, + /// either by removing excess elements from the back or by appending + /// elements generated by calling `generator` to the back. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_resize_with)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(5); + /// buf.push_back(10); + /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); + /// + /// buf.resize_with(5, Default::default); + /// assert_eq!(buf, [5, 10, 15, 0, 0]); + /// + /// buf.resize_with(2, || unreachable!()); + /// assert_eq!(buf, [5, 10]); + /// + /// let mut state = 100; + /// buf.resize_with(5, || { state += 1; state }); + /// assert_eq!(buf, [5, 10, 101, 102, 103]); + /// ``` + #[unstable(feature = "vec_resize_with", issue = "41758")] + pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut()->T) { + let len = self.len(); + + if new_len > len { + self.extend(repeat_with(generator).take(new_len - len)) + } else { + self.truncate(new_len); + } + } } /// Returns the index in the underlying buffer for a given logical element index. From a5b4cb29919a19a9f92bf57a304461fe4239d46d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 18 Nov 2018 10:07:25 -0500 Subject: [PATCH 41/42] remove "approx env bounds" if we already know from trait --- src/librustc/infer/outlives/obligations.rs | 36 +++++++++++++++------ src/test/ui/nll/ty-outlives/issue-55756.rs | 37 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/nll/ty-outlives/issue-55756.rs diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index f2825887f36..ab75a914d9c 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -389,16 +389,6 @@ fn projection_must_outlive( // rule might not apply (but another rule might). For now, we err // on the side of adding too few edges into the graph. - // Compute the bounds we can derive from the environment. This - // is an "approximate" match -- in some cases, these bounds - // may not apply. - let approx_env_bounds = self.verify_bound - .projection_approx_declared_bounds_from_env(projection_ty); - debug!( - "projection_must_outlive: approx_env_bounds={:?}", - approx_env_bounds - ); - // Compute the bounds we can derive from the trait definition. // These are guaranteed to apply, no matter the inference // results. @@ -406,6 +396,32 @@ fn projection_must_outlive( .projection_declared_bounds_from_trait(projection_ty) .collect(); + // Compute the bounds we can derive from the environment. This + // is an "approximate" match -- in some cases, these bounds + // may not apply. + let mut approx_env_bounds = self.verify_bound + .projection_approx_declared_bounds_from_env(projection_ty); + debug!( + "projection_must_outlive: approx_env_bounds={:?}", + approx_env_bounds + ); + + // Remove outlives bounds that we get from the environment but + // which are also deducable from the trait. This arises (cc + // #55756) in cases where you have e.g. `>::Item: + // 'a` in the environment but `trait Foo<'b> { type Item: 'b + // }` in the trait definition. + approx_env_bounds.retain(|bound| { + match bound.0.sty { + ty::Projection(projection_ty) => { + self.verify_bound.projection_declared_bounds_from_trait(projection_ty) + .all(|r| r != bound.1) + } + + _ => panic!("expected only projection types from env, not {:?}", bound.0), + } + }); + // If declared bounds list is empty, the only applicable rule is // OutlivesProjectionComponent. If there are inference variables, // then, we can break down the outlives into more primitive diff --git a/src/test/ui/nll/ty-outlives/issue-55756.rs b/src/test/ui/nll/ty-outlives/issue-55756.rs new file mode 100644 index 00000000000..cda3915849e --- /dev/null +++ b/src/test/ui/nll/ty-outlives/issue-55756.rs @@ -0,0 +1,37 @@ +// Regression test for #55756. +// +// In this test, the result of `self.callee` is a projection `>::Guard`. As it may contain a destructor, the dropck +// rules require that this type outlivess the scope of `state`. Unfortunately, +// our region inference is not smart enough to figure out how to +// translate a requirement like +// +// >::guard: 'r +// +// into a requirement that `'0: 'r` -- in particular, it fails to do +// so because it *also* knows that `>::Guard: 'a` +// from the trait definition. Faced with so many choices, the current +// solver opts to do nothing. +// +// Fixed by tweaking the solver to recognize that the constraint from +// the environment duplicates one from the trait. +// +// compile-pass + +#![crate_type="lib"] + +pub trait Database<'a> { + type Guard: 'a; +} + +pub struct Stateful<'a, D: 'a>(&'a D); + +impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> { + pub fn callee<'a>(&'a self) -> >::Guard { + unimplemented!() + } + pub fn caller<'a>(&'a self) -> >::Guard { + let state = self.callee(); + unimplemented!() + } +} From 86073253d563a7792765933f24acbf93fd3fee1d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 18 Nov 2018 19:08:06 -0800 Subject: [PATCH 42/42] Increase `Duration` approximate equal threshold to 1us Previously this threshold when testing was 100ns, but the Windows documentation states: > which is a high resolution (<1us) time stamp which presumably means that we could have up to 1us resolution, which means that 100ns doesn't capture "equivalent" time intervals due to various bits of rounding here and there. It's hoped that this.. Closes #56034 --- src/libstd/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index d124cf53dda..58be1972a81 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -481,7 +481,7 @@ macro_rules! assert_almost_eq { let (a, b) = ($a, $b); if a != b { let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 100) <= b, + assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); } })