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 de4293aaaeac7..9b78351c3e165 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -218,35 +218,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - 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), - }); - - err.span_label(call_expr.span, "not a function"); + 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), + }); - 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => 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 990fb404c9466..194cfab8527c0 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 fff696fc80f05..360e0c6f107b2 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 ef7ace44d59a6..3bcc83e01c1f0 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 edc4ecbab525a..d04108ca39e24 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 8f10cb0f7b03d..c297c20069ec2 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 1ea85ee440e21..70a9736d2a243 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 9fb9a7b51f280..b94e0833a5810 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 034a076fbfe83..af32c0e20ce9d 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 22772e596b19e..ffffe6d3ab5db 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 ae6fda8b93248..7f481c230ba65 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 2b3870feef37c..b7b5f76395a9d 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 0d57d61e9ffe6..90adb3ed73f56 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 6f5a84966bf35..305ee2f547145 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 3eb0b19a6aaea..9c87806da9e5d 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 8e08f124d6807..01e6488de5303 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 0000000000000..37f078285d695 --- /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 0000000000000..40ddb5ec53c29 --- /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 cef0849937bf0..71b204b2de985 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -22,7 +22,7 @@ use std::fs::{self, File}; 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 be3485cfa7cc2..b8a171b52adf2 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 cc4f3f95d079a..650aa39114fad 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 dd5d4b8f6afff..4f94b427ec169 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1062,8 +1062,7 @@ impl<'a> LoweringContext<'a> { 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 54550b8a2055f..7d3ae64f4fcd6 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -281,7 +281,7 @@ impl<'sess> OnDiskCache<'sess> { // 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 7f3736e82caa6..5604729d2f8dc 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -146,7 +146,7 @@ impl FromHex for str { } 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 dd90ef06c3929..bfdb53a9d9e18 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1200,16 +1200,14 @@ impl<'a> MethodDef<'a> { 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 @@ impl<'a> MethodDef<'a> { // 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 877bd5a82e6a0..0b00cfc2d7fd4 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -697,7 +697,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { 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 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } 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 83feadd50d77f..9553d1244837c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1994,6 +1994,12 @@ impl ReprOptions { 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 0000000000000..0fa06fa777b29 --- /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 ab96d3126bb22..0928f7560e175 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 f3a62975dd9f4..d8b207fa25aaf 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -387,10 +387,10 @@ impl_stable_hash_for!(enum mir::interpret::ErrorHandled { 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 f28aa41ed4222..c30d41f340340 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 super::{Pointer, Scalar}; use backtrace::Backtrace; -use ty; use ty::query::TyCtxtAt; use errors::DiagnosticBuilder; @@ -52,16 +52,30 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; 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 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { 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 e6267012dc275..279955fba17ad 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,7 +14,6 @@ use std::mem; 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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } } - 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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } 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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc 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 8df49f364a372..b087ea7899f4c 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 0a2dae72f7382..a1a778c2b2c61 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 4595eacb31061..2762f0bf7ec74 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 fcebfb932474c..11d85471b7c08 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 b208e760d95c6..14fb17aeeddca 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 c30d41f340340..e1b22c64ed69c 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 | 144 ++++++++++++++--------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index df994ad9e55c4..ef29e13d9fe12 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,14 +45,14 @@ use super::FnCtxt; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; +use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +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; -use rustc::hir; -use rustc::hir::def_id::LocalDefId; -use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -121,7 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!( "var_id={:?} freevar_ty={:?} capture={:?}", - var_node_id, - freevar_ty, - capture + var_node_id, freevar_ty, capture ); match capture { @@ -271,8 +268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, ), } - }) - .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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { /// 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { ) { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { ) { 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 0fa06fa777b29..786968128ec1b 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -26,15 +26,15 @@ 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) +// 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 e1b22c64ed69c..d375e62b27c58 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -23,7 +23,7 @@ use backtrace::Backtrace; 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 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { 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 ef35bb6d98dae..4246ec2dad332 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 a780322e85e86..f25aa000d803d 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 0000000000000..12e59a4813f85 --- /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 0000000000000..7ae6af4a75e8c --- /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 0000000000000..aa369bb17fead --- /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 590506566dd5f..0584cd5a3df47 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1890,7 +1890,6 @@ mod tests { 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 fd66bf55a74be..ac972f20f9432 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 @@ impl ParseSess { 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 d90ec4ea081b2..b4fc9c2c6fc7c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6591,16 +6591,7 @@ impl<'a> Parser<'a> { } 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 7d37c6d939954..b2fea9b5e53f8 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 0000000000000..b76b4321d62aa --- /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 0000000000000..b76b4321d62aa --- /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 9e3f10f12ed63..99684c86d2eaf 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 0000000000000..f664b0166d80d --- /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 c0a10fe3e60fe..229b005ec7d56 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 0000000000000..df60629eca161 --- /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 9c95f45939367..84fa1f032d78e 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 0000000000000..9ebb4f1bdbdb3 --- /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 0000000000000..457e8fcccbfb3 --- /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 7d37c6d939954..0000000000000 --- 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 e69de29bb2d1d..0000000000000 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 77cab972352bd..0000000000000 --- 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 b61667cfd882c..0000000000000 --- 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 b61667cfd882c..0000000000000 --- 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 77cab972352bd..0000000000000 --- 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 e69de29bb2d1d..0000000000000 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 77cab972352bd..0000000000000 --- 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 b61667cfd882c..0000000000000 --- 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 b61667cfd882c..0000000000000 --- 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 77cab972352bd..0000000000000 --- 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 9e3f10f12ed63..0000000000000 --- 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 226e6fda0a41f..0000000000000 --- 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 e69de29bb2d1d..0000000000000 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 b61667cfd882c..0000000000000 --- 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 77cab972352bd..0000000000000 --- 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 f3a62975dd9f4..928a6accf2d12 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -216,7 +216,9 @@ impl<'gcx> HashStable> for ty::adjustment::AutoBorrow } } -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 f833ebc7ca763..59a490f4a013d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1315,7 +1315,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 54d01a035a8be..a539c321af3f0 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -41,7 +41,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "...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 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 7e9b26bbf729c..5b92bfe6ad3c4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -938,7 +938,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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 59ef8fa14484b..cadf0c42d228f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -818,7 +818,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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 cdfe8f53b854b..923d362c2345f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -789,7 +789,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { 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 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { 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 8197136d189ae..d1497c42af78f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -731,12 +731,17 @@ impl 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 e44c0c05bb1a6..d53370d242bd9 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -678,8 +678,8 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { 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 78a31ed668fca..21fb0cdf90ad1 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -453,8 +453,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } 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 e1a4473539c8c..cfd530b7e3d09 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 d52d78181b77a..d189460d08848 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -846,7 +846,7 @@ impl<'a, 'tcx> BorrowckCtxt<'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 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { 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 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { 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 5b4001f0652ad..94d1874e9c9e8 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 656a467fb4912..2e9edf20c5708 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 ef29e13d9fe12..312ce402775d2 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -134,7 +134,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { 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 d968bf222aa09..4460d5f64ce26 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -306,7 +306,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { 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 82fe08fa038a4..96ea0d5094966 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -39,6 +39,6 @@ pub use self::machine::{Machine, AllocMap, MayLeak}; 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 c3554512806b3..229f48381eaa4 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -21,7 +21,7 @@ use rustc::mir::interpret::{ }; use super::{ - OpTy, MPlaceTy, ImmTy, Machine, EvalContext, ValueVisitor + OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor }; macro_rules! validation_failure { @@ -281,8 +281,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, '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 4a47045643253..f0a71242599bf 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ use rustc::mir::interpret::{ }; 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 @@ macro_rules! make_value_visitor { { 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 @@ macro_rules! make_value_visitor { _ => 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 d8b207fa25aaf..f3b58ee5cf19b 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -388,7 +388,7 @@ impl_stable_hash_for!(enum mir::interpret::ErrorHandled { }); 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 d375e62b27c58..8700f5d6e432f 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 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { } 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 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { // 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 279955fba17ad..dbda506d115af 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -679,7 +679,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc mir::ClearCrossCrate::Set(ref ivs) => 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 8197136d189ae..c801cb99a1e2c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -49,7 +49,6 @@ use std::hash::{Hash, Hasher}; 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 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'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 f28aa41ed4222..c51a655418c10 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::{Ty, layout}; 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 578bcdc09295d..b3b4980beafad 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -601,7 +601,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> (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 c3554512806b3..10513f2ebba79 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -274,7 +274,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, '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 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> 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 cc1db5db6915c..0126743eedecb 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 3075be9e28b35..608094b179dd6 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 d55c1c2c70ba1..c4bad73eb0276 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 d36e96b08174a..b94a57d00a444 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 c3f5f4a26f555..fe969d40a2ea6 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 d5a20640771df..98c2c1472aae0 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 f3a62975dd9f4..9c1fb99cb73cc 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -451,7 +451,7 @@ impl_stable_hash_for!( 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_stable_hash_for!( } ); +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 cc92b63256c1f..02c0ebcec4fef 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -19,6 +19,14 @@ use mir; 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 c51a655418c10..bf678db51c952 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::{Ty, layout}; 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 40daf78f546fb..ec25431bd1ffe 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -28,7 +28,7 @@ pub use self::error::{ 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 e125927e7d273..c5a242f334c90 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -28,7 +28,7 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap}; 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> 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 b3b4980beafad..b7910ad3bce9e 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -19,7 +19,7 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> 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 10513f2ebba79..5d5c25e66a2e0 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -17,7 +17,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; 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 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } // 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 0aa15c8393879..89b449464419e 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 @@ const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; 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 b94a57d00a444..5aae3a2f35110 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 03de0efd07362..a4c228416147e 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 16dc2a91030f1..792afc759e166 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -297,6 +297,7 @@ supported_targets! { ("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 0000000000000..1a4d0cb323f1f --- /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 80a4d693dc36b..56d09c072924d 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 88f22912fa6fc..22afb0da05bc1 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -229,7 +229,7 @@ impl HasDataLayout for 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 56d09c072924d..f7ef1390f14de 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 792afc759e166..f67152ee90b7a 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -299,6 +299,7 @@ supported_targets! { ("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 0000000000000..95e95510e1fea --- /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 4ea3d0d0d0a07..2aaa28341ad91 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 a0bb92867ff4e..2eaa937baa244 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 10820007629ff..79f073d643ddc 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 7bff76f948e57..51046399ec201 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -365,13 +365,19 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> 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 18476494300b2..bd407192cd7a1 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 81be93e916e8b..219fcec51b386 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` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +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 54bfd8122b4ed..ec9207ea45b4f 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -69,7 +69,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// 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 83f2735aa9d8e..17dc9f94fe19c 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 fc42f87ccbfda..1ed513033fd5d 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 2e480a29774ce..f01fd1fd8f144 100644 --- a/src/test/ui/issues/issue-39559-2.rs +++ b/src/test/ui/issues/issue-39559-2.rs @@ -23,6 +23,8 @@ impl Dim for Dim3 { 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 ca9da096b6c16..57e9f23e0b33c 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` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0015`. +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 2bddc443d5baf..60b18a66f1a38 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 67a6008cd8ebc..f26447ed2b9f0 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 9cf42eff219ba..b1ef15b4513ad 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 118539fc58ebf..7d636b77ced4c 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -44,16 +44,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } } } 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> 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 b1ef15b4513ad..d8d51f53377f7 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 0000000000000..872dbd8977070 --- /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 0000000000000..780a119a66634 --- /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 872dbd8977070..348bc6b4e982d 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 780a119a66634..491fcc0143119 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 715ce0d7e805b..c79fa3861234f 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -470,7 +470,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, '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 88e76033f273e..cbf104a8fcde9 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 @@ impl VecDeque { 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 | 30 ++++++++++++++---- src/test/ui/nll/ty-outlives/issue-55756.rs | 37 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 7 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 f2825887f36e2..ab75a914d9c80 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -389,22 +389,38 @@ where // 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 trait definition. + // These are guaranteed to apply, no matter the inference + // results. + let trait_bounds: Vec<_> = self.verify_bound + .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 approx_env_bounds = self.verify_bound + 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 ); - // Compute the bounds we can derive from the trait definition. - // These are guaranteed to apply, no matter the inference - // results. - let trait_bounds: Vec<_> = self.verify_bound - .projection_declared_bounds_from_trait(projection_ty) - .collect(); + // 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, 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 0000000000000..cda3915849e2d --- /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 d124cf53dda5d..58be1972a8121 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -481,7 +481,7 @@ mod tests { 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); } })