From 3b0fd82bfad814ff777e7aa236b74804e4c469c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 8 Oct 2019 00:00:00 +0000 Subject: [PATCH 01/20] Disable Go and OCaml bindings when building LLVM Instead of instaling OCaml bindings in a location where installation will not fail, don't build them in the first place. --- src/bootstrap/native.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 7bf9ea2688f4c..fb308bc35ebc5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -157,6 +157,7 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_ENABLE_BINDINGS", "OFF") .define("LLVM_ENABLE_Z3_SOLVER", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) @@ -169,15 +170,6 @@ impl Step for Llvm { } } - // By default, LLVM will automatically find OCaml and, if it finds it, - // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults - // to /usr/bin/ocaml. - // This causes problem for non-root builds of Rust. Side-step the issue - // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs - // in the prefix. - cfg.define("LLVM_OCAML_INSTALL_PATH", - env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); - let want_lldb = builder.config.lldb_enabled && !self.emscripten; // This setting makes the LLVM tools link to the dynamic LLVM library, From bcff26606a74ebd2b5bcbfe03476963a1e21c765 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 14 Sep 2019 09:22:07 -0400 Subject: [PATCH 02/20] [const-prop] Handle MIR Rvalue::Repeat --- src/librustc_mir/transform/const_prop.rs | 2 +- src/test/mir-opt/const_prop/repeat.rs | 37 ++++++++++++++++++++++++ src/test/ui/consts/const-prop-ice.rs | 1 + src/test/ui/consts/const-prop-ice.stderr | 8 ++++- 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/const_prop/repeat.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 49ac1de8fef64..77943e9acd527 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -436,13 +436,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::Repeat(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => return None, Rvalue::Use(_) | Rvalue::Len(_) | + Rvalue::Repeat(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | diff --git a/src/test/mir-opt/const_prop/repeat.rs b/src/test/mir-opt/const_prop/repeat.rs new file mode 100644 index 0000000000000..fb091ad2a3d53 --- /dev/null +++ b/src/test/mir-opt/const_prop/repeat.rs @@ -0,0 +1,37 @@ +// compile-flags: -O + +fn main() { + let x: u32 = [42; 8][2] + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = [const 42u32; 8]; +// ... +// _4 = const 2usize; +// _5 = const 8usize; +// _6 = Lt(_4, _5); +// assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1; +// } +// bb1: { +// _2 = _3[_4]; +// _1 = Add(move _2, const 0u32); +// ... +// return; +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _6 = const true; +// assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1; +// } +// bb1: { +// _2 = const 42u32; +// _1 = Add(move _2, const 0u32); +// ... +// return; +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs index 13309f978b672..48c4b7da942e4 100644 --- a/src/test/ui/consts/const-prop-ice.rs +++ b/src/test/ui/consts/const-prop-ice.rs @@ -1,3 +1,4 @@ fn main() { [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3 + //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 4b3880198bf2d..8ecc6f4bc6b12 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -6,5 +6,11 @@ LL | [0; 3][3u64 as usize]; | = note: `#[deny(const_err)]` on by default -error: aborting due to previous error +error: this expression will panic at runtime + --> $DIR/const-prop-ice.rs:2:5 + | +LL | [0; 3][3u64 as usize]; + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3 + +error: aborting due to 2 previous errors From 714d00d8d848327dfca7aab8bc3bd3b32ea18ebe Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sat, 14 Sep 2019 14:11:31 -0400 Subject: [PATCH 03/20] [const-prop] Handle MIR Rvalue::Aggregates --- src/librustc_mir/transform/const_prop.rs | 8 +++++- src/test/compile-fail/consts/const-err3.rs | 1 + src/test/mir-opt/const_prop/aggregate.rs | 25 +++++++++++++++++++ src/test/run-fail/overflowing-rsh-5.rs | 1 + src/test/run-fail/overflowing-rsh-6.rs | 1 + src/test/ui/consts/const-err2.rs | 1 + src/test/ui/consts/const-err2.stderr | 8 +++++- src/test/ui/consts/const-err3.rs | 1 + src/test/ui/consts/const-err3.stderr | 8 +++++- src/test/ui/issues/issue-54348.rs | 2 ++ src/test/ui/issues/issue-54348.stderr | 16 ++++++++++-- src/test/ui/lint/lint-exceeding-bitshifts2.rs | 2 +- .../ui/lint/lint-exceeding-bitshifts2.stderr | 8 +++++- 13 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/test/mir-opt/const_prop/aggregate.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 77943e9acd527..2119ee1b598ef 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -436,13 +436,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => return None, Rvalue::Use(_) | Rvalue::Len(_) | Rvalue::Repeat(..) | + Rvalue::Aggregate(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | @@ -535,6 +535,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } } + } else if let Rvalue::Aggregate(_, operands) = rvalue { + // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that + // `SimplifyLocals` doesn't know it can remove. + if operands.len() == 0 { + return None; + } } self.use_ecx(source_info, |this| { diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs index fc10824f0c03c..add4eef13c784 100644 --- a/src/test/compile-fail/consts/const-err3.rs +++ b/src/test/compile-fail/consts/const-err3.rs @@ -14,6 +14,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR const_err + //~| ERROR this expression will panic at runtime black_box(b); black_box(c); black_box(d); diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs new file mode 100644 index 0000000000000..0937d37be6b6e --- /dev/null +++ b/src/test/mir-opt/const_prop/aggregate.rs @@ -0,0 +1,25 @@ +// compile-flags: -O + +fn main() { + let x = (0, 1, 2).1 + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = (const 0i32, const 1i32, const 2i32); +// _2 = (_3.1: i32); +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = (const 0i32, const 1i32, const 2i32); +// _2 = const 1i32; +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.after.mir diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index 793f495240d57..58dfc5710ae4e 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] fn main() { let _n = 1i64 >> [64][0]; diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index d6b2f8dc9f9af..c2fec5e4860af 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -2,6 +2,7 @@ // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] +#![warn(const_err)] #![feature(const_indexing)] fn main() { diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index ecbcc2a4b496f..e5ee90fc9f11f 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -23,6 +23,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR index out of bounds + //~| ERROR this expression will panic at runtime black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr index 1d84d44dc27b3..0a09a7213dabc 100644 --- a/src/test/ui/consts/const-err2.stderr +++ b/src/test/ui/consts/const-err2.stderr @@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1 LL | let _e = [5u8][1]; | ^^^^^^^^ -error: aborting due to 5 previous errors +error: this expression will panic at runtime + --> $DIR/const-err2.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 6 previous errors diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs index a9cf04cda7a5a..89373f99f75c2 100644 --- a/src/test/ui/consts/const-err3.rs +++ b/src/test/ui/consts/const-err3.rs @@ -23,6 +23,7 @@ fn main() { //~^ ERROR const_err let _e = [5u8][1]; //~^ ERROR const_err + //~| ERROR this expression will panic at runtime black_box(a); black_box(b); black_box(c); diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr index 0602707be7040..42de247c8f7e0 100644 --- a/src/test/ui/consts/const-err3.stderr +++ b/src/test/ui/consts/const-err3.stderr @@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1 LL | let _e = [5u8][1]; | ^^^^^^^^ -error: aborting due to 5 previous errors +error: this expression will panic at runtime + --> $DIR/const-err3.rs:24:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 6 previous errors diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs index 68d838054776e..e7221e2cbb1e1 100644 --- a/src/test/ui/issues/issue-54348.rs +++ b/src/test/ui/issues/issue-54348.rs @@ -1,5 +1,7 @@ fn main() { [1][0u64 as usize]; [1][1.5 as usize]; //~ ERROR index out of bounds + //~| ERROR this expression will panic at runtime [1][1u64 as usize]; //~ ERROR index out of bounds + //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index fa77bd6fd7797..79320ef4f31c7 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -6,11 +6,23 @@ LL | [1][1.5 as usize]; | = note: `#[deny(const_err)]` on by default +error: this expression will panic at runtime + --> $DIR/issue-54348.rs:3:5 + | +LL | [1][1.5 as usize]; + | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/issue-54348.rs:4:5 + --> $DIR/issue-54348.rs:5:5 | LL | [1][1u64 as usize]; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: this expression will panic at runtime + --> $DIR/issue-54348.rs:5:5 + | +LL | [1][1u64 as usize]; + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 4 previous errors diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.rs b/src/test/ui/lint/lint-exceeding-bitshifts2.rs index 69b627355b801..2c213daddd752 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts2.rs @@ -8,7 +8,7 @@ fn main() { let n = 1u8 << (4+3); let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow let n = 1i64 >> [63][0]; - let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation + let n = 1i64 >> [64][0]; //~ ERROR: attempt to shift right with overflow #[cfg(target_pointer_width = "32")] const BITS: usize = 32; diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr index cb96982a78930..d9c76d233d03e 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr @@ -10,6 +10,12 @@ note: lint level defined here LL | #![deny(exceeding_bitshifts, const_err)] | ^^^^^^^^^^^^^^^^^^^ +error: attempt to shift right with overflow + --> $DIR/lint-exceeding-bitshifts2.rs:11:15 + | +LL | let n = 1i64 >> [64][0]; + | ^^^^^^^^^^^^^^^ + error: attempt to shift left with overflow --> $DIR/lint-exceeding-bitshifts2.rs:17:15 | @@ -22,5 +28,5 @@ error: attempt to shift left with overflow LL | let n = 1_usize << BITS; | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From 81fa59187b19c379c4f9e330984e5e8853981b12 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 00:05:19 -0400 Subject: [PATCH 04/20] [const-prop] Handle MIR Rvalue::Discriminant --- src/librustc_mir/transform/const_prop.rs | 4 +- src/test/mir-opt/const_prop/discriminant.rs | 53 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/const_prop/discriminant.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 2119ee1b598ef..fb2cdce2d7aef 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -436,13 +436,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // if this isn't a supported operation, then return None match rvalue { - Rvalue::NullaryOp(NullOp::Box, _) | - Rvalue::Discriminant(..) => return None, + Rvalue::NullaryOp(NullOp::Box, _) => return None, Rvalue::Use(_) | Rvalue::Len(_) | Rvalue::Repeat(..) | Rvalue::Aggregate(..) | + Rvalue::Discriminant(..) | Rvalue::Cast(..) | Rvalue::NullaryOp(..) | Rvalue::CheckedBinaryOp(..) | diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs new file mode 100644 index 0000000000000..07bbd9202b940 --- /dev/null +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -0,0 +1,53 @@ +// compile-flags: -O + +fn main() { + let x = (if let Some(true) = Some(true) { 42 } else { 10 }) + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = std::option::Option::::Some(const true,); +// _4 = discriminant(_3); +// switchInt(move _4) -> [1isize: bb3, otherwise: bb2]; +// } +// bb1: { +// _2 = const 42i32; +// goto -> bb4; +// } +// bb2: { +// _2 = const 10i32; +// goto -> bb4; +// } +// bb3: { +// switchInt(((_3 as Some).0: bool)) -> [false: bb2, otherwise: bb1]; +// } +// bb4: { +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = const Scalar(0x01) : std::option::Option; +// _4 = const 1isize; +// switchInt(const 1isize) -> [1isize: bb3, otherwise: bb2]; +// } +// bb1: { +// _2 = const 42i32; +// goto -> bb4; +// } +// bb2: { +// _2 = const 10i32; +// goto -> bb4; +// } +// bb3: { +// switchInt(const true) -> [false: bb2, otherwise: bb1]; +// } +// bb4: { +// _1 = Add(move _2, const 0i32); +// ... +// } +// END rustc.main.ConstProp.after.mir From 79c5858bfd07f90201b91cd10cd3aa9f062377cc Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 12:03:52 -0400 Subject: [PATCH 05/20] [const-prop] Handle MIR Rvalue::Box --- src/librustc_mir/transform/const_prop.rs | 19 +-------- src/test/mir-opt/const_prop/boxes.rs | 53 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/test/mir-opt/const_prop/boxes.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fb2cdce2d7aef..984938d00b2f0 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -8,7 +8,7 @@ use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, - Local, NullOp, UnOp, StatementKind, Statement, LocalKind, + Local, UnOp, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock, }; @@ -434,23 +434,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) -> Option> { let span = source_info.span; - // if this isn't a supported operation, then return None - match rvalue { - Rvalue::NullaryOp(NullOp::Box, _) => return None, - - Rvalue::Use(_) | - Rvalue::Len(_) | - Rvalue::Repeat(..) | - Rvalue::Aggregate(..) | - Rvalue::Discriminant(..) | - Rvalue::Cast(..) | - Rvalue::NullaryOp(..) | - Rvalue::CheckedBinaryOp(..) | - Rvalue::Ref(..) | - Rvalue::UnaryOp(..) | - Rvalue::BinaryOp(..) => { } - } - // perform any special checking for specific Rvalue types if let Rvalue::UnaryOp(op, arg) = rvalue { trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs new file mode 100644 index 0000000000000..52a7f7ee79503 --- /dev/null +++ b/src/test/mir-opt/const_prop/boxes.rs @@ -0,0 +1,53 @@ +// compile-flags: -O + +#![feature(box_syntax)] + +// Note: this test verifies that we, in fact, do not const prop `box` + +fn main() { + let x = *(box 42) + 0; +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _4 = Box(i32); +// (*_4) = const 42i32; +// _3 = move _4; +// ... +// _2 = (*_3); +// _1 = Add(move _2, const 0i32); +// ... +// drop(_3) -> [return: bb2, unwind: bb1]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// _0 = (); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _4 = Box(i32); +// (*_4) = const 42i32; +// _3 = move _4; +// ... +// _2 = (*_3); +// _1 = Add(move _2, const 0i32); +// ... +// drop(_3) -> [return: bb2, unwind: bb1]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// _0 = (); +// ... +// } +// END rustc.main.ConstProp.after.mir From f2afa98c95960432d2aa3a9d827f493651fdf02b Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 15 Sep 2019 12:08:09 -0400 Subject: [PATCH 06/20] Cleanup const_prop() some --- src/librustc_mir/transform/const_prop.rs | 147 ++++++++++++----------- 1 file changed, 75 insertions(+), 72 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 984938d00b2f0..abb880fd62419 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { struct ConstPropMachine; impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { - type MemoryKinds= !; + type MemoryKinds = !; type PointerTag = (); type ExtraFnVal = !; @@ -435,79 +435,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let span = source_info.span; // perform any special checking for specific Rvalue types - if let Rvalue::UnaryOp(op, arg) = rvalue { - trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); - let overflow_check = self.tcx.sess.overflow_checks(); - - self.use_ecx(source_info, |this| { - // We check overflow in debug mode already - // so should only check in release mode. - if *op == UnOp::Neg && !overflow_check { - let ty = arg.ty(&this.local_decls, this.tcx); - - if ty.is_integral() { - let arg = this.ecx.eval_operand(arg, None)?; - let prim = this.ecx.read_immediate(arg)?; - // Need to do overflow check here: For actual CTFE, MIR - // generation emits code that does this before calling the op. - if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - throw_panic!(OverflowNeg) + match rvalue { + Rvalue::UnaryOp(UnOp::Neg, arg) => { + trace!("checking UnaryOp(op = Neg, arg = {:?})", arg); + let overflow_check = self.tcx.sess.overflow_checks(); + + self.use_ecx(source_info, |this| { + // We check overflow in debug mode already + // so should only check in release mode. + if !overflow_check { + let ty = arg.ty(&this.local_decls, this.tcx); + + if ty.is_integral() { + let arg = this.ecx.eval_operand(arg, None)?; + let prim = this.ecx.read_immediate(arg)?; + // Need to do overflow check here: For actual CTFE, MIR + // generation emits code that does this before calling the op. + if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + throw_panic!(OverflowNeg) + } } } - } - Ok(()) - })?; - } else if let Rvalue::BinaryOp(op, left, right) = rvalue { - trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - - let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) - })?; - if *op == BinOp::Shr || *op == BinOp::Shl { - let left_bits = place_layout.size.bits(); - let right_size = r.layout.size; - let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); - if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { - let source_scope_local_data = match self.source_scope_local_data { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return None, - }; - let dir = if *op == BinOp::Shr { - "right" - } else { - "left" - }; - let hir_id = source_scope_local_data[source_info.scope].lint_root; - self.tcx.lint_hir( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - hir_id, - span, - &format!("attempt to shift {} with overflow", dir)); - return None; - } + Ok(()) + })?; } - self.use_ecx(source_info, |this| { - let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; - let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; - - // We check overflow in debug mode already - // so should only check in release mode. - if !this.tcx.sess.overflow_checks() && overflow { - let err = err_panic!(Overflow(*op)).into(); - return Err(err); + + Rvalue::BinaryOp(op, left, right) => { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + + let r = self.use_ecx(source_info, |this| { + this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) + })?; + if *op == BinOp::Shr || *op == BinOp::Shl { + let left_bits = place_layout.size.bits(); + let right_size = r.layout.size; + let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); + if r_bits.ok().map_or(false, |b| b >= left_bits as u128) { + let source_scope_local_data = match self.source_scope_local_data { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return None, + }; + let dir = if *op == BinOp::Shr { + "right" + } else { + "left" + }; + let hir_id = source_scope_local_data[source_info.scope].lint_root; + self.tcx.lint_hir( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + hir_id, + span, + &format!("attempt to shift {} with overflow", dir)); + return None; + } } + self.use_ecx(source_info, |this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; + + // We check overflow in debug mode already + // so should only check in release mode. + if !this.tcx.sess.overflow_checks() && overflow { + let err = err_panic!(Overflow(*op)).into(); + return Err(err); + } - Ok(()) - })?; - } else if let Rvalue::Ref(_, _, place) = rvalue { - trace!("checking Ref({:?})", place); - // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref - // from a function argument that hasn't been assigned to in this function. - if let Place { - base: PlaceBase::Local(local), - projection: box [] - } = place { + Ok(()) + })?; + } + + Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { + trace!("checking Ref({:?})", place); + // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref + // from a function argument that hasn't been assigned to in this function. let alive = if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { true @@ -518,12 +519,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } } - } else if let Rvalue::Aggregate(_, operands) = rvalue { - // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that - // `SimplifyLocals` doesn't know it can remove. - if operands.len() == 0 { + + Rvalue::Aggregate(_, operands) if operands.len() == 0 => { + // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that + // `SimplifyLocals` doesn't know it can remove. return None; } + + _ => { } } self.use_ecx(source_info, |this| { From c50664d328ccbe4199bc28e13730493b96f4f165 Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 4 Oct 2019 16:17:23 +0800 Subject: [PATCH 07/20] Prefer statx on linux if available --- src/libstd/fs.rs | 20 ++++- src/libstd/sys/unix/fs.rs | 170 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 180 insertions(+), 10 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index fc26dcb321148..055686fb0271a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1090,13 +1090,14 @@ impl Metadata { /// Returns the creation time listed in this metadata. /// - /// The returned value corresponds to the `birthtime` field of `stat` on + /// The returned value corresponds to the `btime` field of `statx` on + /// Linux not prior to 4.11, the `birthtime` field of `stat` on other /// Unix platforms and the `ftCreationTime` field on Windows platforms. /// /// # Errors /// /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. + /// `Err` on platforms or filesystems where it is not available. /// /// # Examples /// @@ -1109,7 +1110,7 @@ impl Metadata { /// if let Ok(time) = metadata.created() { /// println!("{:?}", time); /// } else { - /// println!("Not supported on this platform"); + /// println!("Not supported on this platform or filesystem"); /// } /// Ok(()) /// } @@ -3443,5 +3444,18 @@ mod tests { check!(a.created()); check!(b.created()); } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) if e1.kind() == ErrorKind::Other && + e2.kind() == ErrorKind::Other => {} + (a, b) => panic!( + "creation time must be always supported or not supported: {:?} {:?}", + a, b, + ), + } + } } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3b1eb86b84fe1..539c3ab449a16 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -44,6 +44,83 @@ pub struct File(FileDesc); #[derive(Clone)] pub struct FileAttr { stat: stat64, + #[cfg(target_os = "linux")] + statx_extra_fields: Option, +} + +#[derive(Clone)] +struct StatxExtraFields { + // This is needed to check if btime is supported by the filesystem. + stx_mask: u32, + stx_btime: libc::statx_timestamp, +} + +// We prefer `statx` on Linux if available, which contains file creation time. +// Default `stat64` contains no creation time. +#[cfg(target_os = "linux")] +unsafe fn try_statx( + fd: c_int, + path: *const libc::c_char, + flags: i32, + mask: u32, +) -> Option> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_STATX: AtomicBool = AtomicBool::new(true); + syscall! { + fn statx( + fd: c_int, + pathname: *const libc::c_char, + flags: c_int, + mask: libc::c_uint, + statxbuf: *mut libc::statx + ) -> c_int + } + + if !HAS_STATX.load(Ordering::Relaxed) { + return None; + } + + let mut buf: libc::statx = mem::zeroed(); + let ret = cvt(statx(fd, path, flags, mask, &mut buf)); + match ret { + Err(err) => match err.raw_os_error() { + Some(libc::ENOSYS) => { + HAS_STATX.store(false, Ordering::Relaxed); + return None; + } + _ => return Some(Err(err)), + } + Ok(_) => { + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor); + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor); + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) + } + } } // all DirEntry's will have a reference to this struct @@ -98,6 +175,14 @@ pub struct FileType { mode: mode_t } pub struct DirBuilder { mode: mode_t } impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { + stat, + #[cfg(target_os = "linux")] + statx_extra_fields: None, + } + } + pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { FilePermissions { mode: (self.stat.st_mode as mode_t) } @@ -164,6 +249,23 @@ impl FileAttr { target_os = "macos", target_os = "ios")))] pub fn created(&self) -> io::Result { + #[cfg(target_os = "linux")] + { + if let Some(ext) = &self.statx_extra_fields { + return if (ext.stx_mask & libc::STATX_BTIME) != 0 { + Ok(SystemTime::from(libc::timespec { + tv_sec: ext.stx_btime.tv_sec as libc::time_t, + tv_nsec: ext.stx_btime.tv_nsec as libc::c_long, + })) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available for the filesystem", + )) + }; + } + } + Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ currently")) @@ -306,12 +408,26 @@ impl DirEntry { #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; + let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; + let name = self.entry.d_name.as_ptr(); + + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + fd, + name, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) + fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] @@ -517,11 +633,25 @@ impl File { } pub fn file_attr(&self) -> io::Result { + let fd = self.0.raw(); + + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + fd, + b"\0" as *const _ as *const libc::c_char, + libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstat64(self.0.raw(), &mut stat) + fstat64(fd, &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn fsync(&self) -> io::Result<()> { @@ -798,20 +928,46 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; + + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; + + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn canonicalize(p: &Path) -> io::Result { From 55cddb879a6adf02ee00edd26ab2fe1b7213bc08 Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 11 Oct 2019 03:52:02 +0800 Subject: [PATCH 08/20] Fix missing guard --- src/libstd/sys/unix/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 539c3ab449a16..8113fe38165b0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -48,6 +48,7 @@ pub struct FileAttr { statx_extra_fields: Option, } +#[cfg(target_os = "linux")] #[derive(Clone)] struct StatxExtraFields { // This is needed to check if btime is supported by the filesystem. From e3b7f3da42d0d1f22bdf2056842b5e562ca84cc2 Mon Sep 17 00:00:00 2001 From: oxalica Date: Mon, 14 Oct 2019 07:17:15 +0800 Subject: [PATCH 09/20] Fix cfgs for current libc --- src/libstd/sys/unix/fs.rs | 226 +++++++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 89 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 8113fe38165b0..0934ffef48773 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -41,88 +41,135 @@ pub use crate::sys_common::fs::remove_dir_all; pub struct File(FileDesc); -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, - #[cfg(target_os = "linux")] - statx_extra_fields: Option, -} - -#[cfg(target_os = "linux")] -#[derive(Clone)] -struct StatxExtraFields { - // This is needed to check if btime is supported by the filesystem. - stx_mask: u32, - stx_btime: libc::statx_timestamp, +// FIXME: This should be available on Linux with all `target_arch` and `target_env`. +// https://github.com/rust-lang/libc/issues/1545 +macro_rules! cfg_has_statx { + ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => { + cfg_if::cfg_if! { + if #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] { + $($then_tt)* + } else { + $($else_tt)* + } + } + }; + ($($block_inner:tt)*) => { + #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] + { + $($block_inner)* + } + }; } -// We prefer `statx` on Linux if available, which contains file creation time. -// Default `stat64` contains no creation time. -#[cfg(target_os = "linux")] -unsafe fn try_statx( - fd: c_int, - path: *const libc::c_char, - flags: i32, - mask: u32, -) -> Option> { - use crate::sync::atomic::{AtomicBool, Ordering}; +cfg_has_statx! {{ + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, + statx_extra_fields: Option, + } + + #[derive(Clone)] + struct StatxExtraFields { + // This is needed to check if btime is supported by the filesystem. + stx_mask: u32, + stx_btime: libc::statx_timestamp, + } + + // We prefer `statx` on Linux if available, which contains file creation time. + // Default `stat64` contains no creation time. + unsafe fn try_statx( + fd: c_int, + path: *const libc::c_char, + flags: i32, + mask: u32, + ) -> Option> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_STATX: AtomicBool = AtomicBool::new(true); + syscall! { + fn statx( + fd: c_int, + pathname: *const libc::c_char, + flags: c_int, + mask: libc::c_uint, + statxbuf: *mut libc::statx + ) -> c_int + } - // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` - // We store the availability in a global to avoid unnecessary syscalls - static HAS_STATX: AtomicBool = AtomicBool::new(true); - syscall! { - fn statx( - fd: c_int, - pathname: *const libc::c_char, - flags: c_int, - mask: libc::c_uint, - statxbuf: *mut libc::statx - ) -> c_int - } + if !HAS_STATX.load(Ordering::Relaxed) { + return None; + } - if !HAS_STATX.load(Ordering::Relaxed) { - return None; - } + let mut buf: libc::statx = mem::zeroed(); + let ret = cvt(statx(fd, path, flags, mask, &mut buf)); + match ret { + Err(err) => match err.raw_os_error() { + Some(libc::ENOSYS) => { + HAS_STATX.store(false, Ordering::Relaxed); + return None; + } + _ => return Some(Err(err)), + } + Ok(_) => { + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor); + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor); + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; - let mut buf: libc::statx = mem::zeroed(); - let ret = cvt(statx(fd, path, flags, mask, &mut buf)); - match ret { - Err(err) => match err.raw_os_error() { - Some(libc::ENOSYS) => { - HAS_STATX.store(false, Ordering::Relaxed); - return None; + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) } - _ => return Some(Err(err)), } - Ok(_) => { - // We cannot fill `stat64` exhaustively because of private padding fields. - let mut stat: stat64 = mem::zeroed(); - stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor); - stat.st_ino = buf.stx_ino as libc::ino64_t; - stat.st_nlink = buf.stx_nlink as libc::nlink_t; - stat.st_mode = buf.stx_mode as libc::mode_t; - stat.st_uid = buf.stx_uid as libc::uid_t; - stat.st_gid = buf.stx_gid as libc::gid_t; - stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor); - stat.st_size = buf.stx_size as off64_t; - stat.st_blksize = buf.stx_blksize as libc::blksize_t; - stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; - stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; - stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long; - stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; - stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long; - stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; - stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long; - - let extra = StatxExtraFields { - stx_mask: buf.stx_mask, - stx_btime: buf.stx_btime, - }; + } - Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) - } +} else { + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, } -} +}} // all DirEntry's will have a reference to this struct struct InnerReadDir { @@ -175,15 +222,21 @@ pub struct FileType { mode: mode_t } #[derive(Debug)] pub struct DirBuilder { mode: mode_t } -impl FileAttr { - fn from_stat64(stat: stat64) -> Self { - Self { - stat, - #[cfg(target_os = "linux")] - statx_extra_fields: None, +cfg_has_statx! {{ + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat, statx_extra_fields: None } } } +} else { + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat } + } + } +}} +impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { FilePermissions { mode: (self.stat.st_mode as mode_t) } @@ -250,8 +303,7 @@ impl FileAttr { target_os = "macos", target_os = "ios")))] pub fn created(&self) -> io::Result { - #[cfg(target_os = "linux")] - { + cfg_has_statx! { if let Some(ext) = &self.statx_extra_fields { return if (ext.stx_mask & libc::STATX_BTIME) != 0 { Ok(SystemTime::from(libc::timespec { @@ -412,8 +464,7 @@ impl DirEntry { let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; let name = self.entry.d_name.as_ptr(); - #[cfg(target_os = "linux")] - { + cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, name, @@ -636,8 +687,7 @@ impl File { pub fn file_attr(&self) -> io::Result { let fd = self.0.raw(); - #[cfg(target_os = "linux")] - { + cfg_has_statx! { if let Some(ret) = unsafe { try_statx( fd, b"\0" as *const _ as *const libc::c_char, @@ -930,8 +980,7 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; - #[cfg(target_os = "linux")] - { + cfg_has_statx! { if let Some(ret) = unsafe { try_statx( libc::AT_FDCWD, p.as_ptr(), @@ -952,8 +1001,7 @@ pub fn stat(p: &Path) -> io::Result { pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; - #[cfg(target_os = "linux")] - { + cfg_has_statx! { if let Some(ret) = unsafe { try_statx( libc::AT_FDCWD, p.as_ptr(), From 77f0aaf0d0a92feb068999d6b14f60dcf325b0c1 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Sat, 12 Oct 2019 20:53:11 +0200 Subject: [PATCH 10/20] Add more coherence tests --- .../ui/coherence/impl-foreign-for-foreign.rs | 17 +++++++++++ .../coherence/impl-foreign-for-foreign.stderr | 12 ++++++++ .../impl-foreign-for-foreign[foreign].rs | 25 ++++++++++++++++ .../impl-foreign-for-foreign[foreign].stderr | 30 +++++++++++++++++++ .../impl-foreign-for-foreign[local].rs | 16 ++++++++++ .../impl-foreign-for-fundamental[foreign].rs | 21 +++++++++++++ ...pl-foreign-for-fundamental[foreign].stderr | 21 +++++++++++++ .../impl-foreign-for-fundamental[local].rs | 17 +++++++++++ .../ui/coherence/impl-foreign-for-local.rs | 15 ++++++++++ ...reign[fundemental[foreign]]-for-foreign.rs | 26 ++++++++++++++++ ...n[fundemental[foreign]]-for-foreign.stderr | 30 +++++++++++++++++++ ...foreign[fundemental[local]]-for-foreign.rs | 18 +++++++++++ .../impl[t]-foreign-for-(local, t).rs | 17 +++++++++++ .../impl[t]-foreign-for-(local, t).stderr | 12 ++++++++ .../impl[t]-foreign-for-foreign[t].rs | 23 ++++++++++++++ .../impl[t]-foreign-for-foreign[t].stderr | 21 +++++++++++++ .../impl[t]-foreign-for-fundamental[t].rs | 17 +++++++++++ .../impl[t]-foreign-for-fundamental[t].stderr | 11 +++++++ ...eign[fundemental[local]]-for-foreign[t].rs | 17 +++++++++++ .../impl[t]-foreign[local]-for-foreign[t].rs | 17 +++++++++++ ...eign[local]-for-fundamental[foreign[t]].rs | 19 ++++++++++++ 21 files changed, 402 insertions(+) create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign.rs create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-foreign[local].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr create mode 100644 src/test/ui/coherence/impl-foreign-for-fundamental[local].rs create mode 100644 src/test/ui/coherence/impl-foreign-for-local.rs create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr create mode 100644 src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr create mode 100644 src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs create mode 100644 src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.rs b/src/test/ui/coherence/impl-foreign-for-foreign.rs new file mode 100644 index 0000000000000..de0b66a35eb01 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.stderr b/src/test/ui/coherence/impl-foreign-for-foreign.stderr new file mode 100644 index 0000000000000..b03a75a77c346 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign.rs:12:1 + | +LL | impl Remote for i32 { + | ^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs new file mode 100644 index 0000000000000..5146263d99114 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs @@ -0,0 +1,25 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr new file mode 100644 index 0000000000000..bfaec790b20a6 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:12:1 + | +LL | impl Remote1> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:16:1 + | +LL | impl Remote1> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:20:1 + | +LL | impl Remote1> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[local].rs b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs new file mode 100644 index 0000000000000..050769dcf4ce8 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local(Rc); + +impl Remote1> for i32 {} +impl Remote1> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs new file mode 100644 index 0000000000000..03b11edf98b41 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs @@ -0,0 +1,21 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Box { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote for Box> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr new file mode 100644 index 0000000000000..2ce4921cf938f --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:12:1 + | +LL | impl Remote for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:16:1 + | +LL | impl Remote for Box> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs new file mode 100644 index 0000000000000..ae03ce6a440dc --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote for Box {} +impl Remote for Box> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-local.rs b/src/test/ui/coherence/impl-foreign-for-local.rs new file mode 100644 index 0000000000000..c9dddeba18dc5 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs new file mode 100644 index 0000000000000..06efb6c2ad75e --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs @@ -0,0 +1,26 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1>> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1>> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr new file mode 100644 index 0000000000000..bf2361a1718af --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:13:1 + | +LL | impl Remote1> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:17:1 + | +LL | impl Remote1>> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:21:1 + | +LL | impl Remote1>> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs new file mode 100644 index 0000000000000..d47e0a36a5659 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs @@ -0,0 +1,18 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for i32 {} +impl Remote1>> for f64 {} +impl Remote1>> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs new file mode 100644 index 0000000000000..850b6f85d0ed7 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for (Local, T) { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr new file mode 100644 index 0000000000000..ff0b9d6d0da9a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-(local, t).rs:12:1 + | +LL | impl Remote for (Local, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs new file mode 100644 index 0000000000000..db7a2ae8076a3 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs @@ -0,0 +1,23 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; +use std::sync::Arc; + +struct Local; + +impl Remote for Rc { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +impl Remote for Arc { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr new file mode 100644 index 0000000000000..d7ffcaf76f9a2 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:13:1 + | +LL | impl Remote for Rc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:18:1 + | +LL | impl Remote for Arc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs new file mode 100644 index 0000000000000..4cc19e1a526ca --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Box { + //~^ ERROR type parameter `T` must be used as the type parameter for + // | some local type (e.g., `MyStruct`) +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr new file mode 100644 index 0000000000000..20ce11ef9759e --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/impl[t]-foreign-for-fundamental[t].rs:12:1 + | +LL | impl Remote for Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs new file mode 100644 index 0000000000000..914680f191ac9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1> for Rc {} +impl Remote1>> for Rc {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs new file mode 100644 index 0000000000000..1e84ff40c6227 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1 for Rc {} +impl Remote1> for Rc {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs new file mode 100644 index 0000000000000..ea6aa101d209c --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1(Rc); + +impl Remote1 for Box> {} +impl Remote1> for Box> {} +impl Remote1> for Box> {} +impl Remote1>> for Box> {} + +fn main() {} From b6f6dc4f7ffb7e52e5621230728c32908e9b6259 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 9 Oct 2019 06:08:46 -0400 Subject: [PATCH 11/20] Don't ICE when evaluating writes to uninhabited enum variants --- src/librustc/mir/interpret/error.rs | 7 +++-- src/librustc_mir/interpret/operand.rs | 8 ++--- src/librustc_mir/interpret/place.rs | 16 ++++++---- src/librustc_mir/interpret/validity.rs | 2 +- .../write-to-uninhabited-enum-variant.rs | 29 +++++++++++++++++++ 5 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 71967b513a049..0c0951c69c2ce 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -363,6 +363,8 @@ pub enum UndefinedBehaviorInfo { UbExperimental(String), /// Unreachable code was executed. Unreachable, + /// An enum discriminant was set to a value which was outside the range of valid values. + InvalidDiscriminant(ScalarMaybeUndef), } impl fmt::Debug for UndefinedBehaviorInfo { @@ -373,6 +375,8 @@ impl fmt::Debug for UndefinedBehaviorInfo { write!(f, "{}", msg), Unreachable => write!(f, "entered unreachable code"), + InvalidDiscriminant(val) => + write!(f, "encountered invalid enum discriminant {}", val), } } } @@ -404,7 +408,6 @@ pub enum UnsupportedOpInfo<'tcx> { InvalidMemoryAccess, InvalidFunctionPointer, InvalidBool, - InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, msg: CheckInAllocMsg, @@ -489,8 +492,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { write!(f, "incorrect alloc info: expected size {} and align {}, \ got size {} and align {}", size.bytes(), align.bytes(), size2.bytes(), align2.bytes()), - InvalidDiscriminant(val) => - write!(f, "encountered invalid enum discriminant {}", val), InvalidMemoryAccess => write!(f, "tried to access memory through an invalid pointer"), DanglingPointerDeref => diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 4bdd71f9602ac..4d9be55945e02 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -647,7 +647,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let bits_discr = raw_discr .not_undef() .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size)) - .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?; + .map_err(|_| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type // requires first sign extending with the discriminant layout @@ -677,7 +677,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => bug!("tagged layout for non-adt non-generator"), }.ok_or_else( - || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())) + || err_ub!(InvalidDiscriminant(raw_discr.erase_tag())) )?; (real_discr, index.0) }, @@ -689,7 +689,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let variants_start = niche_variants.start().as_u32(); let variants_end = niche_variants.end().as_u32(); let raw_discr = raw_discr.not_undef().map_err(|_| { - err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef)) + err_ub!(InvalidDiscriminant(ScalarMaybeUndef::Undef)) })?; match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { Err(ptr) => { @@ -697,7 +697,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr_valid = niche_start == 0 && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag().into())) + throw_ub!(InvalidDiscriminant(raw_discr.erase_tag().into())) } (dataful_variant.as_u32() as u128, dataful_variant) }, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3ba989529f18f..6ee6f6095d971 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1034,9 +1034,13 @@ where variant_index: VariantIdx, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { + let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into(); + match dest.layout.variants { layout::Variants::Single { index } => { - assert_eq!(index, variant_index); + if index != variant_index { + throw_ub!(InvalidDiscriminant(variant_scalar)); + } } layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, @@ -1044,7 +1048,9 @@ where discr_index, .. } => { - assert!(dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index)); + if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) { + throw_ub!(InvalidDiscriminant(variant_scalar)); + } let discr_val = dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val; @@ -1067,9 +1073,9 @@ where discr_index, .. } => { - assert!( - variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(), - ); + if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() { + throw_ub!(InvalidDiscriminant(variant_scalar)); + } if variant_index != dataful_variant { let variants_start = niche_variants.start().as_u32(); let variant_index_relative = variant_index.as_u32() diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 853fcb1beabf5..3444fb60f333b 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -344,7 +344,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { - err_unsup!(InvalidDiscriminant(val)) => + err_ub!(InvalidDiscriminant(val)) => throw_validation_failure!( val, self.path, "a valid enum discriminant" ), diff --git a/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs new file mode 100644 index 0000000000000..0a5ca97e2d971 --- /dev/null +++ b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs @@ -0,0 +1,29 @@ +// run-pass +// ignore-wasm + +#![allow(dead_code)] + +enum Empty { } +enum Test1 { + A(u8), + B(Empty), +} +enum Test2 { + A(u8), + B(Empty), + C, +} + +fn bar() -> Option { + std::process::exit(0) +} + +fn main() { + if let Some(x) = bar() { + Test1::B(x); + } + + if let Some(x) = bar() { + Test2::B(x); + } +} From 224591028e3a370193465d6639af0cdd1bf42535 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 16 Oct 2019 19:03:40 +0800 Subject: [PATCH 12/20] Fix types --- src/libstd/sys/unix/fs.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0934ffef48773..f1bdbb58644ff 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -137,22 +137,24 @@ cfg_has_statx! {{ Ok(_) => { // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); - stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor); + // c_ulong`` on gnu-mips, `dev_t` otherwise + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; stat.st_ino = buf.stx_ino as libc::ino64_t; stat.st_nlink = buf.stx_nlink as libc::nlink_t; stat.st_mode = buf.stx_mode as libc::mode_t; stat.st_uid = buf.stx_uid as libc::uid_t; stat.st_gid = buf.stx_gid as libc::gid_t; - stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor); + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; stat.st_size = buf.stx_size as off64_t; stat.st_blksize = buf.stx_blksize as libc::blksize_t; stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; - stat.st_atime_nsec = buf.stx_atime.tv_nsec as libc::c_long; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; - stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as libc::c_long; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; - stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as libc::c_long; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; let extra = StatxExtraFields { stx_mask: buf.stx_mask, From f7804efb1ad165e6c6d7784e7d6dd563daa77568 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 16 Oct 2019 19:21:54 +0800 Subject: [PATCH 13/20] Fix typo --- src/libstd/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index f1bdbb58644ff..fee6eecf864a9 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -137,7 +137,7 @@ cfg_has_statx! {{ Ok(_) => { // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); - // c_ulong`` on gnu-mips, `dev_t` otherwise + // `c_ulong` on gnu-mips, `dev_t` otherwise stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; stat.st_ino = buf.stx_ino as libc::ino64_t; stat.st_nlink = buf.stx_nlink as libc::nlink_t; From c3bbdc5c8016726a18b9ae7efa963b3864666b80 Mon Sep 17 00:00:00 2001 From: oxalica Date: Thu, 17 Oct 2019 07:47:33 +0800 Subject: [PATCH 14/20] Fix sentences --- src/libstd/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 055686fb0271a..6595f54162f0a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1091,8 +1091,8 @@ impl Metadata { /// Returns the creation time listed in this metadata. /// /// The returned value corresponds to the `btime` field of `statx` on - /// Linux not prior to 4.11, the `birthtime` field of `stat` on other - /// Unix platforms and the `ftCreationTime` field on Windows platforms. + /// Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other + /// Unix platforms, and the `ftCreationTime` field on Windows platforms. /// /// # Errors /// From d1db077e067b00c4733512dd23f8b144a760f367 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Oct 2019 14:48:20 +0200 Subject: [PATCH 15/20] Add long error explanation for E0575 --- src/librustc_resolve/error_codes.rs | 54 ++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index ab3d95dd8edfe..8ccb27078d569 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1735,6 +1735,59 @@ match eco { ``` "##, +E0575: r##" +Something other than a type or an associated type was given. + +Erroneous code example: + +```compile_fail,E0575 +enum Rick { Morty } + +let _: ::Morty; // error! + +trait Age { + type Empire; + fn Mythology() {} +} + +impl Age for u8 { + type Empire = u16; +} + +let _: ::Mythology; // error! +``` + +In both cases, we're declaring a variable (called `_`) and we're giving it a +type. However, `::Morty` and `::Mythology` aren't types, +therefore the compiler throws an error. + +`::Morty` is an enum variant, you cannot use a variant as a type, +you have to use the enum directly: + +``` +enum Rick { Morty } + +let _: Rick; // ok! +``` + +`::Mythology` is a trait method, which is definitely not a type. +However, the `Age` trait provides an associated type `Empire` which can be +used as a type: + +``` +trait Age { + type Empire; + fn Mythology() {} +} + +impl Age for u8 { + type Empire = u16; +} + +let _: ::Empire; // ok! +``` +"##, + E0603: r##" A private item was used outside its scope. @@ -1862,7 +1915,6 @@ struct Foo> { // E0427, merged into 530 // E0467, removed // E0470, removed - E0575, E0576, E0577, E0578, From 21d9258909d131898bdd9d69bc9da8be3b31db9a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 12 Oct 2019 14:48:28 +0200 Subject: [PATCH 16/20] Update ui tests --- src/test/ui/ufcs/ufcs-partially-resolved.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 5ee8adaaf270f..39752f66b9d65 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -200,5 +200,5 @@ LL | ::X::N; error: aborting due to 32 previous errors -Some errors have detailed explanations: E0223, E0433, E0599. +Some errors have detailed explanations: E0223, E0433, E0575, E0599. For more information about an error, try `rustc --explain E0223`. From 91239077211ad25ab1e86241493ac4c3e8a35909 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 13 Oct 2019 13:48:26 -0400 Subject: [PATCH 17/20] Improve comments and structure of `ConstProp::const_prop()` Per code review feedback --- src/librustc_mir/transform/const_prop.rs | 82 +++++++++++++++--------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index abb880fd62419..f0c0e57344388 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -434,26 +434,32 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) -> Option> { let span = source_info.span; - // perform any special checking for specific Rvalue types + let overflow_check = self.tcx.sess.overflow_checks(); + + // Perform any special handling for specific Rvalue types. + // Generally, checks here fall into one of two categories: + // 1. Additional checking to provide useful lints to the user + // - In this case, we will do some validation and then fall through to the + // end of the function which evals the assignment. + // 2. Working around bugs in other parts of the compiler + // - In this case, we'll return `None` from this function to stop evaluation. match rvalue { - Rvalue::UnaryOp(UnOp::Neg, arg) => { + // Additional checking: if overflow checks are disabled (which is usually the case in + // release mode), then we need to do additional checking here to give lints to the user + // if an overflow would occur. + Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => { trace!("checking UnaryOp(op = Neg, arg = {:?})", arg); - let overflow_check = self.tcx.sess.overflow_checks(); self.use_ecx(source_info, |this| { - // We check overflow in debug mode already - // so should only check in release mode. - if !overflow_check { - let ty = arg.ty(&this.local_decls, this.tcx); - - if ty.is_integral() { - let arg = this.ecx.eval_operand(arg, None)?; - let prim = this.ecx.read_immediate(arg)?; - // Need to do overflow check here: For actual CTFE, MIR - // generation emits code that does this before calling the op. - if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { - throw_panic!(OverflowNeg) - } + let ty = arg.ty(&this.local_decls, this.tcx); + + if ty.is_integral() { + let arg = this.ecx.eval_operand(arg, None)?; + let prim = this.ecx.read_immediate(arg)?; + // Need to do overflow check here: For actual CTFE, MIR + // generation emits code that does this before calling the op. + if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) { + throw_panic!(OverflowNeg) } } @@ -461,6 +467,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { })?; } + // Additional checking: check for overflows on integer binary operations and report + // them to the user as lints. Rvalue::BinaryOp(op, left, right) => { trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); @@ -490,25 +498,34 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } } - self.use_ecx(source_info, |this| { - let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; - let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; - - // We check overflow in debug mode already - // so should only check in release mode. - if !this.tcx.sess.overflow_checks() && overflow { - let err = err_panic!(Overflow(*op)).into(); - return Err(err); - } - Ok(()) - })?; + // If overflow checking is enabled (like in debug mode by default), + // then we'll already catch overflow when we evaluate the `Assert` statement + // in MIR. However, if overflow checking is disabled, then there won't be any + // `Assert` statement and so we have to do additional checking here. + if !overflow_check { + self.use_ecx(source_info, |this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?; + + if overflow { + let err = err_panic!(Overflow(*op)).into(); + return Err(err); + } + + Ok(()) + })?; + } } + // Work around: avoid ICE in miri. + // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref + // from a function argument that hasn't been assigned to in this function. The main + // issue is if an arg is a fat-pointer, miri `expects()` to be able to read the value + // of that pointer to get size info. However, since this is `ConstProp`, that argument + // doesn't actually have a backing value and so this causes an ICE. Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { trace!("checking Ref({:?})", place); - // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref - // from a function argument that hasn't been assigned to in this function. let alive = if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { true @@ -520,9 +537,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } + // Work around: avoid extra unnecessary locals. + // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that + // `SimplifyLocals` doesn't know it can remove. Rvalue::Aggregate(_, operands) if operands.len() == 0 => { - // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that - // `SimplifyLocals` doesn't know it can remove. return None; } From 83e97c6ac1b722c1b55fdf9d6378f87d9e0cdbdd Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 17 Oct 2019 13:53:57 +0200 Subject: [PATCH 18/20] properly document panics in div_euclid and rem_euclid --- src/libcore/num/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 998c8f8165204..8f4ade377e312 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1864,7 +1864,7 @@ if `self < 0`, this is equal to round towards +/- infinity. # Panics -This function will panic if `rhs` is 0. +This function will panic if `rhs` is 0 or the division results in overflow. # Examples @@ -1903,7 +1903,7 @@ This is done as if by the Euclidean division algorithm -- given # Panics -This function will panic if `rhs` is 0. +This function will panic if `rhs` is 0 or the division results in overflow. # Examples @@ -3694,6 +3694,10 @@ Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self / rhs`. +# Panics + +This function will panic if `rhs` is 0. + # Examples Basic usage: @@ -3719,6 +3723,10 @@ Since, for the positive integers, all common definitions of division are equal, this is exactly equal to `self % rhs`. +# Panics + +This function will panic if `rhs` is 0. + # Examples Basic usage: From a4d94925c737b1fee1dc8e90225a71b47ed77042 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Oct 2019 14:15:59 -0400 Subject: [PATCH 19/20] add option to ping llvm ice-breakers to triagebot --- triagebot.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index d87c5b64c21c2..b39c95f683618 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -8,3 +8,14 @@ allow-unauthenticated = [ ] [assign] + +[ping.icebreaker-llvm] +message = """\ +Hey LLVM ICE-breakers! This bug has been identified as a good +"LLVM ICE-breaking candidate". In case it's useful, here are some +[instructions] for tackling these sorts of bugs. Maybe take a look? +Thanks! <3 + +[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/llvm.html +""" +label = "ICEBreaker-LLVM" From 54879949f18ed44dc4db4b9c450d6c09551a2e0d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 17 Oct 2019 16:53:47 -0400 Subject: [PATCH 20/20] Update triagebot.toml Co-Authored-By: Mark Rousskov --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index b39c95f683618..f0e3a99037b02 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -9,7 +9,7 @@ allow-unauthenticated = [ [assign] -[ping.icebreaker-llvm] +[ping.icebreakers-llvm] message = """\ Hey LLVM ICE-breakers! This bug has been identified as a good "LLVM ICE-breaking candidate". In case it's useful, here are some