From 4574a70e84bb68301b4ce23326ddb2f3d43474ee Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 11 May 2018 11:26:51 +0200 Subject: [PATCH 1/6] Introduce OperandValue::volatile_store and use it in the intrinsics Fixes #50371. --- src/librustc_trans/abi.rs | 3 ++- src/librustc_trans/base.rs | 10 ++++++---- src/librustc_trans/builder.rs | 3 ++- src/librustc_trans/intrinsic.rs | 21 +++------------------ src/librustc_trans/mir/block.rs | 2 +- src/librustc_trans/mir/operand.rs | 24 +++++++++++++++++++++--- 6 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1838dae049ad7..c80d989e3cb18 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -220,7 +220,8 @@ impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { bx.pointercast(dst.llval, Type::i8p(cx)), bx.pointercast(llscratch, Type::i8p(cx)), C_usize(cx, self.layout.size.bytes()), - self.layout.align.min(scratch_align)); + self.layout.align.min(scratch_align), + false); bx.lifetime_end(llscratch, scratch_size); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b756a6695f941..ae54a6d49ba4a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -320,7 +320,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, 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)); + src_f.align.min(dst_f.align), false); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -408,7 +408,8 @@ pub fn call_memcpy(bx: &Builder, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, - align: Align) { + align: Align, + volatile: bool) { let cx = bx.cx; let ptr_width = &cx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); @@ -417,7 +418,7 @@ pub fn call_memcpy(bx: &Builder, 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, false); + let volatile = C_bool(cx, volatile); bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } @@ -427,13 +428,14 @@ pub fn memcpy_ty<'a, 'tcx>( src: ValueRef, layout: TyLayout<'tcx>, align: Align, + volatile: bool, ) { let size = layout.size.bytes(); if size == 0 { return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align); + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, volatile); } pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index db803ca8209d9..49bcf9b88a065 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -590,13 +590,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { + pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); assert!(!self.llbuilder.is_null()); self.count_insn("store.volatile"); let ptr = self.check_store(val, ptr); unsafe { let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); + llvm::LLVMSetAlignment(insn, align.abi() as c_uint); llvm::LLVMSetVolatile(insn, llvm::True); insn } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 49a207a2d8ab5..65e211ae740bc 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -247,26 +247,11 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, to_immediate(bx, load, cx.layout_of(tp_ty)) }, "volatile_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - if let OperandValue::Pair(a, b) = args[1].val { - bx.volatile_store(a, dst.project_field(bx, 0).llval); - bx.volatile_store(b, dst.project_field(bx, 1).llval); - } else { - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - if dst.layout.is_zst() { - return; - } - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.volatile_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } + if dst.layout.is_zst() { + return; } + args[1].val.volatile_store(bx, dst); return; }, "prefetch_read_data" | "prefetch_write_data" | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index b666c2b211525..df8807c318b17 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -626,7 +626,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, false); (scratch.llval, scratch.align, true) } else { (llval, align, true) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 9d34f73ed2298..6dc6c700fbd68 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -278,6 +278,14 @@ impl<'a, 'tcx> OperandRef<'tcx> { impl<'a, 'tcx> OperandValue { pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_maybe_volatile(bx, dest, false); + } + + pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_maybe_volatile(bx, dest, true); + } + + fn store_maybe_volatile(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, volatile: bool) { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`, and store itself is useless. @@ -287,9 +295,14 @@ impl<'a, 'tcx> OperandValue { match self { OperandValue::Ref(r, source_align) => base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align)), + source_align.min(dest.align), volatile), OperandValue::Immediate(s) => { - bx.store(base::from_immediate(bx, s), dest.llval, dest.align); + let val = base::from_immediate(bx, s); + if !volatile { + bx.store(val, dest.llval, dest.align); + } else { + bx.volatile_store(val, dest.llval, dest.align); + } } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { @@ -298,7 +311,12 @@ impl<'a, 'tcx> OperandValue { if common::val_ty(x) == Type::i1(bx.cx) { llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); } - bx.store(base::from_immediate(bx, x), llptr, dest.align); + let val = base::from_immediate(bx, x); + if !volatile { + bx.store(val, llptr, dest.align); + } else { + bx.volatile_store(val, llptr, dest.align); + } } } } From 352f32bb00d3e7f1b870083303af801cf79da0f3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 11 May 2018 12:26:32 +0200 Subject: [PATCH 2/6] Introduce OperandValue::nontemporal_store and use it in the intrinsics We use a new MemFlags bitflags type to merge some store code paths. --- src/Cargo.lock | 1 + src/librustc_trans/Cargo.toml | 1 + src/librustc_trans/abi.rs | 4 +- src/librustc_trans/base.rs | 19 ++++++--- src/librustc_trans/builder.rs | 67 ++++++++++++++----------------- src/librustc_trans/intrinsic.rs | 17 +------- src/librustc_trans/lib.rs | 1 + src/librustc_trans/mir/block.rs | 4 +- src/librustc_trans/mir/operand.rs | 29 ++++++------- 9 files changed, 65 insertions(+), 78 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index bcebd5c3f16c5..ea2d146ff624f 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2169,6 +2169,7 @@ dependencies = [ name = "rustc_trans" version = "0.0.0" dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index a4dd02e97b233..64d3a4f4d53be 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] +bitflags = "1.0.1" cc = "1.0.1" flate2 = "1.0" jobserver = "0.1.5" diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c80d989e3cb18..25c598c532c48 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, AttributePlace}; use base; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{ty_fn_sig, C_usize}; use context::CodegenCx; use mir::place::PlaceRef; @@ -221,7 +221,7 @@ impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { bx.pointercast(llscratch, Type::i8p(cx)), C_usize(cx, self.layout.size.bytes()), self.layout.align.min(scratch_align), - false); + MemFlags::empty()); bx.lifetime_end(llscratch, scratch_size); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ae54a6d49ba4a..118510d17d779 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -53,7 +53,7 @@ use rustc_incremental; use allocator; use mir::place::PlaceRef; use attributes; -use builder::Builder; +use builder::{Builder, MemFlags}; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; @@ -320,7 +320,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, 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), false); + src_f.align.min(dst_f.align), MemFlags::empty()); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -409,7 +409,14 @@ pub fn call_memcpy(bx: &Builder, src: ValueRef, n_bytes: ValueRef, align: Align, - volatile: bool) { + 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 ptr = bx.pointercast(dst, val_ty(val).ptr_to()); + bx.store_with_flags(val, ptr, 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); @@ -418,7 +425,7 @@ pub fn call_memcpy(bx: &Builder, 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, volatile); + let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } @@ -428,14 +435,14 @@ pub fn memcpy_ty<'a, 'tcx>( src: ValueRef, layout: TyLayout<'tcx>, align: Align, - volatile: bool, + flags: MemFlags, ) { let size = layout.size.bytes(); if size == 0 { return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, volatile); + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); } pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 49bcf9b88a065..4153c61e5269a 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -50,6 +50,13 @@ fn noname() -> *const c_char { &CNULL } +bitflags! { + pub struct MemFlags: u8 { + const VOLATILE = 1 << 0; + const NONTEMPORAL = 1 << 1; + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self { let bx = Builder::with_cx(cx); @@ -579,30 +586,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + pub fn store_with_flags( + &self, + val: ValueRef, + ptr: ValueRef, + align: Align, + flags: MemFlags, + ) -> ValueRef { + debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags); assert!(!self.llbuilder.is_null()); self.count_insn("store"); let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); llvm::LLVMSetAlignment(store, align.abi() as c_uint); + if flags.contains(MemFlags::VOLATILE) { + llvm::LLVMSetVolatile(store, llvm::True); + } + if flags.contains(MemFlags::NONTEMPORAL) { + // According to LLVM [1] building a nontemporal store must + // *always* point to a metadata value of the integer 1. + // + // [1]: http://llvm.org/docs/LangRef.html#store-instruction + let one = C_i32(self.cx, 1); + let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); + llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); + } store } } - pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.volatile"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetAlignment(insn, align.abi() as c_uint); - llvm::LLVMSetVolatile(insn, llvm::True); - insn - } - } - pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering, align: Align) { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); @@ -616,29 +632,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.nontemporal"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - - // According to LLVM [1] building a nontemporal store must *always* - // point to a metadata value of the integer 1. Who knew? - // - // [1]: http://llvm.org/docs/LangRef.html#store-instruction - let one = C_i32(self.cx, 1); - let node = llvm::LLVMMDNodeInContext(self.cx.llcx, - &one, - 1); - llvm::LLVMSetMetadata(insn, - llvm::MD_nontemporal as c_uint, - node); - insn - } - } - pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { self.count_insn("gep"); unsafe { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 65e211ae740bc..86aa48b6a9e48 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -248,9 +248,6 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, }, "volatile_store" => { let dst = args[0].deref(bx.cx); - if dst.layout.is_zst() { - return; - } args[1].val.volatile_store(bx, dst); return; }, @@ -536,19 +533,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } "nontemporal_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.nontemporal_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } - return + args[1].val.nontemporal_store(bx, dst); + return; } _ => { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 7a152d6ded4c5..537dfc61b2a4f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -34,6 +34,7 @@ use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; +#[macro_use] extern crate bitflags; extern crate flate2; extern crate libc; #[macro_use] extern crate rustc; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index df8807c318b17..e4989da36c026 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -17,7 +17,7 @@ use rustc::mir::interpret::EvalErrorKind; use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; use consts; use meth; @@ -626,7 +626,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, false); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); (scratch.llval, scratch.align, true) } else { (llval, align, true) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 6dc6c700fbd68..a9870be9e54d2 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::Idx; use base; use common::{self, CodegenCx, C_null, C_undef, C_usize}; -use builder::Builder; +use builder::{Builder, MemFlags}; use value::Value; use type_of::LayoutLlvmExt; use type_::Type; @@ -278,14 +278,18 @@ impl<'a, 'tcx> OperandRef<'tcx> { impl<'a, 'tcx> OperandValue { pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_maybe_volatile(bx, dest, false); + self.store_with_flags(bx, dest, MemFlags::empty()); } pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { - self.store_maybe_volatile(bx, dest, true); + self.store_with_flags(bx, dest, MemFlags::VOLATILE); } - fn store_maybe_volatile(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, volatile: bool) { + pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); + } + + fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) { debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`, and store itself is useless. @@ -293,16 +297,13 @@ impl<'a, 'tcx> OperandValue { return; } match self { - OperandValue::Ref(r, source_align) => + OperandValue::Ref(r, source_align) => { base::memcpy_ty(bx, dest.llval, r, dest.layout, - source_align.min(dest.align), volatile), + source_align.min(dest.align), flags) + } OperandValue::Immediate(s) => { let val = base::from_immediate(bx, s); - if !volatile { - bx.store(val, dest.llval, dest.align); - } else { - bx.volatile_store(val, dest.llval, dest.align); - } + bx.store_with_flags(val, dest.llval, dest.align, flags); } OperandValue::Pair(a, b) => { for (i, &x) in [a, b].iter().enumerate() { @@ -312,11 +313,7 @@ impl<'a, 'tcx> OperandValue { llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); } let val = base::from_immediate(bx, x); - if !volatile { - bx.store(val, llptr, dest.align); - } else { - bx.volatile_store(val, llptr, dest.align); - } + bx.store_with_flags(val, llptr, dest.align, flags); } } } From fea0fd7f97604b87b0468d06c85dccc86d1b5bb7 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Sat, 12 May 2018 19:04:44 +0000 Subject: [PATCH 3/6] typeck: Save the index of private fields Save the index of all fields regardless of their visibility. Problems could occur later when attempting to index fields in error recovery if they are not inserted. --- src/librustc_typeck/check/mod.rs | 4 ++- .../proc-macro/auxiliary/issue_50493.rs | 32 +++++++++++++++++++ .../proc-macro/issue-50493.rs | 27 ++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs create mode 100644 src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 073b0047f4ecf..044509c868840 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3078,12 +3078,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) { let field = &fields[index]; let field_ty = self.field_ty(expr.span, field, substs); + // Save the index of all fields regardless of their visibility in case + // of error recovery. + self.write_field_index(expr.id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { let adjustments = autoderef.adjust_steps(needs); self.apply_adjustments(base, adjustments); autoderef.finalize(); - self.write_field_index(expr.id, index); self.tcx.check_stability(field.did, Some(expr.id), expr.span); return field_ty; } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs new file mode 100644 index 0000000000000..7d36517d9704b --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue_50493.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(proc_macro, proc_macro_lib)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(Derive)] +pub fn derive(_: TokenStream) -> TokenStream { + let code = " + fn one(r: Restricted) { + r.field; + } + fn two(r: Restricted) { + r.field; + } + "; + + code.parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs new file mode 100644 index 0000000000000..51112f202c897 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-50493.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue_50493.rs +// ignore-stage1 + +#![feature(proc_macro)] + +#[macro_use] +extern crate issue_50493; + +#[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private +struct Restricted { + pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules +} + +mod restricted {} + +fn main() {} + From 2ee251b58ba5be01306a15006ba59132f178b03b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 14 May 2018 12:23:12 +0300 Subject: [PATCH 4/6] rustc: don't trip an assertion for enums with present but uninhabited variants. --- src/librustc/ty/layout.rs | 5 +++++ src/test/run-pass/issue-50731.rs | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/run-pass/issue-50731.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 2171b9a6c52b7..c13e43877bbcd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -888,6 +888,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if x < min { min = x; } if x > max { max = x; } } + // We might have no inhabited variants, so pretend there's at least one. + if (min, max) == (i128::max_value(), i128::min_value()) { + min = 0; + max = 0; + } assert!(min <= max, "discriminant range is {}...{}", min, max); let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); diff --git a/src/test/run-pass/issue-50731.rs b/src/test/run-pass/issue-50731.rs new file mode 100644 index 0000000000000..06df2b989af28 --- /dev/null +++ b/src/test/run-pass/issue-50731.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Void {} +fn foo(_: Result<(Void, u32), (Void, String)>) {} +fn main() { + let _: fn(_) = foo; +} From 4a2313b568efe29bac7fb1d659b5b1cc92d09ccd Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Mon, 14 May 2018 12:32:04 -0400 Subject: [PATCH 5/6] Update stdsimd module to include https://github.com/rust-lang-nursery/stdsimd/commit/a19ca1cd91cf97777af8268a6136bd2e4648e189 --- src/stdsimd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdsimd b/src/stdsimd index 2f86c75a2479c..a19ca1cd91cf9 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1 +Subproject commit a19ca1cd91cf97777af8268a6136bd2e4648e189 From eee8802ceb24eee99394e629bac5883b67da7fa5 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 12 May 2018 16:43:42 -0300 Subject: [PATCH 6/6] Fix self referential impl Trait substitutions A high impact bug because a lot of common traits use a `Self` substitution by default. Should be backported to beta. There was a check for this which wasn't catching all cases, it was made more robust. Fixes #49376 Fixes #50626 r? @petrochenkov --- src/librustc_privacy/lib.rs | 15 +++++++++-- src/test/run-pass/impl-trait/issue-49376.rs | 29 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/impl-trait/issue-49376.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ee08e6223903e..42031d9cc5630 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -30,6 +30,7 @@ use rustc::middle::privacy::{AccessLevel, AccessLevels}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::maps::Providers; +use rustc::ty::subst::UnpackedKind; use rustc::util::nodemap::NodeSet; use syntax::ast::{self, CRATE_NODE_ID, Ident}; use syntax::symbol::keywords; @@ -37,6 +38,7 @@ use syntax_pos::Span; use std::cmp; use std::mem::replace; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; mod diagnostics; @@ -624,6 +626,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> { in_body: bool, span: Span, empty_tables: &'a ty::TypeckTables<'tcx>, + visited_anon_tys: FxHashSet } impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { @@ -943,8 +946,15 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { self.tcx.sess.span_err(self.span, &msg); return true; } - // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion - for subst in trait_ref.substs.iter().skip(1) { + for subst in trait_ref.substs.iter() { + // Skip repeated `TyAnon`s to avoid infinite recursion. + if let UnpackedKind::Type(ty) = subst.unpack() { + if let ty::TyAnon(def_id, ..) = ty.sty { + if !self.visited_anon_tys.insert(def_id) { + continue; + } + } + } if subst.visit_with(self) { return true; } @@ -1677,6 +1687,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, in_body: false, span: krate.span, empty_tables: &empty_tables, + visited_anon_tys: FxHashSet() }; intravisit::walk_crate(&mut visitor, krate); diff --git a/src/test/run-pass/impl-trait/issue-49376.rs b/src/test/run-pass/impl-trait/issue-49376.rs new file mode 100644 index 0000000000000..b687b485fce21 --- /dev/null +++ b/src/test/run-pass/impl-trait/issue-49376.rs @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests for nested self-reference which caused a stack overflow. + +use std::fmt::Debug; +use std::ops::*; + +fn gen() -> impl PartialOrd + PartialEq + Debug { } + +struct Bar {} +trait Foo {} +impl Foo for Bar {} + +fn foo() -> impl Foo { + Bar {} +} + +fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 } +fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 } + +fn main() {}