From cf1406c4e37b0c0710788aa81c989618650b8e43 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 1 Nov 2018 09:52:14 +0100 Subject: [PATCH 01/19] Clarify error message for -C opt-level The new levels s and z are not mentioned as possible values. --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 569e7a24d2353..459a748dd6a60 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -2083,7 +2083,7 @@ pub fn build_session_options_and_crate_config( error_format, &format!( "optimization level needs to be \ - between 0-3 (instead was `{}`)", + between 0-3, s or z (instead was `{}`)", arg ), ); From 5aeb6c756e4b6e28366dee28802022430c66605e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 3 Nov 2018 02:24:50 +0100 Subject: [PATCH 02/19] Sidestep an ICE by providing *some* description for `ReEmpty` when it arises. --- src/librustc/infer/error_reporting/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d19c495af3b96..6c5f10332956d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -178,6 +178,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.msg_span_from_early_bound_and_free_regions(region) } ty::ReStatic => ("the static lifetime".to_owned(), None), + ty::ReEmpty => ("an empty lifetime".to_owned(), None), _ => bug!("{:?}", region), } } From cc33aecb683b1cb08bd60ba1f24ef797827fda94 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 3 Nov 2018 02:29:26 +0100 Subject: [PATCH 03/19] Regression test for issue 55608. --- .../issue-55608-captures-empty-region.rs | 22 +++++++++++++++++++ .../issue-55608-captures-empty-region.stderr | 11 ++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-55608-captures-empty-region.rs create mode 100644 src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs new file mode 100644 index 0000000000000..7ebc348996f5e --- /dev/null +++ b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs @@ -0,0 +1,22 @@ +// This used to ICE because it creates an `impl Trait` that captures a +// hidden empty region. + +#![feature(conservative_impl_trait)] + +fn server() -> impl FilterBase2 { //~ ERROR [E0700] + segment2(|| { loop { } }).map2(|| "") +} + +trait FilterBase2 { + fn map2(self, _fn: F) -> Map2 where Self: Sized { loop { } } +} + +struct Map2 { _func: F } + +impl FilterBase2 for Map2 { } + +fn segment2(_fn: F) -> Map2 where F: Fn() -> Result<(), ()> { + loop { } +} + +fn main() { server(); } diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr new file mode 100644 index 0000000000000..d1f147834d2ef --- /dev/null +++ b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr @@ -0,0 +1,11 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/issue-55608-captures-empty-region.rs:6:16 + | +LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700] + | ^^^^^^^^^^^^^^^^ + | + = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. From f3428a7dc4bef051f6c1fb454761eda77dbeb106 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 3 Nov 2018 10:20:07 -0700 Subject: [PATCH 04/19] rustc: Delete grouping logic from the musl target This commit deletes the injection of `-(` and `-)` options to the linker for the musl targets. This actually causes problems today on nightly if you execute: $ echo 'fn main() {}' >> foo.rs $ rustc --target x86_64-unknown-linux-musl -C panic=abort you get a linker error about "cannot nest groups". This comes about because rustc injects its own `--start-group` and `--end-group` variables which clash with the outer `-(` and `-)` variables. It's not entirely clear to me why this doesn't affect the musl target by default (in `-C panic=unwind` mode). The compiler's own injection of `--start-group` and `--end-group` should solve the issues mentioned in the comment for injecting `-(` and `-)` as well. --- src/librustc_target/spec/linux_musl_base.rs | 25 --------------------- 1 file changed, 25 deletions(-) diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 7a3f3c2a518bc..c87f14977cb1d 100644 --- a/src/librustc_target/spec/linux_musl_base.rs +++ b/src/librustc_target/spec/linux_musl_base.rs @@ -24,31 +24,6 @@ pub fn opts() -> TargetOptions { // argument is *not* necessary for normal builds, but it can't hurt! base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string()); - // There's a whole bunch of circular dependencies when dealing with MUSL - // unfortunately. To put this in perspective libc is statically linked to - // liblibc and libunwind is statically linked to libstd: - // - // * libcore depends on `fmod` which is in libc (transitively in liblibc). - // liblibc, however, depends on libcore. - // * compiler-rt has personality symbols that depend on libunwind, but - // libunwind is in libstd which depends on compiler-rt. - // - // Recall that linkers discard libraries and object files as much as - // possible, and with all the static linking and archives flying around with - // MUSL the linker is super aggressively stripping out objects. For example - // the first case has fmod stripped from liblibc (it's in its own object - // file) so it's not there when libcore needs it. In the second example all - // the unused symbols from libunwind are stripped (each is in its own object - // file in libstd) before we end up linking compiler-rt which depends on - // those symbols. - // - // To deal with these circular dependencies we just force the compiler to - // link everything as a group, not stripping anything out until everything - // is processed. The linker will still perform a pass to strip out object - // files but it won't do so until all objects/archives have been processed. - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string()); - base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]); - // When generating a statically linked executable there's generally some // small setup needed which is listed in these files. These are provided by // a musl toolchain and are linked by default by the `musl-gcc` script. Note From 463ad9098e12d1fbcfec2125d0ebfc6467866e38 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 2 Nov 2018 23:38:16 +0100 Subject: [PATCH 05/19] Support memcpy/memmove with differing src/dst alignment If LLVM 7 is used, generate memcpy/memmove with differing src/dst alignment. I've added new FFI functions to construct these through the builder API, which is more convenient than dealing with differing intrinsic signatures depending on the LLVM version. --- src/librustc_codegen_llvm/abi.rs | 3 ++- src/librustc_codegen_llvm/base.rs | 27 +++++++++---------- src/librustc_codegen_llvm/builder.rs | 18 +++++++++++++ src/librustc_codegen_llvm/context.rs | 6 ----- src/librustc_codegen_llvm/intrinsic.rs | 28 +++++-------------- src/librustc_codegen_llvm/llvm/ffi.rs | 16 +++++++++++ src/librustc_codegen_llvm/mir/block.rs | 3 ++- src/librustc_codegen_llvm/mir/operand.rs | 6 ++--- src/rustllvm/RustWrapper.cpp | 34 ++++++++++++++++++++++++ src/test/codegen/packed.rs | 4 +-- src/test/codegen/stores.rs | 4 +-- 11 files changed, 98 insertions(+), 51 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index e50534a4e1dc9..bd7a1c2c3293e 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -225,9 +225,10 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { // ...and then memcpy it to the intended destination. base::call_memcpy(bx, bx.pointercast(dst.llval, Type::i8p(cx)), + self.layout.align, bx.pointercast(llscratch, Type::i8p(cx)), + scratch_align, C_usize(cx, self.layout.size.bytes()), - self.layout.align.min(scratch_align), MemFlags::empty()); bx.lifetime_end(llscratch, scratch_size); diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 9736994fc0755..dd1348cdf2b6a 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -53,7 +53,7 @@ use mir::place::PlaceRef; use attributes; use builder::{Builder, MemFlags}; use callee; -use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; +use common::{C_bool, C_bytes_in_context, C_usize}; use rustc_mir::monomorphize::item::DefPathBasedNames; use common::{C_struct_in_context, C_array, val_ty}; use consts; @@ -77,7 +77,6 @@ use rustc_data_structures::sync::Lrc; use std::any::Any; use std::cmp; use std::ffi::CString; -use std::i32; use std::ops::{Deref, DerefMut}; use std::sync::mpsc; use std::time::{Instant, Duration}; @@ -319,8 +318,8 @@ pub fn coerce_unsized_into( } if src_f.layout.ty == dst_f.layout.ty { - memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, - src_f.align.min(dst_f.align), MemFlags::empty()); + memcpy_ty(bx, dst_f.llval, dst_f.align, src_f.llval, src_f.align, + src_f.layout, MemFlags::empty()); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -420,36 +419,34 @@ pub fn to_immediate_scalar( pub fn call_memcpy( bx: &Builder<'_, 'll, '_>, dst: &'ll Value, + dst_align: Align, src: &'ll Value, + src_align: Align, n_bytes: &'ll Value, - align: Align, flags: MemFlags, ) { if flags.contains(MemFlags::NONTEMPORAL) { // HACK(nox): This is inefficient but there is no nontemporal memcpy. - let val = bx.load(src, align); + let val = bx.load(src, src_align); let ptr = bx.pointercast(dst, val_ty(val).ptr_to()); - bx.store_with_flags(val, ptr, align, flags); + bx.store_with_flags(val, ptr, dst_align, flags); return; } let cx = bx.cx; - let ptr_width = &cx.sess().target.target.target_pointer_width; - let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); - let memcpy = cx.get_intrinsic(&key); let src_ptr = bx.pointercast(src, Type::i8p(cx)); let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); let size = bx.intcast(n_bytes, cx.isize_ty, false); - let align = C_i32(cx, align.abi() as i32); - let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); - bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); + let volatile = flags.contains(MemFlags::VOLATILE); + bx.memcpy(dst_ptr, dst_align.abi(), src_ptr, src_align.abi(), size, volatile); } pub fn memcpy_ty( bx: &Builder<'_, 'll, 'tcx>, dst: &'ll Value, + dst_align: Align, src: &'ll Value, + src_align: Align, layout: TyLayout<'tcx>, - align: Align, flags: MemFlags, ) { let size = layout.size.bytes(); @@ -457,7 +454,7 @@ pub fn memcpy_ty( return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); + call_memcpy(bx, dst, dst_align, src, src_align, C_usize(bx.cx, size), flags); } pub fn call_memset( diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 2fe6a0377f81b..eaaa450fbf419 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -784,6 +784,24 @@ impl Builder<'a, 'll, 'tcx> { } } + pub fn memcpy(&self, dst: &'ll Value, dst_align: u64, + src: &'ll Value, src_align: u64, + size: &'ll Value, is_volatile: bool) -> &'ll Value { + unsafe { + llvm::LLVMRustBuildMemCpy(self.llbuilder, dst, dst_align as c_uint, + src, src_align as c_uint, size, is_volatile) + } + } + + pub fn memmove(&self, dst: &'ll Value, dst_align: u64, + src: &'ll Value, src_align: u64, + size: &'ll Value, is_volatile: bool) -> &'ll Value { + unsafe { + llvm::LLVMRustBuildMemMove(self.llbuilder, dst, dst_align as c_uint, + src, src_align as c_uint, size, is_volatile) + } + } + pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { self.count_insn("minnum"); unsafe { diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 241f7989e1681..59dc0f61ecccd 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -530,12 +530,6 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> { let t_v4f64 = Type::vector(t_f64, 4); let t_v8f64 = Type::vector(t_f64, 8); - ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); - ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); - ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); - ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void); ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void); ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 03244c18ac3e4..f7cef6be5b529 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -23,7 +23,7 @@ use glue; use type_::Type; use type_of::LayoutLlvmExt; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{HasDataLayout, LayoutOf}; +use rustc::ty::layout::LayoutOf; use rustc::hir; use syntax::ast; use syntax::symbol::Symbol; @@ -690,28 +690,14 @@ fn copy_intrinsic( let cx = bx.cx; let (size, align) = cx.size_and_align_of(ty); let size = C_usize(cx, size.bytes()); - let align = C_i32(cx, align.abi() as i32); - - let operation = if allow_overlap { - "memmove" - } else { - "memcpy" - }; - - let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, - cx.data_layout().pointer_size.bits()); - + let align = align.abi(); let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); let src_ptr = bx.pointercast(src, Type::i8p(cx)); - let llfn = cx.get_intrinsic(&name); - - bx.call(llfn, - &[dst_ptr, - src_ptr, - bx.mul(size, count), - align, - C_bool(cx, volatile)], - None) + if allow_overlap { + bx.memmove(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile) + } else { + bx.memcpy(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile) + } } fn memset_intrinsic( diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index f046ea030272a..64066d4d786a5 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -998,6 +998,22 @@ extern "C" { Bundle: Option<&OperandBundleDef<'a>>, Name: *const c_char) -> &'a Value; + pub fn LLVMRustBuildMemCpy(B: &Builder<'a>, + Dst: &'a Value, + DstAlign: c_uint, + Src: &'a Value, + SrcAlign: c_uint, + Size: &'a Value, + IsVolatile: bool) + -> &'a Value; + pub fn LLVMRustBuildMemMove(B: &Builder<'a>, + Dst: &'a Value, + DstAlign: c_uint, + Src: &'a Value, + SrcAlign: c_uint, + Size: &'a Value, + IsVolatile: bool) + -> &'a Value; pub fn LLVMBuildSelect(B: &Builder<'a>, If: &'a Value, Then: &'a Value, diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index a7f4c48c89bd6..3f9921a5cf930 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -784,7 +784,8 @@ impl FunctionCx<'a, 'll, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); + base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align, + op.layout, MemFlags::empty()); (scratch.llval, scratch.align, true) } else { (llval, align, true) diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index d1b6aa7fc4280..c76cbfcd97177 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -282,8 +282,8 @@ impl OperandValue<'ll> { } match self { OperandValue::Ref(r, None, source_align) => { - base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align), flags) + base::memcpy_ty(bx, dest.llval, dest.align, r, source_align, + dest.layout, flags) } OperandValue::Ref(_, Some(_), _) => { bug!("cannot directly store unsized values"); @@ -324,7 +324,7 @@ impl OperandValue<'ll> { // Allocate an appropriate region on the stack, and copy the value into it let (llsize, _) = glue::size_and_align_of_dst(&bx, unsized_ty, Some(llextra)); let lldst = bx.array_alloca(Type::i8(bx.cx), llsize, "unsized_tmp", max_align); - base::call_memcpy(&bx, lldst, llptr, llsize, min_align, flags); + base::call_memcpy(&bx, lldst, max_align, llptr, min_align, llsize, flags); // Store the allocated region and the extra to the indirect place. let indirect_operand = OperandValue::Pair(lldst, llextra); diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index affec73e3ac62..3a1e082b7550d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1239,6 +1239,40 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name)); } +extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size, bool IsVolatile) { +#if LLVM_VERSION_GE(7, 0) + return wrap(unwrap(B)->CreateMemCpy( + unwrap(Dst), DstAlign, + unwrap(Src), SrcAlign, + unwrap(Size), IsVolatile)); +#else + unsigned Align = std::min(DstAlign, SrcAlign); + return wrap(unwrap(B)->CreateMemCpy( + unwrap(Dst), unwrap(Src), + unwrap(Size), Align, IsVolatile)); +#endif +} + +extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size, bool IsVolatile) { +#if LLVM_VERSION_GE(7, 0) + return wrap(unwrap(B)->CreateMemMove( + unwrap(Dst), DstAlign, + unwrap(Src), SrcAlign, + unwrap(Size), IsVolatile)); +#else + unsigned Align = std::min(DstAlign, SrcAlign); + return wrap(unwrap(B)->CreateMemMove( + unwrap(Dst), unwrap(Src), + unwrap(Size), Align, IsVolatile)); +#endif +} + extern "C" LLVMValueRef LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, LLVMBasicBlockRef Then, diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index 10dd12909b644..b50f5b6f16fed 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -65,7 +65,7 @@ pub struct BigPacked2 { pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 1 %{{.*}}, i{{[0-9]+}} 32, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. @@ -77,7 +77,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 2 %{{.*}}, i{{[0-9]+}} 32, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 0aaf00bfdbe8e..871bee13b1931 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -31,7 +31,7 @@ pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) { // CHECK: store i32 %0, i32* [[TMP]] // CHECK: [[Y8:%[0-9]+]] = bitcast [4 x i8]* %y to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false) *x = y; } @@ -45,6 +45,6 @@ pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) { // CHECK: store i32 %0, i32* [[TMP]] // CHECK: [[Y8:%[0-9]+]] = bitcast %Bytes* %y to i8* // CHECK: [[TMP8:%[0-9]+]] = bitcast i32* [[TMP]] to i8* -// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 1 [[TMP8]], i{{[0-9]+}} 4, i1 false) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 [[Y8]], i8* align 4 [[TMP8]], i{{[0-9]+}} 4, i1 false) *x = y; } From e7f8c0d1050bc8871f5bb63cfe5018ed854d91e3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 6 Nov 2018 14:21:52 +0100 Subject: [PATCH 06/19] Sidestep link error from rustfix'ed code by using a *defined* static. As a drive-by, added `-g` to the compile-flags so that the test more reliably fails to compile when the extern static in question is *not* provided. (I.e. this is making the test more robust in the face of potential future revisions.) Fix #54388. --- src/test/ui/extern/extern-const.fixed | 25 +++++++++++++++++++++++++ src/test/ui/extern/extern-const.rs | 24 ++++++++++++------------ src/test/ui/extern/extern-const.stderr | 2 +- 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/extern/extern-const.fixed diff --git a/src/test/ui/extern/extern-const.fixed b/src/test/ui/extern/extern-const.fixed new file mode 100644 index 0000000000000..0229362cf0eca --- /dev/null +++ b/src/test/ui/extern/extern-const.fixed @@ -0,0 +1,25 @@ +// This test is checking that extern items cannot be const. It also +// checks that `rustfix` suggests the alternative of using an extern +// static. +// +// #54388: an unused reference to an undefined static may or may not +// compile. To sidestep this by using one that *is* defined. + +// run-rustfix +// compile-flags: -g -Z continue-parse-after-error +#![feature(libc)] +extern crate libc; + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + static rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` +} + +fn main() { + // We suggest turning the (illegal) extern `const` into an extern `static`, + // but this also requires `unsafe` (a deny-by-default lint at comment time, + // future error; Issue #36247) + unsafe { + let _x = rust_dbg_static_mut; + } +} diff --git a/src/test/ui/extern/extern-const.rs b/src/test/ui/extern/extern-const.rs index d8a167311d55c..e7b1715255532 100644 --- a/src/test/ui/extern/extern-const.rs +++ b/src/test/ui/extern/extern-const.rs @@ -1,18 +1,18 @@ -// 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. +// This test is checking that extern items cannot be const. It also +// checks that `rustfix` suggests the alternative of using an extern +// static. // -// 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. +// #54388: an unused reference to an undefined static may or may not +// compile. To sidestep this by using one that *is* defined. -// FIXME(#54388): re-enable rustfix later, when this test has consistent output across targets -// compile-flags: -Z continue-parse-after-error +// run-rustfix +// compile-flags: -g -Z continue-parse-after-error +#![feature(libc)] +extern crate libc; +#[link(name = "rust_test_helpers", kind = "static")] extern "C" { - const C: u8; //~ ERROR extern items cannot be `const` + const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` } fn main() { @@ -20,6 +20,6 @@ fn main() { // but this also requires `unsafe` (a deny-by-default lint at comment time, // future error; Issue #36247) unsafe { - let _x = C; + let _x = rust_dbg_static_mut; } } diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr index cbed5e56c76c4..7ebaec0368e3d 100644 --- a/src/test/ui/extern/extern-const.stderr +++ b/src/test/ui/extern/extern-const.stderr @@ -1,7 +1,7 @@ error: extern items cannot be `const` --> $DIR/extern-const.rs:15:5 | -LL | const C: u8; //~ ERROR extern items cannot be `const` +LL | const rust_dbg_static_mut: libc::c_int; //~ ERROR extern items cannot be `const` | ^^^^^ help: try using a static value: `static` error: aborting due to previous error From 3ec837e763ba423ddff0cdc886eba91f2836b6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 6 Nov 2018 14:49:09 -0800 Subject: [PATCH 07/19] Elide anon lifetimes in conflicting impl note --- src/librustc/traits/specialize/mod.rs | 5 ++++- src/test/ui/coherence/coherence-impls-copy.stderr | 4 ++-- src/test/ui/e0119/issue-28981.stderr | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0ce1d8f822755..d7b5dd049e350 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -396,7 +396,10 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_, '_, '_>, impl_def_id: DefId) -> Option< if !substs.is_noop() { types_without_default_bounds.extend(substs.types()); w.push('<'); - w.push_str(&substs.iter().map(|k| k.to_string()).collect::>().join(", ")); + w.push_str(&substs.iter() + .map(|k| k.to_string()) + .filter(|k| &k[..] != "'_") + .collect::>().join(", ")); w.push('>'); } diff --git a/src/test/ui/coherence/coherence-impls-copy.stderr b/src/test/ui/coherence/coherence-impls-copy.stderr index 613ee0a269e70..dc417957795f5 100644 --- a/src/test/ui/coherence/coherence-impls-copy.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.stderr @@ -14,7 +14,7 @@ LL | impl Copy for &'static NotSync {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl<'_, T> std::marker::Copy for &T + - impl std::marker::Copy for &T where T: ?Sized; error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`: @@ -24,7 +24,7 @@ LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl<'_, T> std::marker::Copy for &T + - impl std::marker::Copy for &T where T: ?Sized; error[E0206]: the trait `Copy` may not be implemented for this type diff --git a/src/test/ui/e0119/issue-28981.stderr b/src/test/ui/e0119/issue-28981.stderr index 4886ad7717574..76ff88d6cc623 100644 --- a/src/test/ui/e0119/issue-28981.stderr +++ b/src/test/ui/e0119/issue-28981.stderr @@ -5,7 +5,7 @@ LL | impl Deref for Foo { } //~ ERROR must be used | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl<'_, T> std::ops::Deref for &T + - impl std::ops::Deref for &T where T: ?Sized; error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g. `MyStruct`) From e72afa9573ab8cb7ca2482f53b234bb59e3040ef Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 21 Oct 2018 11:58:39 -0400 Subject: [PATCH 08/19] Consume optimization fuel from the MIR inliner This makes it easier to debug mis-optimizations that occur during inlining. Thanks to @nikomatsakis for the suggestion! --- src/librustc_mir/transform/inline.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 199cf5650fda8..2db3bbda3233b 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -137,7 +137,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let callee_mir = match self.tcx.try_optimized_mir(callsite.location.span, callsite.callee) { - Ok(callee_mir) if self.should_inline(callsite, callee_mir) => { + Ok(callee_mir) if self.consider_optimizing(callsite, callee_mir) => { self.tcx.subst_and_normalize_erasing_regions( &callsite.substs, param_env, @@ -198,6 +198,18 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } + fn consider_optimizing(&self, + callsite: CallSite<'tcx>, + callee_mir: &Mir<'tcx>) + -> bool + { + debug!("consider_optimizing({:?})", callsite); + self.should_inline(callsite, callee_mir) + && self.tcx.consider_optimizing(|| format!("Inline {:?} into {:?}", + callee_mir.span, + callsite)) + } + fn should_inline(&self, callsite: CallSite<'tcx>, callee_mir: &Mir<'tcx>) From f63c2f80e51a1942a28c660adad0d3bad74574e2 Mon Sep 17 00:00:00 2001 From: F001 Date: Wed, 7 Nov 2018 12:26:05 +0800 Subject: [PATCH 09/19] fix ICE --- src/librustc_typeck/check/_match.rs | 12 +++++++----- src/test/ui/match/match-fn-call.rs | 12 ++++++++++++ src/test/ui/match/match-fn-call.stderr | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/match/match-fn-call.rs create mode 100644 src/test/ui/match/match-fn-call.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 40f2072079a5a..4a300fe09215c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -814,11 +814,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); report_unexpected_def(def); return self.tcx.types.err; } - // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = pat_ty.fn_sig(tcx).output(); - let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); - - self.demand_eqtype(pat.span, expected, pat_ty); let variant = match def { Def::Err => { @@ -836,6 +831,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } _ => bug!("unexpected pattern definition: {:?}", def) }; + + // Replace constructor type with constructed type for tuple struct patterns. + let pat_ty = pat_ty.fn_sig(tcx).output(); + let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); + + self.demand_eqtype(pat.span, expected, pat_ty); + // Type check subpatterns. if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { diff --git a/src/test/ui/match/match-fn-call.rs b/src/test/ui/match/match-fn-call.rs new file mode 100644 index 0000000000000..d9c50e75c4944 --- /dev/null +++ b/src/test/ui/match/match-fn-call.rs @@ -0,0 +1,12 @@ +use std::path::Path; + +fn main() { + let path = Path::new("foo"); + match path { + Path::new("foo") => println!("foo"), + //~^ ERROR expected tuple struct/variant + Path::new("bar") => println!("bar"), + //~^ ERROR expected tuple struct/variant + _ => (), + } +} diff --git a/src/test/ui/match/match-fn-call.stderr b/src/test/ui/match/match-fn-call.stderr new file mode 100644 index 0000000000000..4e24621706bdb --- /dev/null +++ b/src/test/ui/match/match-fn-call.stderr @@ -0,0 +1,15 @@ +error[E0164]: expected tuple struct/variant, found method `::new` + --> $DIR/match-fn-call.rs:6:9 + | +LL | Path::new("foo") => println!("foo"), + | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + +error[E0164]: expected tuple struct/variant, found method `::new` + --> $DIR/match-fn-call.rs:8:9 + | +LL | Path::new("bar") => println!("bar"), + | ^^^^^^^^^^^^^^^^ not a tuple variant or struct + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0164`. From 2d7426bb5a55fa27555de658fca529d8b205ef66 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 7 Nov 2018 15:32:58 +0100 Subject: [PATCH 10/19] borrow_set: remove a helper function and a clone it uses --- src/librustc_mir/borrow_check/borrow_set.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index db56ce4627410..c432826dca865 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -21,7 +21,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::bit_set::BitSet; use std::fmt; -use std::hash::Hash; use std::ops::Index; crate struct BorrowSet<'tcx> { @@ -233,21 +232,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { self.insert_as_pending_if_two_phase(location, &assigned_place, region, kind, idx); - insert(&mut self.region_map, ®ion, idx); + self.region_map.entry(region).or_default().insert(idx); if let Some(local) = borrowed_place.root_local() { - insert(&mut self.local_map, &local, idx); + self.local_map.entry(local).or_default().insert(idx); } } - return self.super_assign(block, assigned_place, rvalue, location); - - fn insert<'a, K, V>(map: &'a mut FxHashMap>, k: &K, v: V) - where - K: Clone + Eq + Hash, - V: Eq + Hash, - { - map.entry(k.clone()).or_default().insert(v); - } + self.super_assign(block, assigned_place, rvalue, location) } fn visit_place( From 299a452a75883b64ea15fc7e7f0d139cab3d750f Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 7 Nov 2018 13:40:55 +0100 Subject: [PATCH 11/19] Ignore never-initialized locals for `unused_mut`. This commit filters out locals that have never been initialized for consideration in the `unused_mut` lint. This is intended to detect when the statement that would have initialized the local was removed as unreachable code. In these cases, we would not want to lint. This is the same behaviour as the AST borrow checker. This is achieved by taking advantage of an existing pass over the MIR for the `unused_mut` lint and creating a set of those locals that were never initialized. --- src/librustc/mir/mod.rs | 14 +++ src/librustc_mir/borrow_check/mod.rs | 20 ++-- src/librustc_mir/borrow_check/used_muts.rs | 104 +++++++++++++++++---- src/test/ui/nll/issue-55344.rs | 26 ++++++ 4 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/nll/issue-55344.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c662ed6a6bf06..722bb64a7469d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -304,6 +304,20 @@ impl<'tcx> Mir<'tcx> { }) } + /// Returns an iterator over all user-declared mutable locals. + #[inline] + pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator + 'a { + (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { + let local = Local::new(index); + let decl = &self.local_decls[local]; + if decl.is_user_variable.is_some() && decl.mutability == Mutability::Mut { + Some(local) + } else { + None + } + }) + } + /// Returns an iterator over all user-declared mutable arguments and locals. #[inline] pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator + 'a { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d4f00ab3bb91a..4e03f6f7f5e7a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -281,23 +281,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // Note that this set is expected to be small - only upvars from closures // would have a chance of erroneously adding non-user-defined mutable vars // to the set. - let temporary_used_locals: FxHashSet = mbcx - .used_mut - .iter() + let temporary_used_locals: FxHashSet = mbcx.used_mut.iter() .filter(|&local| mbcx.mir.local_decls[*local].is_user_variable.is_none()) .cloned() .collect(); - mbcx.gather_used_muts(temporary_used_locals); + // For the remaining unused locals that are marked as mutable, we avoid linting any that + // were never initialized. These locals may have been removed as unreachable code; or will be + // linted as unused variables. + let unused_mut_locals = mbcx.mir.mut_vars_iter() + .filter(|local| !mbcx.used_mut.contains(local)) + .collect(); + mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); debug!("mbcx.used_mut: {:?}", mbcx.used_mut); - let used_mut = mbcx.used_mut; - - for local in mbcx - .mir - .mut_vars_and_args_iter() - .filter(|local| !used_mut.contains(local)) - { + for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data { let local_decl = &mbcx.mir.local_decls[local]; diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index dad87ed65a7d4..7c75fb59917c0 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -9,43 +9,113 @@ // except according to those terms. use rustc::mir::visit::{PlaceContext, Visitor}; -use rustc::mir::{Local, Location, Place}; +use rustc::mir::{BasicBlock, Local, Location, Place, Statement, StatementKind, TerminatorKind}; use rustc_data_structures::fx::FxHashSet; use borrow_check::MirBorrowckCtxt; impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - /// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable - /// local variables lint, to update the context's `used_mut` in a single walk. - crate fn gather_used_muts(&mut self, locals: FxHashSet) { - let mut visitor = GatherUsedMutsVisitor { - needles: locals, - mbcx: self, - }; - visitor.visit_mir(visitor.mbcx.mir); + /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes + /// of the `unused_mut` lint. + /// + /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and + /// used from borrow checking. This function looks for assignments into these locals from + /// user-declared locals and adds those user-defined locals to the `used_mut` set. This can + /// occur due to a rare case involving upvars in closures. + /// + /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals + /// (not arguments) that have not already been marked as being used. + /// This function then looks for assignments from statements or the terminator into the locals + /// from this set and removes them from the set. This leaves only those locals that have not + /// been assigned to - this set is used as a proxy for locals that were not initialized due to + /// unreachable code. These locals are then considered "used" to silence the lint for them. + /// See #55344 for context. + crate fn gather_used_muts( + &mut self, + temporary_used_locals: FxHashSet, + mut never_initialized_mut_locals: FxHashSet, + ) { + { + let mut visitor = GatherUsedMutsVisitor { + temporary_used_locals, + never_initialized_mut_locals: &mut never_initialized_mut_locals, + mbcx: self, + }; + visitor.visit_mir(visitor.mbcx.mir); + } + + // Take the union of the existed `used_mut` set with those variables we've found were + // never initialized. + debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals); + self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect(); } } -/// MIR visitor gathering the assignments to a set of locals, in a single walk. -/// 'visit = the duration of the MIR walk +/// MIR visitor for collecting used mutable variables. +/// The 'visit lifetime represents the duration of the MIR walk. struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> { - needles: FxHashSet, + temporary_used_locals: FxHashSet, + never_initialized_mut_locals: &'visit mut FxHashSet, mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, } impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> { + fn visit_terminator_kind( + &mut self, + _block: BasicBlock, + kind: &TerminatorKind<'tcx>, + _location: Location, + ) { + debug!("visit_terminator_kind: kind={:?}", kind); + match &kind { + TerminatorKind::Call { destination: Some((into, _)), .. } => { + if let Some(local) = into.base_local() { + debug!( + "visit_terminator_kind: kind={:?} local={:?} \ + never_initialized_mut_locals={:?}", + kind, local, self.never_initialized_mut_locals + ); + let _ = self.never_initialized_mut_locals.remove(&local); + } + }, + _ => {}, + } + } + + fn visit_statement( + &mut self, + _block: BasicBlock, + statement: &Statement<'tcx>, + _location: Location, + ) { + match &statement.kind { + StatementKind::Assign(into, _) => { + // Remove any locals that we found were initialized from the + // `never_initialized_mut_locals` set. At the end, the only remaining locals will + // be those that were never initialized - we will consider those as being used as + // they will either have been removed by unreachable code optimizations; or linted + // as unused variables. + if let Some(local) = into.base_local() { + debug!( + "visit_statement: statement={:?} local={:?} \ + never_initialized_mut_locals={:?}", + statement, local, self.never_initialized_mut_locals + ); + let _ = self.never_initialized_mut_locals.remove(&local); + } + }, + _ => {}, + } + } + fn visit_local( &mut self, local: &Local, place_context: PlaceContext<'tcx>, location: Location, ) { - if !self.needles.contains(local) { - return; - } - - if place_context.is_place_assignment() { + if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) { // Propagate the Local assigned at this Location as a used mutable local variable for moi in &self.mbcx.move_data.loc_map[location] { let mpi = &self.mbcx.move_data.moves[*moi].path; diff --git a/src/test/ui/nll/issue-55344.rs b/src/test/ui/nll/issue-55344.rs new file mode 100644 index 0000000000000..131c979a24b7d --- /dev/null +++ b/src/test/ui/nll/issue-55344.rs @@ -0,0 +1,26 @@ +// 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-pass + +#![feature(nll)] +#![allow(unreachable_code)] +#![deny(unused_mut)] + +pub fn foo() { + return; + + let mut v = 0; + assert_eq!(v, 0); + v = 1; + assert_eq!(v, 1); +} + +fn main() {} From 34ffbdb965dd84c6eb6309cacc1f44d6304fdd17 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 7 Nov 2018 16:33:41 +0100 Subject: [PATCH 12/19] This test will not link on wasm32. --- src/test/ui/extern/extern-const.fixed | 6 +++--- src/test/ui/extern/extern-const.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/extern/extern-const.fixed b/src/test/ui/extern/extern-const.fixed index 0229362cf0eca..dca5698a70c20 100644 --- a/src/test/ui/extern/extern-const.fixed +++ b/src/test/ui/extern/extern-const.fixed @@ -1,11 +1,11 @@ -// This test is checking that extern items cannot be const. It also -// checks that `rustfix` suggests the alternative of using an extern -// static. +// Check extern items cannot be const + `rustfix` suggests using +// extern static. // // #54388: an unused reference to an undefined static may or may not // compile. To sidestep this by using one that *is* defined. // run-rustfix +// ignore-wasm32 no external library to link to. // compile-flags: -g -Z continue-parse-after-error #![feature(libc)] extern crate libc; diff --git a/src/test/ui/extern/extern-const.rs b/src/test/ui/extern/extern-const.rs index e7b1715255532..07dbe545a850a 100644 --- a/src/test/ui/extern/extern-const.rs +++ b/src/test/ui/extern/extern-const.rs @@ -1,11 +1,11 @@ -// This test is checking that extern items cannot be const. It also -// checks that `rustfix` suggests the alternative of using an extern -// static. +// Check extern items cannot be const + `rustfix` suggests using +// extern static. // // #54388: an unused reference to an undefined static may or may not // compile. To sidestep this by using one that *is* defined. // run-rustfix +// ignore-wasm32 no external library to link to. // compile-flags: -g -Z continue-parse-after-error #![feature(libc)] extern crate libc; From 5159b32997c92323ac7dd746b6898c1e96e7078c Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 7 Nov 2018 17:00:51 +0100 Subject: [PATCH 13/19] mir: remove a hacky recursive helper function --- src/librustc_mir/transform/promote_consts.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index e79da88a2464b..c5add6260789a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -310,16 +310,11 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { match statement.kind { StatementKind::Assign(_, box Rvalue::Ref(_, _, ref mut place)) => { // Find the underlying local for this (necessarily interior) borrow. - // HACK(eddyb) using a recursive function because of mutable borrows. - fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>) - -> &'a mut Place<'tcx> { - if let Place::Projection(ref mut proj) = *place { - assert_ne!(proj.elem, ProjectionElem::Deref); - return interior_base(&mut proj.base); - } - place - } - let place = interior_base(place); + let mut place = place; + while let Place::Projection(ref mut proj) = *place { + assert_ne!(proj.elem, ProjectionElem::Deref); + place = &mut proj.base; + }; let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx); let span = statement.source_info.span; From 36f815bf8da2b05ef8919711223a23d849beeb3f Mon Sep 17 00:00:00 2001 From: Jon Gjengset Date: Wed, 7 Nov 2018 11:02:08 -0500 Subject: [PATCH 14/19] Remove intermediate font specs This is a (much) more constrained version of #54772 that also aims at improving the situation in #34681. It removes any font specifications that are not the "official" rustdoc font, and instead relies on the browser to provide the fallback font if the official on is not available. On Linux systems, this is particularly important, as fonts like Helvetica, Arial, and Times often look pretty bad since they're pulled from extracted MS fonts. A specification like `serif` or `sans-serif` lets the browser instead choose a good font. --- src/librustdoc/html/static/rustdoc.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8f679b4d22b25..1ae3b0b88c6dd 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -70,7 +70,7 @@ /* General structure and fonts */ body { - font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif; + font: 16px/1.4 "Source Serif Pro", serif; margin: 0; position: relative; padding: 10px 15px 20px 15px; @@ -114,7 +114,7 @@ h3.impl, h3.method, h3.type { h1, h2, h3, h4, .sidebar, a.source, .search-input, .content table :not(code)>a, .collapse-toggle, div.item-list .out-of-band { - font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Fira Sans", sans-serif; } ol, ul { @@ -133,7 +133,7 @@ summary { } code, pre { - font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; + font-family: "Source Code Pro", monospace; white-space: pre-wrap; } .docblock code, .docblock-short code { @@ -415,7 +415,7 @@ h4 > code, h3 > code, .invisible > code { } #main > .since { top: inherit; - font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Fira Sans", sans-serif; } .content table:not(.table-display) { @@ -1338,7 +1338,7 @@ h3.important { kbd { display: inline-block; padding: 3px 5px; - font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + font: 15px monospace; line-height: 10px; vertical-align: middle; border: solid 1px; From a9b598884719cccdcf699567cece2a6ac46fc84c Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Thu, 8 Nov 2018 02:56:25 +0100 Subject: [PATCH 15/19] wasm32-unknown-emscripten expects the rust_eh_personality symbol The `wasm32-unknown-emscripten` expects the `rust_eh_personality` symbol to be there, but a cfg checking for `target_arch = "wasm32"` which was meant to remove the symbol from the `wasm32-unknown-unknown` target, didn't check for whether `emscripten` is targeted or not, so the symbol accidentally got filtered out there as well. Fixes #55276 --- src/libpanic_abort/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index b86928534cb24..9235f8e7660a1 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -97,7 +97,10 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { pub mod personalities { #[no_mangle] #[cfg(not(any( - target_arch = "wasm32", + all( + target_arch = "wasm32", + not(target_os = "emscripten"), + ), all( target_os = "windows", target_env = "gnu", From 706c2ad651c1b2db95aeb4efc9acf5d0b42d5640 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Nov 2018 15:55:52 +1100 Subject: [PATCH 16/19] Use `Lit` rather than `P` in `ast::ExprKind`. Because it results in fewer allocations and small speedups on some benchmarks. --- src/librustc/hir/lowering.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/ext/quote.rs | 4 ++-- src/libsyntax/parse/parser.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e558d94551671..dd5d4b8f6afff 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3705,7 +3705,7 @@ impl<'a> LoweringContext<'a> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((**l).clone())), + ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((*l).clone())), ExprKind::Cast(ref expr, ref ty) => { let expr = P(self.lower_expr(expr)); hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index cfedda18a7e22..2f17bc0548cad 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1086,7 +1086,7 @@ pub enum ExprKind { /// A unary operation (For example: `!x`, `*x`) Unary(UnOp, P), /// A literal (For example: `1`, `"foo"`) - Lit(P), + Lit(Lit), /// A cast (`foo as f64`) Cast(P, P), Type(P, P), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1701c8da2c5bd..88ee80e60888f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -491,7 +491,7 @@ impl DummyResult { pub fn raw_expr(sp: Span) -> P { P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Lit(P(source_map::respan(sp, ast::LitKind::Bool(false)))), + node: ast::ExprKind::Lit(source_map::respan(sp, ast::LitKind::Bool(false))), span: sp, attrs: ThinVec::new(), }) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7928ec1606b1d..cacec867cf198 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -695,7 +695,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P { - self.expr(sp, ast::ExprKind::Lit(P(respan(sp, lit)))) + self.expr(sp, ast::ExprKind::Lit(respan(sp, lit))) } fn expr_usize(&self, span: Span, i: usize) -> P { self.expr_lit(span, ast::LitKind::Int(i as u128, diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 62bc9fae3b59a..ebc618a4c3cb3 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -274,7 +274,7 @@ pub mod rt { // FIXME: This is wrong P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Lit(P(self.clone())), + node: ast::ExprKind::Lit(self.clone()), span: DUMMY_SP, attrs: ThinVec::new(), }).to_tokens(cx) @@ -305,7 +305,7 @@ pub mod rt { let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag)); let lit = P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Lit(P(dummy_spanned(lit))), + node: ast::ExprKind::Lit(dummy_spanned(lit)), span: DUMMY_SP, attrs: ThinVec::new(), }); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c453b4b5597ff..ae5c936a70d72 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1957,7 +1957,7 @@ impl<'a> Parser<'a> { let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); let lo = self.span; - let literal = P(self.parse_lit()?); + let literal = self.parse_lit()?; let hi = self.prev_span; let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); From e3390d89ea7a58a35d3aca62247e2a5d3c327181 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 7 Nov 2018 15:38:06 +0100 Subject: [PATCH 17/19] Improve creation of 3 IndexVecs --- src/librustc/ty/query/on_disk_cache.rs | 3 +-- src/librustc_mir/shim.rs | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 3dc31c517169f..54550b8a2055f 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -450,8 +450,7 @@ impl<'sess> OnDiskCache<'sess> { .map(|&(cnum, ..)| cnum) .max() .unwrap_or(0) + 1; - let mut map = IndexVec::new(); - map.resize(map_size as usize, None); + let mut map = IndexVec::from_elem_n(None, map_size as usize); for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { let key = (crate_name.clone(), crate_disambiguator); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 76a8501fb177a..54983b8f4e026 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -196,7 +196,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; let return_block = BasicBlock::new(1); - let mut blocks = IndexVec::new(); + let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { blocks.push(BasicBlockData { statements: vec![], @@ -768,7 +768,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })); } - let mut blocks = IndexVec::new(); + let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 }; + let mut blocks = IndexVec::with_capacity(n_blocks); let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { blocks.push(BasicBlockData { statements, From 255cc1aed33442567c29c95fa445a534575e925c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 8 Nov 2018 07:49:28 -0800 Subject: [PATCH 18/19] rustc: Request ansi colors if stderr isn't a tty Currently Cargo will always capture the output of rustc meaning that rustc is never hooked up to a tty. To retain colors Cargo uses the `fwdansi` crate to ensure that ansi color codes are translated to windows terminal methods (and ansi codes otherwise just go their natural route on Unix). Cargo passes `--color always` to rustc to ensure that using a pipe doesn't trick it into not emitting colors at all. It turns out, however, that `--color always` ends up still accidentally using the native shell api on native windows shells. The fix here is to instead pass `AlwaysAnsi` to `termcolor` instead of `Always`, ensuring that when `--color always` is passed to rustc and its output isn't a terminal, we're always generating ansi colors regardless of the platform. Closes #55769 --- src/librustc_errors/emitter.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 720e8def5ab1c..7e69e98071d4b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -108,7 +108,13 @@ pub enum ColorConfig { impl ColorConfig { fn to_color_choice(&self) -> ColorChoice { match *self { - ColorConfig::Always => ColorChoice::Always, + ColorConfig::Always => { + if atty::is(atty::Stream::Stderr) { + ColorChoice::Always + } else { + ColorChoice::AlwaysAnsi + } + } ColorConfig::Never => ColorChoice::Never, ColorConfig::Auto if atty::is(atty::Stream::Stderr) => { ColorChoice::Auto From d75dae306989369760eb20860a8a72eb4d15a18b Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 14:20:45 +0100 Subject: [PATCH 19/19] Deprecate channel selection --- src/libstd/macros.rs | 2 ++ src/libstd/sync/mpsc/mod.rs | 1 + src/libstd/sync/mpsc/select.rs | 7 +++---- src/test/run-pass/issues/issue-13494.rs | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 34bbbb53d5ff1..96c92ceb5bb41 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -399,6 +399,8 @@ macro_rules! await { /// For more information about select, see the `std::sync::mpsc::Select` structure. #[macro_export] #[unstable(feature = "mpsc_select", issue = "27800")] +#[rustc_deprecated(since = "1.32.0", + reason = "channel selection will be removed in a future release")] macro_rules! select { ( $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 81f98a55c1171..059ced4f56efd 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -124,6 +124,7 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] +#![allow(deprecated)] // for mpsc_select // A description of how Rust's channel implementation works // diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index a7a284cfb7994..2ec4b52dbf3cb 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -51,11 +51,10 @@ #![unstable(feature = "mpsc_select", reason = "This implementation, while likely sufficient, is unsafe and \ likely to be error prone. At some point in the future this \ - module will likely be replaced, and it is currently \ - unknown how much API breakage that will cause. The ability \ - to select over a number of channels will remain forever, \ - but no guarantees beyond this are being made", + module will be removed.", issue = "27800")] +#![rustc_deprecated(since = "1.32.0", + reason = "channel selection will be removed in a future release")] use fmt; diff --git a/src/test/run-pass/issues/issue-13494.rs b/src/test/run-pass/issues/issue-13494.rs index 0750a4c895936..a31ad72b0881a 100644 --- a/src/test/run-pass/issues/issue-13494.rs +++ b/src/test/run-pass/issues/issue-13494.rs @@ -16,6 +16,7 @@ // expose is still present. #![feature(mpsc_select)] +#![allow(deprecated)] use std::sync::mpsc::{channel, Sender, Receiver}; use std::thread;