From 11426a4d502cac062773071cf7fd320a383564ff Mon Sep 17 00:00:00 2001 From: Saleem Jaffer Date: Fri, 10 May 2019 10:19:58 +0530 Subject: [PATCH 01/45] refactor some `FnType` stuff to `rustc::ty::layout` --- src/librustc/ty/layout.rs | 349 +++++++++++++++++++++++++++++++ src/librustc_codegen_llvm/abi.rs | 291 -------------------------- 2 files changed, 349 insertions(+), 291 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index d1a8a9a34e155..58d27d4c5dbe4 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; pub use rustc_target::abi::*; +use rustc_target::spec::HasTargetSpec; +use rustc_target::abi::call::{ + ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode +}; + + pub trait IntegerExt { fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>; @@ -2259,3 +2265,346 @@ impl<'a, 'gcx> HashStable> for LayoutError<'gcx> } } } + +pub trait FnTypeExt<'tcx, C> { + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>; + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>; + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>; + fn new_internal( + cx: &C, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>; +} + + +impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + { + let sig = instance.fn_sig(cx.tcx()); + let sig = cx + .tcx() + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + call::FnType::new(cx, sig, &[]) + } + + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + { + call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty))) + } + + + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + { + FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { + let mut layout = cx.layout_of(ty); + // Don't pass the vtable, it's not an argument of the virtual fn. + // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` + // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen + if arg_idx == Some(0) { + let fat_pointer_ty = if layout.is_unsized() { + // unsized `self` is passed as a pointer to `self` + // FIXME (mikeyhew) change this to use &own if it is ever added to the language + cx.tcx().mk_mut_ptr(layout.ty) + } else { + match layout.abi { + Abi::ScalarPair(..) => (), + _ => bug!("receiver type has unsupported layout: {:?}", layout), + } + + // In the case of Rc, we need to explicitly pass a *mut RcBox + // with a Scalar (not ScalarPair) ABI. This is a hack that is understood + // elsewhere in the compiler as a method on a `dyn Trait`. + // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we + // get a built-in pointer type + let mut fat_pointer_layout = layout; + 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() + && !fat_pointer_layout.ty.is_region_ptr() + { + 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { + let field_layout = fat_pointer_layout.field(cx, i); + + if !field_layout.is_zst() { + fat_pointer_layout = field_layout; + continue 'descend_newtypes; + } + } + + bug!( + "receiver has no non-zero-sized fields {:?}", + fat_pointer_layout + ); + } + + fat_pointer_layout.ty + }; + + // we now have a type like `*mut RcBox` + // change its layout to that of `*mut ()`, a thin pointer, but keep the same type + // this is understood as a special case elsewhere in the compiler + let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit()); + layout = cx.layout_of(unit_pointer_ty); + layout.ty = fat_pointer_ty; + } + ArgType::new(layout) + }) + } + + fn new_internal( + cx: &C, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self + where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + { + debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); + + use rustc_target::spec::abi::Abi::*; + let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C, + + // It's the ABI's job to select this, not ours. + System => bug!("system abi should be selected elsewhere"), + + Stdcall => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall => Conv::X86ThisCall, + C => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, + AmdGpuKernel => Conv::AmdGpuKernel, + + // These API constants ought to be more specific... + Cdecl => Conv::C, + }; + + let mut inputs = sig.inputs(); + let extra_args = if sig.abi == RustCall { + assert!(!sig.c_variadic && extra_args.is_empty()); + + match sig.inputs().last().unwrap().sty { + ty::Tuple(tupled_arguments) => { + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; + tupled_arguments.iter().map(|k| k.expect_ty()).collect() + } + _ => { + bug!( + "argument to function with \"rust-call\" ABI \ + is not a tuple" + ); + } + } + } else { + assert!(sig.c_variadic || extra_args.is_empty()); + extra_args.to_vec() + }; + + let target = &cx.tcx().sess.target.target; + let win_x64_gnu = + target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; + let linux_s390x = + target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu"; + let linux_sparc64 = + target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; + let rust_abi = match sig.abi { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, + _ => false, + }; + + // Handle safe Rust thin and fat pointers. + let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, + scalar: &Scalar, + layout: TyLayout<'tcx>, + offset: Size, + is_return: bool| { + // Booleans are always an i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.set(ArgAttribute::ZExt); + return; + } + + // Only pointer types handled below. + if scalar.value != Pointer { + return; + } + + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { + attrs.set(ArgAttribute::NonNull); + } + } + + if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_size = pointee.size; + attrs.pointee_align = Some(pointee.align); + + // `Box` pointer parameters never alias because ownership is transferred + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + let no_alias = match kind { + PointerKind::Shared => false, + PointerKind::UniqueOwned => true, + PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return, + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + } + } + }; + + // Store the index of the last argument. This is useful for working with + // C-compatible variadic arguments. + let last_arg_idx = if sig.inputs().is_empty() { + None + } else { + Some(sig.inputs().len() - 1) + }; + + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { + let is_return = arg_idx.is_none(); + let mut arg = mk_arg_type(ty, arg_idx); + if arg.layout.is_zst() { + // For some forsaken reason, x86_64-pc-windows-gnu + // doesn't ignore zero-sized struct arguments. + // The same is true for s390x-unknown-linux-gnu + // and sparc64-unknown-linux-gnu. + if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { + arg.mode = PassMode::Ignore(IgnoreMode::Zst); + } + } + + // If this is a C-variadic function, this is not the return value, + // and there is one or more fixed arguments; ensure that the `VaList` + // is ignored as an argument. + if sig.c_variadic { + match (last_arg_idx, arg_idx) { + (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { + let va_list_did = match cx.tcx().lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), + }; + match ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // This is the "spoofed" `VaList`. Set the arguments mode + // so that it will be ignored. + arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); + } + _ => (), + } + } + _ => {} + } + } + + // FIXME(eddyb) other ABIs don't have logic for scalar pairs. + if !is_return && rust_abi { + if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi { + let mut a_attrs = ArgAttributes::new(); + let mut b_attrs = ArgAttributes::new(); + adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false); + adjust_for_rust_scalar( + &mut b_attrs, + b, + arg.layout, + a.value.size(cx).align_to(b.value.align(cx).abi), + false, + ); + arg.mode = PassMode::Pair(a_attrs, b_attrs); + return arg; + } + } + + if let Abi::Scalar(ref scalar) = arg.layout.abi { + if let PassMode::Direct(ref mut attrs) = arg.mode { + adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return); + } + } + + arg + }; + + let fn_ty = FnType { + ret: arg_of(sig.output(), None), + args: inputs + .iter() + .cloned() + .chain(extra_args) + .enumerate() + .map(|(i, ty)| arg_of(ty, Some(i))) + .collect(), + c_variadic: sig.c_variadic, + conv, + }; + // FIXME: uncomment this after figuring out wwhere should adjust_for_abi reside. + //fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty + } +} diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 70d184240fccd..cf4a523d9caa5 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -295,19 +295,6 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> { } pub trait FnTypeExt<'tcx> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self; - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self; fn adjust_for_abi(&mut self, cx: &CodegenCx<'ll, 'tcx>, abi: Abi); @@ -319,284 +306,6 @@ pub trait FnTypeExt<'tcx> { } impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let sig = instance.fn_sig(cx.tcx); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - FnType::new(cx, sig, &[]) - } - - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, _| { - ArgType::new(cx.layout_of(ty)) - }) - } - - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { - let mut layout = cx.layout_of(ty); - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if arg_idx == Some(0) { - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx.mk_mut_ptr(layout.ty) - } else { - match layout.abi { - LayoutAbi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout) - } - - // In the case of Rc, we need to explicitly pass a *mut RcBox - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - } - ArgType::new(layout) - }) - } - - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self { - debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); - - use self::Abi::*; - let conv = match cx.sess().target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => Conv::C, - - // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), - - Stdcall => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - match sig.inputs().last().unwrap().sty { - ty::Tuple(tupled_arguments) => { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments.iter().map(|k| k.expect_ty()).collect() - } - _ => { - bug!("argument to function with \"rust-call\" ABI \ - is not a tuple"); - } - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args.to_vec() - }; - - let target = &cx.sess().target.target; - let win_x64_gnu = target.target_os == "windows" - && target.arch == "x86_64" - && target.target_env == "gnu"; - let linux_s390x = target.target_os == "linux" - && target.arch == "s390x" - && target.target_env == "gnu"; - let linux_sparc64 = target.target_os == "linux" - && target.arch == "sparc64" - && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &layout::Scalar, - layout: TyLayout<'tcx, Ty<'tcx>>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != layout::Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_size = pointee.size; - attrs.pointee_align = Some(pointee.align); - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | - PointerKind::UniqueBorrowed => !is_return - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - // Store the index of the last argument. This is useful for working with - // C-compatible variadic arguments. - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { - let is_return = arg_idx.is_none(); - let mut arg = mk_arg_type(ty, arg_idx); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore(IgnoreMode::Zst); - } - } - - // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaList` - // is ignored as an argument. - if sig.c_variadic { - match (last_arg_idx, arg_idx) { - (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { - let va_list_did = match cx.tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaList`. Set the arguments mode - // so that it will be ignored. - arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); - }, - _ => (), - } - } - _ => {} - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, - a, - arg.layout, - Size::ZERO, - false); - adjust_for_rust_scalar(&mut b_attrs, - b, - arg.layout, - a.value.size(cx).align_to(b.value.align(cx).abi), - false); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, - scalar, - arg.layout, - Size::ZERO, - is_return); - } - } - - arg - }; - - let mut fn_ty = FnType { - ret: arg_of(sig.output(), None), - args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| { - arg_of(ty, Some(i)) - }).collect(), - c_variadic: sig.c_variadic, - conv, - }; - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty - } - fn adjust_for_abi(&mut self, cx: &CodegenCx<'ll, 'tcx>, abi: Abi) { From 677161e0d94082e9aac1fd76dbe5849837160b58 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 18 Mar 2019 14:21:41 +0100 Subject: [PATCH 02/45] Remove unnecessary secondary recursion --- src/librustc/ty/fold.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index dbf9047f775bf..dae28d51efc2e 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -939,7 +939,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { let flags = FlagComputation::for_const(c); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); - flags.intersects(self.flags) || c.super_visit_with(self) + flags.intersects(self.flags) } } From 35cf77f0911449945ea3d70b1da29895541e9f5a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 26 Mar 2019 17:57:13 +0100 Subject: [PATCH 03/45] Ignore .vscode even if it is a symlink --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 67e0dd8e795bb..d34ed114972c5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ __pycache__/ .project .settings/ .valgrindrc -.vscode/ +.vscode .favorites.json /*-*-*-*/ /*-*-*/ From f223eec8228ae0acf9c45d5bdafdb449f6240944 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 29 Mar 2019 10:52:09 +0100 Subject: [PATCH 04/45] Reuse the pretty printing architecture for printing of constants --- src/librustc/mir/mod.rs | 77 ++++------------------------ src/librustc/ty/print/pretty.rs | 59 ++++++++++++++++++--- src/librustc/ty/structural_impls.rs | 33 ++++++++++++ src/librustc_mir/hair/pattern/mod.rs | 8 +-- src/librustdoc/clean/mod.rs | 3 +- 5 files changed, 100 insertions(+), 80 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index bd67aabfe8e5f..aebe0be50a330 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -9,8 +9,6 @@ use crate::hir::def_id::DefId; use crate::hir::{self, InlineAsm as HirInlineAsm}; use crate::mir::interpret::{ConstValue, InterpError, Scalar}; use crate::mir::visit::MirVisitable; -use rustc_apfloat::ieee::{Double, Single}; -use rustc_apfloat::Float; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; @@ -21,13 +19,13 @@ use rustc_macros::HashStable; use crate::rustc_serialize::{self as serialize}; use smallvec::SmallVec; use std::borrow::Cow; -use std::fmt::{self, Debug, Formatter, Write}; +use std::fmt::{self, Debug, Formatter, Write, Display}; use std::iter::FusedIterator; use std::ops::{Index, IndexMut}; use std::slice; use std::vec::IntoIter; use std::{iter, mem, option, u32}; -use syntax::ast::{self, Name}; +use syntax::ast::Name; use syntax::symbol::{InternedString, Symbol}; use syntax_pos::{Span, DUMMY_SP}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -1663,8 +1661,7 @@ impl<'tcx> TerminatorKind<'tcx> { values .iter() .map(|&u| { - let mut s = String::new(); - let c = ty::Const { + (&ty::Const { val: ConstValue::Scalar( Scalar::Bits { bits: u, @@ -1672,9 +1669,7 @@ impl<'tcx> TerminatorKind<'tcx> { }.into(), ), ty: switch_ty, - }; - fmt_const_val(&mut s, c).unwrap(); - s.into() + }).to_string().into() }).chain(iter::once("otherwise".into())) .collect() } @@ -2828,67 +2823,15 @@ newtype_index! { impl<'tcx> Debug for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!(fmt, "const ")?; - fmt_const_val(fmt, *self.literal) - } -} -/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output. -pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result { - use crate::ty::TyKind::*; - let value = const_val.val; - let ty = const_val.ty; - // print some primitives - if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = value { - match ty.sty { - Bool if bits == 0 => return write!(f, "false"), - Bool if bits == 1 => return write!(f, "true"), - Float(ast::FloatTy::F32) => return write!(f, "{}f32", Single::from_bits(bits)), - Float(ast::FloatTy::F64) => return write!(f, "{}f64", Double::from_bits(bits)), - Uint(ui) => return write!(f, "{:?}{}", bits, ui), - Int(i) => { - let bit_width = ty::tls::with(|tcx| { - let ty = tcx.lift_to_global(&ty).unwrap(); - tcx.layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size - .bits() - }); - let shift = 128 - bit_width; - return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i); - } - Char => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()), - _ => {} - } + write!(fmt, "{}", self) } - // print function definitions - if let FnDef(did, _) = ty.sty { - return write!(f, "{}", def_path_str(did)); - } - // print string literals - if let ConstValue::Slice(ptr, len) = value { - if let Scalar::Ptr(ptr) = ptr { - if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty { - return ty::tls::with(|tcx| { - let alloc = tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(interpret::AllocKind::Memory(alloc)) = alloc { - assert_eq!(len as usize as u64, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - write!(f, "{:?}", s) - } else { - write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) - } - }); - } - } - } - // just raw dump everything else - write!(f, "{:?} : {}", value, ty) } -fn def_path_str(def_id: DefId) -> String { - ty::tls::with(|tcx| tcx.def_path_str(def_id)) +impl<'tcx> Display for Constant<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + write!(fmt, "const ")?; + write!(fmt, "{}", self.literal) + } } impl<'tcx> graph::DirectedGraph for Mir<'tcx> { diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8e98d4d85b9cc..0129805474012 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -6,8 +6,11 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::middle::region; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; use crate::ty::subst::{Kind, Subst, UnpackedKind}; -use crate::mir::interpret::ConstValue; +use crate::mir::interpret::{ConstValue, sign_extend, Scalar}; use syntax::symbol::{keywords, Symbol}; +use syntax::ast; +use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::Float; use rustc_target::spec::abi::Abi; use syntax::symbol::InternedString; @@ -1532,12 +1535,54 @@ define_print_and_forward_display! { p!(print_def_path(self.def_id, self.substs)); } - &'tcx ty::Const<'tcx> { - match self.val { - ConstValue::Unevaluated(..) | - ConstValue::Infer(..) => p!(write("_")), - ConstValue::Param(ParamConst { name, .. }) => p!(write("{}", name)), - _ => p!(write("{:?}", self)), + ty::Const<'tcx> { + match (self.val, &self.ty.sty) { + | (ConstValue::Unevaluated(..), _) + | (ConstValue::Infer(..), _) + => p!(write("_: "), print(self.ty)), + (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), + (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")), + (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")), + (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F32)) => + p!(write( + "{}f32", + Single::from_bits(bits) + )), + (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F64)) => + p!(write( + "{}f64", + Double::from_bits(bits) + )), + (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) => + p!(write("{}{}", bits, ui)), + (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => { + let size = ty::tls::with(|tcx| { + let ty = tcx.lift_to_global(&self.ty).unwrap(); + tcx.layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size + }); + p!(write("{}{}", sign_extend(bits, size) as i128, i)) + }, + (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) + => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())), + (_, ty::FnDef(did, _)) => p!(write("{}", ty::tls::with(|tcx| tcx.def_path_str(*did)))), + (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) => + p!(write("\"\"")), + ( + ConstValue::Slice(Scalar::Ptr(ptr), len), + ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _), + ) => { + ty::tls::with(|tcx| { + let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + assert_eq!(len as usize as u64, len); + let slice = + &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + Ok(p!(write("{:?}", s))) + })?; + }, + _ => p!(write("{:?} : ", self.val), print(self.ty)), } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index cf04d6eac3ae0..35d0359dbcfd2 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -295,6 +295,9 @@ CloneTypeFoldableAndLiftImpls! { (), bool, usize, + u32, + crate::ty::BoundVar, + crate::ty::DebruijnIndex, crate::ty::layout::VariantIdx, u64, String, @@ -311,6 +314,8 @@ CloneTypeFoldableAndLiftImpls! { ::rustc_target::spec::abi::Abi, crate::mir::Local, crate::mir::Promoted, + crate::mir::interpret::Scalar, + crate::mir::interpret::Pointer, crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, @@ -788,6 +793,34 @@ BraceStructLiftImpl! { } } +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> { + type Lifted = ty::Const<'tcx>; + val, ty + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for interpret::ConstValue<'a> { + type Lifted = interpret::ConstValue<'tcx>; + (interpret::ConstValue::Unevaluated)(a, b), + (interpret::ConstValue::Param)(a), + (interpret::ConstValue::Infer)(a), + (interpret::ConstValue::Scalar)(a), + (interpret::ConstValue::Slice)(a, b), + (interpret::ConstValue::ByRef)(a, b), + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for ty::InferConst<'a> { + type Lifted = ty::InferConst<'tcx>; + (ty::InferConst::Var)(a), + (ty::InferConst::Fresh)(a), + (ty::InferConst::Canonical)(a, b), + } +} + impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> { type Lifted = ConstVid<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 01b1780a2054f..6a8ae47143591 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -10,7 +10,7 @@ use crate::const_eval::{const_field, const_variant_index}; use crate::hair::util::UserAnnotatedTyHelpers; use crate::hair::constant::*; -use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; @@ -290,15 +290,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - fmt_const_val(f, value) + write!(f, "{}", &value) } PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { - fmt_const_val(f, lo)?; + write!(f, "{}", &lo)?; match end { RangeEnd::Included => write!(f, "..=")?, RangeEnd::Excluded => write!(f, "..")?, } - fmt_const_val(f, hi) + write!(f, "{}", &hi) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3a260db806520..3a0a15526b0f4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -4128,8 +4128,7 @@ fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { } }, _ => { - let mut s = String::new(); - ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed"); + let mut s = n.to_string(); // array lengths are obviously usize if s.ends_with("usize") { let n = s.len() - "usize".len(); From 72087ec43b3f8f20040094f535a0bf686a35f015 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 2 Apr 2019 14:23:23 +0200 Subject: [PATCH 05/45] There's a tcx in scope, don't use the tls one --- src/librustc/ty/print/pretty.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 0129805474012..7b72ffcb7b0d7 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1556,31 +1556,27 @@ define_print_and_forward_display! { (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) => p!(write("{}{}", bits, ui)), (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => { - let size = ty::tls::with(|tcx| { - let ty = tcx.lift_to_global(&self.ty).unwrap(); - tcx.layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size - }); + let ty = cx.tcx().lift_to_global(&self.ty).unwrap(); + let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size; p!(write("{}{}", sign_extend(bits, size) as i128, i)) }, (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())), - (_, ty::FnDef(did, _)) => p!(write("{}", ty::tls::with(|tcx| tcx.def_path_str(*did)))), + (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) => p!(write("\"\"")), ( ConstValue::Slice(Scalar::Ptr(ptr), len), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _), ) => { - ty::tls::with(|tcx| { - let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - assert_eq!(len as usize as u64, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - Ok(p!(write("{:?}", s))) - })?; + let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id); + assert_eq!(len as usize as u64, len); + let slice = + &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + p!(write("{:?}", s)) }, _ => p!(write("{:?} : ", self.val), print(self.ty)), } From 7e7cd9280932262ea5c6b347fc2e4d1ebbd9fec0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 2 Apr 2019 14:26:28 +0200 Subject: [PATCH 06/45] Merge the string printing paths of ty::Const --- src/librustc/ty/print/pretty.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 7b72ffcb7b0d7..e7de05a8bc874 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1565,17 +1565,21 @@ define_print_and_forward_display! { (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())), (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), - (ConstValue::Slice(_, 0), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _)) => - p!(write("\"\"")), ( - ConstValue::Slice(Scalar::Ptr(ptr), len), + ConstValue::Slice(place, len), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _), ) => { - let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id); - assert_eq!(len as usize as u64, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + let s = match (place, len) { + (_, 0) => "", + (Scalar::Ptr(ptr), len) => { + let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id); + assert_eq!(len as usize as u64, len); + let slice = + &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; + ::std::str::from_utf8(slice).expect("non utf8 str from miri") + }, + _ => bug!("invalid slice: {:#?}", self), + }; p!(write("{:?}", s)) }, _ => p!(write("{:?} : ", self.val), print(self.ty)), From 17c6c8dc3da3d753a1c4198a7d199141ae094e0f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 2 Apr 2019 14:26:56 +0200 Subject: [PATCH 07/45] Print const chars escaped with surrounding quotes --- src/librustc/ty/print/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index e7de05a8bc874..bcc3bba060688 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1563,7 +1563,7 @@ define_print_and_forward_display! { p!(write("{}{}", sign_extend(bits, size) as i128, i)) }, (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) - => p!(write("{}", ::std::char::from_u32(bits as u32).unwrap())), + => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())), (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), ( ConstValue::Slice(place, len), From 04ad22cf40b083d0b9dfe00434b5ab230139e0c8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 3 Apr 2019 15:29:31 +0200 Subject: [PATCH 08/45] Don't use `ty::Const` without immediately interning --- src/librustc/mir/interpret/error.rs | 2 +- src/librustc/mir/mod.rs | 38 ++++++++------- src/librustc/traits/project.rs | 3 +- src/librustc/traits/query/normalize.rs | 3 +- src/librustc/ty/context.rs | 19 +++----- src/librustc/ty/print/pretty.rs | 2 +- src/librustc/ty/structural_impls.rs | 46 +------------------ src/librustc/ty/sty.rs | 19 ++++---- src/librustc_codegen_ssa/mir/constant.rs | 6 +-- src/librustc_codegen_ssa/mir/operand.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 4 +- src/librustc_mir/build/matches/test.rs | 11 ++--- src/librustc_mir/build/misc.rs | 4 +- src/librustc_mir/const_eval.rs | 14 +++--- src/librustc_mir/hair/constant.rs | 8 ++-- src/librustc_mir/hair/cx/expr.rs | 23 ++++------ src/librustc_mir/hair/cx/mod.rs | 12 ++--- src/librustc_mir/hair/pattern/_match.rs | 12 ++--- src/librustc_mir/hair/pattern/mod.rs | 24 +++++----- src/librustc_mir/interpret/operand.rs | 4 +- src/librustc_mir/monomorphize/collector.rs | 4 +- src/librustc_mir/shim.rs | 12 ++--- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 4 +- src/librustc_mir/transform/generator.rs | 4 +- src/librustc_mir/util/elaborate_drops.rs | 4 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 8 +++- 28 files changed, 114 insertions(+), 182 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 5c6fc6f49f0f0..9c2fd399ee029 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -38,7 +38,7 @@ impl ErrorHandled { } pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; +pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ConstEvalErr<'tcx> { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index aebe0be50a330..94a37341baa23 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1653,25 +1653,25 @@ impl<'tcx> TerminatorKind<'tcx> { switch_ty, .. } => { - let size = ty::tls::with(|tcx| { + ty::tls::with(|tcx| { let param_env = ty::ParamEnv::empty(); let switch_ty = tcx.lift_to_global(&switch_ty).unwrap(); - tcx.layout_of(param_env.and(switch_ty)).unwrap().size - }); - values - .iter() - .map(|&u| { - (&ty::Const { - val: ConstValue::Scalar( - Scalar::Bits { - bits: u, - size: size.bytes() as u8, - }.into(), - ), - ty: switch_ty, - }).to_string().into() - }).chain(iter::once("otherwise".into())) - .collect() + let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; + values + .iter() + .map(|&u| { + tcx.mk_const(ty::Const { + val: ConstValue::Scalar( + Scalar::Bits { + bits: u, + size: size.bytes() as u8, + }.into(), + ), + ty: switch_ty, + }).to_string().into() + }).chain(iter::once("otherwise".into())) + .collect() + }) } Call { destination: Some(_), @@ -2327,9 +2327,7 @@ impl<'tcx> Operand<'tcx> { span, ty, user_ty: None, - literal: tcx.mk_const( - ty::Const::zero_sized(ty), - ), + literal: ty::Const::zero_sized(tcx, ty), }) } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b5232e828c4cd..b37217a57bf28 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -411,7 +411,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { let substs = tcx.lift_to_global(&substs).unwrap(); - let evaluated = tcx.mk_const(evaluated); let evaluated = evaluated.subst(tcx, substs); return evaluated; } @@ -425,7 +424,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, promoted: None }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return tcx.mk_const(evaluated); + return evaluated; } } } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 9940249da8ba9..d09a9c107869b 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -202,7 +202,6 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { let substs = tcx.lift_to_global(&substs).unwrap(); - let evaluated = tcx.mk_const(evaluated); let evaluated = evaluated.subst(tcx, substs); return evaluated; } @@ -216,7 +215,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx promoted: None, }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return tcx.mk_const(evaluated); + return evaluated; } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 15524ca6e930c..3a61a7ec7ae34 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -24,7 +24,7 @@ use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; use crate::mir::{self, Mir, interpret, ProjectionKind}; -use crate::mir::interpret::{ConstValue, Allocation}; +use crate::mir::interpret::{ConstValue, Allocation, Scalar}; use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; use crate::traits; @@ -996,7 +996,10 @@ impl<'tcx> CommonConsts<'tcx> { }; CommonConsts { - err: mk_const(ty::Const::zero_sized(types.err)), + err: mk_const(ty::Const { + val: ConstValue::Scalar(Scalar::Bits { bits: 0, size: 0 }), + ty: types.err, + }), } } } @@ -1809,14 +1812,6 @@ nop_list_lift!{ProjectionKind => ProjectionKind} // this is the impl for `&'a InternalSubsts<'a>` nop_list_lift!{Kind<'a> => Kind<'tcx>} -impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation { - type Lifted = &'tcx mir::interpret::Allocation; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - assert!(tcx.global_arenas.const_allocs.in_arena(*self as *const _)); - Some(unsafe { mem::transmute(*self) }) - } -} - pub mod tls { use super::{GlobalCtxt, TyCtxt, ptr_eq}; @@ -2581,9 +2576,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, self.mk_const( - ty::Const::from_usize(self.global_tcx(), n) - ))) + self.mk_ty(Array(ty, ty::Const::from_usize(self.global_tcx(), n))) } #[inline] diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index bcc3bba060688..8598798b3488f 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1535,7 +1535,7 @@ define_print_and_forward_display! { p!(print_def_path(self.def_id, self.substs)); } - ty::Const<'tcx> { + &'tcx ty::Const<'tcx> { match (self.val, &self.ty.sty) { | (ConstValue::Unevaluated(..), _) | (ConstValue::Infer(..), _) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 35d0359dbcfd2..86883a14f687c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -6,7 +6,7 @@ use crate::hir::def::Namespace; use crate::mir::ProjectionKind; use crate::mir::interpret::ConstValue; -use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst}; +use crate::ty::{self, Lift, Ty, TyCtxt, InferConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -14,7 +14,6 @@ use smallvec::SmallVec; use crate::mir::interpret; use std::fmt; -use std::marker::PhantomData; use std::rc::Rc; impl fmt::Debug for ty::GenericParamDef { @@ -295,9 +294,6 @@ CloneTypeFoldableAndLiftImpls! { (), bool, usize, - u32, - crate::ty::BoundVar, - crate::ty::DebruijnIndex, crate::ty::layout::VariantIdx, u64, String, @@ -314,8 +310,6 @@ CloneTypeFoldableAndLiftImpls! { ::rustc_target::spec::abi::Abi, crate::mir::Local, crate::mir::Promoted, - crate::mir::interpret::Scalar, - crate::mir::interpret::Pointer, crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, @@ -793,44 +787,6 @@ BraceStructLiftImpl! { } } -BraceStructLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> { - type Lifted = ty::Const<'tcx>; - val, ty - } -} - -EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for interpret::ConstValue<'a> { - type Lifted = interpret::ConstValue<'tcx>; - (interpret::ConstValue::Unevaluated)(a, b), - (interpret::ConstValue::Param)(a), - (interpret::ConstValue::Infer)(a), - (interpret::ConstValue::Scalar)(a), - (interpret::ConstValue::Slice)(a, b), - (interpret::ConstValue::ByRef)(a, b), - } -} - -EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for ty::InferConst<'a> { - type Lifted = ty::InferConst<'tcx>; - (ty::InferConst::Var)(a), - (ty::InferConst::Fresh)(a), - (ty::InferConst::Canonical)(a, b), - } -} - -impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> { - type Lifted = ConstVid<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - Some(ConstVid { - index: self.index, - phantom: PhantomData, - }) - } -} - /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 760f3d60d0571..c632e089841b9 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2212,13 +2212,14 @@ static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 48); impl<'tcx> Const<'tcx> { #[inline] pub fn from_scalar( + tcx: TyCtxt<'_, '_, 'tcx>, val: Scalar, ty: Ty<'tcx>, - ) -> Self { - Self { + ) -> &'tcx Self { + tcx.mk_const(Self { val: ConstValue::Scalar(val), ty, - } + }) } #[inline] @@ -2226,28 +2227,28 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'_, '_, 'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Self { + ) -> &'tcx Self { let ty = tcx.lift_to_global(&ty).unwrap(); let size = tcx.layout_of(ty).unwrap_or_else(|e| { panic!("could not compute layout for {:?}: {:?}", ty, e) }).size; let truncated = truncate(bits, size); assert_eq!(truncated, bits, "from_bits called with untruncated value"); - Self::from_scalar(Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value) + Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value) } #[inline] - pub fn zero_sized(ty: Ty<'tcx>) -> Self { - Self::from_scalar(Scalar::Bits { bits: 0, size: 0 }, ty) + pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty) } #[inline] - pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> Self { + pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) } #[inline] - pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> Self { + pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 3f8dc420cf402..eaa1dd186a536 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -13,7 +13,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant( &mut self, constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { + ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { match constant.literal.val { mir::interpret::ConstValue::Unevaluated(def_id, ref substs) => { let substs = self.monomorphize(substs); @@ -26,7 +26,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)) }, - _ => Ok(*self.monomorphize(&constant.literal)), + _ => Ok(self.monomorphize(&constant.literal)), } } @@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result, ErrorHandled>, + constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, ) -> (Bx::Value, Ty<'tcx>) { constant .map(|c| { diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 3b8e5b4495383..670f2da161974 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { pub fn from_const>( bx: &mut Bx, - val: ty::Const<'tcx> + val: &'tcx ty::Const<'tcx> ) -> Result { let layout = bx.layout_of(val.ty); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 51d5c96083d8f..73a3c3be3aa57 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -747,12 +747,12 @@ enum TestKind<'tcx> { SwitchInt { switch_ty: Ty<'tcx>, options: Vec, - indices: FxHashMap, usize>, + indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, // test for equality Eq { - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, ty: Ty<'tcx>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index a5834b02ffc82..0995a2f7fdf49 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -98,7 +98,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, options: &mut Vec, - indices: &mut FxHashMap, usize>) + indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { @@ -305,7 +305,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]); - let method = self.hir.tcx().mk_const(method); let re_erased = self.hir.tcx().lifetimes.re_erased; // take the argument by reference @@ -371,8 +370,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => { // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, ty.clone(), lo.clone()); - let hi = self.literal_operand(test.span, ty.clone(), hi.clone()); + let lo = self.literal_operand(test.span, ty, lo); + let hi = self.literal_operand(test.span, ty, hi); let val = Operand::Copy(place.clone()); let fail = self.cfg.start_new_block(); @@ -724,7 +723,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn const_range_contains( &self, range: PatternRange<'tcx>, - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, ) -> Option { use std::cmp::Ordering::*; @@ -744,7 +743,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn values_not_contained_in_range( &self, range: PatternRange<'tcx>, - indices: &FxHashMap, usize>, + indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>, ) -> Option { for &val in indices.keys() { if self.const_range_contains(range, val)? { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index d71a13dec5a2f..daf59d7a1353c 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -27,13 +27,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn literal_operand(&mut self, span: Span, ty: Ty<'tcx>, - literal: ty::Const<'tcx>) + literal: &'tcx ty::Const<'tcx>) -> Operand<'tcx> { let constant = box Constant { span, ty, user_ty: None, - literal: self.hir.tcx().mk_const(literal), + literal, }; Operand::Constant(constant) } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 866b6492d10bc..2bfc10f8e8c4e 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -65,7 +65,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>( fn mplace_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, mplace: MPlaceTy<'tcx>, -) -> ty::Const<'tcx> { +) -> &'tcx ty::Const<'tcx> { let MemPlace { ptr, align, meta } = *mplace; // extract alloc-offset pair assert!(meta.is_none()); @@ -79,13 +79,13 @@ fn mplace_to_const<'tcx>( // interned this? I thought that is the entire point of that `FinishStatic` stuff? let alloc = ecx.tcx.intern_const_alloc(alloc); let val = ConstValue::ByRef(ptr, alloc); - ty::Const { val, ty: mplace.layout.ty } + ecx.tcx.mk_const(ty::Const { val, ty: mplace.layout.ty }) } fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, op: OpTy<'tcx>, -) -> ty::Const<'tcx> { +) -> &'tcx ty::Const<'tcx> { // We do not normalize just any data. Only non-union scalars and slices. let normalize = match op.layout.abi { layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()), @@ -104,7 +104,7 @@ fn op_to_const<'tcx>( Err(Immediate::ScalarPair(a, b)) => ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()), }; - ty::Const { val, ty: op.layout.ty } + ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty }) } // Returns a pointer to where the result lives @@ -450,8 +450,8 @@ pub fn const_field<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, variant: Option, field: mir::Field, - value: ty::Const<'tcx>, -) -> ty::Const<'tcx> { + value: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { trace!("const_field: {:?}, {:?}", field, value); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); // get the operand again @@ -473,7 +473,7 @@ pub fn const_field<'a, 'tcx>( pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - val: ty::Const<'tcx>, + val: &'tcx ty::Const<'tcx>, ) -> VariantIdx { trace!("const_variant_index: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env); diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index caadc6055b5c6..5ed16abb9a672 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -14,7 +14,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>, neg: bool, -) -> Result, LitToConstError> { +) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { use syntax::ast::*; let trunc = |n| { @@ -39,10 +39,10 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( LitKind::Err(ref s) => { let s = s.as_str(); let id = tcx.allocate_bytes(s.as_bytes()); - return Ok(ty::Const { + return Ok(tcx.mk_const(ty::Const { val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64), ty: tcx.types.err, - }); + })); }, LitKind::ByteStr(ref data) => { let id = tcx.allocate_bytes(data); @@ -71,7 +71,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)), LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), }; - Ok(ty::Const { val: lit, ty }) + Ok(tcx.mk_const(ty::Const { val: lit, ty })) } fn parse_float<'tcx>( diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 50140880a368d..f58055ea28419 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -329,9 +329,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Lit(ref lit) => ExprKind::Literal { - literal: cx.tcx.mk_const( - cx.const_eval_literal(&lit.node, expr_ty, lit.span, false) - ), + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), user_ty: None, }, @@ -429,9 +427,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { if let hir::ExprKind::Lit(ref lit) = arg.node { ExprKind::Literal { - literal: cx.tcx.mk_const( - cx.const_eval_literal(&lit.node, expr_ty, lit.span, true) - ), + literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, } } else { @@ -680,7 +676,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty: var_ty, span: expr.span, kind: ExprKind::Literal { - literal: cx.tcx.mk_const(literal), + literal, user_ty: None }, }.to_ref(); @@ -694,10 +690,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::Const { + let lhs = mk_const(cx.tcx().mk_const(ty::Const { val: ConstValue::Unevaluated(did, substs), ty: var_ty, - }); + })); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -837,9 +833,7 @@ fn method_callee<'a, 'gcx, 'tcx>( ty, span, kind: ExprKind::Literal { - literal: cx.tcx().mk_const( - ty::Const::zero_sized(ty) - ), + literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty, }, } @@ -898,9 +892,10 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); debug!("convert_path_expr: user_ty={:?}", user_ty); ExprKind::Literal { - literal: cx.tcx.mk_const(ty::Const::zero_sized( + literal: ty::Const::zero_sized( + cx.tcx, cx.tables().node_type(expr.hir_id), - )), + ), user_ty, } } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 7aed0bace8c0b..06b5f491a83c6 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> { - self.tcx.mk_const(ty::Const::from_usize(self.tcx, value)) + ty::Const::from_usize(self.tcx, value) } pub fn bool_ty(&mut self) -> Ty<'tcx> { @@ -118,11 +118,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> { - self.tcx.mk_const(ty::Const::from_bool(self.tcx, true)) + ty::Const::from_bool(self.tcx, true) } pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> { - self.tcx.mk_const(ty::Const::from_bool(self.tcx, false)) + ty::Const::from_bool(self.tcx, false) } pub fn const_eval_literal( @@ -131,7 +131,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, sp: Span, neg: bool, - ) -> ty::Const<'tcx> { + ) -> &'tcx ty::Const<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); match lit_to_const(lit, self.tcx, ty, neg) { @@ -166,14 +166,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { method_name: &str, self_ty: Ty<'tcx>, params: &[Kind<'tcx>]) - -> (Ty<'tcx>, ty::Const<'tcx>) { + -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) { let method_name = Symbol::intern(method_name); let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name { let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); - return (method_ty, ty::Const::zero_sized(method_ty)); + return (method_ty, ty::Const::zero_sized(self.tcx, method_ty)); } } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index fd4416fc2b763..83e17514c08f8 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -255,10 +255,10 @@ impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> { subpattern: Pattern { ty: rty, span: pat.span, - kind: box PatternKind::Constant { value: Const { - val: self.fold_const_value_deref(val, rty, crty), + kind: box PatternKind::Constant { value: self.tcx.mk_const(Const { + val: self.fold_const_value_deref(*val, rty, crty), ty: rty, - } }, + }) }, } } } @@ -423,7 +423,7 @@ enum Constructor<'tcx> { /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(ty::Const<'tcx>), + ConstantValue(&'tcx ty::Const<'tcx>), /// Ranges of literal values (`2...5` and `2..5`). ConstantRange(u128, u128, Ty<'tcx>, RangeEnd), /// Array patterns of length n. @@ -1424,7 +1424,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, fn slice_pat_covered_by_const<'tcx>( tcx: TyCtxt<'_, 'tcx, '_>, _span: Span, - const_val: ty::Const<'tcx>, + const_val: &'tcx ty::Const<'tcx>, prefix: &[Pattern<'tcx>], slice: &Option>, suffix: &[Pattern<'tcx>] @@ -1824,7 +1824,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( &cx.tcx, ptr, layout.size, ).ok()?; let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(scalar, ty); + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); let pattern = Pattern { ty, span: pat.span, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 6a8ae47143591..3223c3d583629 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -151,7 +151,7 @@ pub enum PatternKind<'tcx> { }, Constant { - value: ty::Const<'tcx>, + value: &'tcx ty::Const<'tcx>, }, Range(PatternRange<'tcx>), @@ -175,8 +175,8 @@ pub enum PatternKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq)] pub struct PatternRange<'tcx> { - pub lo: ty::Const<'tcx>, - pub hi: ty::Const<'tcx>, + pub lo: &'tcx ty::Const<'tcx>, + pub hi: &'tcx ty::Const<'tcx>, pub ty: Ty<'tcx>, pub end: RangeEnd, } @@ -290,15 +290,15 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { write!(f, "{}", subpattern) } PatternKind::Constant { value } => { - write!(f, "{}", &value) + write!(f, "{}", value) } PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { - write!(f, "{}", &lo)?; + write!(f, "{}", lo)?; match end { RangeEnd::Included => write!(f, "..=")?, RangeEnd::Excluded => write!(f, "..")?, } - write!(f, "{}", &hi) + write!(f, "{}", hi) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -941,7 +941,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn const_to_pat( &self, instance: ty::Instance<'tcx>, - cv: ty::Const<'tcx>, + cv: &'tcx ty::Const<'tcx>, id: hir::HirId, span: Span, ) -> Pattern<'tcx> { @@ -1204,7 +1204,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { PatternKind::Constant { value } => PatternKind::Constant { - value: value.fold_with(folder) + value, }, PatternKind::Range(PatternRange { lo, @@ -1212,8 +1212,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { ty, end, }) => PatternKind::Range(PatternRange { - lo: lo.fold_with(folder), - hi: hi.fold_with(folder), + lo, + hi, ty: ty.fold_with(folder), end, }), @@ -1241,8 +1241,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { pub fn compare_const_vals<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 9c2b491925f47..9481dd3cb8f8f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -500,7 +500,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Move(ref place) => self.eval_place_to_op(place, layout)?, - Constant(ref constant) => self.eval_const_to_op(*constant.literal, layout)?, + Constant(ref constant) => self.eval_const_to_op(constant.literal, layout)?, }; trace!("{:?}: {:?}", mir_op, *op); Ok(op) @@ -520,7 +520,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> // in patterns via the `const_eval` module crate fn eval_const_to_op( &self, - val: ty::Const<'tcx>, + val: &'tcx ty::Const<'tcx>, layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match val.val { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 91cf0fbb9b44f..e0d6784789e2d 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -609,7 +609,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - collect_const(self.tcx, **constant, self.param_substs, self.output); + collect_const(self.tcx, *constant, self.param_substs, self.output); self.super_const(constant); } @@ -1248,7 +1248,7 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn collect_const<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - constant: ty::Const<'tcx>, + constant: &'tcx ty::Const<'tcx>, param_substs: SubstsRef<'tcx>, output: &mut Vec>, ) { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 5bd3a1714887d..6a03ec83d232e 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -458,9 +458,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, user_ty: None, - literal: tcx.mk_const( - ty::Const::zero_sized(func_ty), - ), + literal: ty::Const::zero_sized(tcx, func_ty), }); let ref_loc = self.make_place( @@ -520,9 +518,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, user_ty: None, - literal: self.tcx.mk_const( - ty::Const::from_usize(self.tcx, value), - ), + literal: ty::Const::from_usize(self.tcx, value), } } @@ -762,9 +758,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, user_ty: None, - literal: tcx.mk_const( - ty::Const::zero_sized(ty) - ), + literal: ty::Const::zero_sized(tcx, ty), }), vec![rcvr]) } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 72af027820106..9ec48a3aec060 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -280,7 +280,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { c: &Constant<'tcx>, ) -> Option> { self.ecx.tcx.span = c.span; - match self.ecx.eval_const_to_op(*c.literal, None) { + match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => { Some(op) }, diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 023a61588c42e..6320cb4424814 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -533,9 +533,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, user_ty: None, - literal: self.tcx.mk_const( - ty::Const::from_bool(self.tcx, val), - ), + literal: ty::Const::from_bool(self.tcx, val), }))) } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index d2da1e6e3ac9d..8e38ae6dde9b4 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -757,9 +757,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, user_ty: None, - literal: tcx.mk_const( - ty::Const::from_bool(tcx, false), - ), + literal: ty::Const::from_bool(tcx, false), }), expected: true, msg: message, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 98ca7c32675c8..ac5ebc5e2512a 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -975,9 +975,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, user_ty: None, - literal: self.tcx().mk_const( - ty::Const::from_usize(self.tcx(), val.into()) - ), + literal: ty::Const::from_usize(self.tcx(), val.into()), }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a32745f27e1a0..ed4bb8da27daf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4441,7 +4441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if element_ty.references_error() { tcx.types.err } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, tcx.mk_const(count))) + tcx.mk_ty(ty::Array(t, count)) } else { tcx.types.err } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3a0a15526b0f4..5fc64a62a868e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2958,7 +2958,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { - let mut n = *cx.tcx.lift(&n).expect("array lift failed"); + let mut n = cx.tcx.lift(&n).expect("array lift failed"); if let ConstValue::Unevaluated(def_id, substs) = n.val { let param_env = cx.tcx.param_env(def_id); let cid = GlobalId { @@ -4118,7 +4118,7 @@ fn name_from_pat(p: &hir::Pat) -> String { } } -fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { +fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { match n.val { ConstValue::Unevaluated(def_id, _) => { if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { @@ -4133,6 +4133,10 @@ fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { if s.ends_with("usize") { let n = s.len() - "usize".len(); s.truncate(n); + if s.ends_with(": ") { + let n = s.len() - ": ".len(); + s.truncate(n); + } } s }, From 3a4f5ab59949904180b8d8af6ff068747c601663 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 11 Apr 2019 11:11:11 +0200 Subject: [PATCH 09/45] Add test showing how byte slices are printed in MIR --- src/test/mir-opt/byte_slice.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/mir-opt/byte_slice.rs diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs new file mode 100644 index 0000000000000..ae5d7c4895f72 --- /dev/null +++ b/src/test/mir-opt/byte_slice.rs @@ -0,0 +1,15 @@ +// compile-flags: -Z mir-opt-level=0 + +fn main() { + let x = b"foo"; + let y = [5u8, b'x']; +} + +// END RUST SOURCE +// START rustc.main.EraseRegions.after.mir +// ... +// _1 = const Scalar(Ptr(Pointer { alloc_id: AllocId(0), offset: Size { raw: 0 }, tag: () })) : &[u8; 3]; +// ... +// _2 = [const 5u8, const 120u8]; +// ... +// END rustc.main.EraseRegions.after.mir From f4f82ff0f4c7e3ebc689a9edf070dc2c5bebc613 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 11 Apr 2019 11:12:47 +0200 Subject: [PATCH 10/45] Refactor string constant printing to prep for byte string printing --- src/librustc/ty/print/pretty.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8598798b3488f..18683e4d0ff08 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1569,18 +1569,18 @@ define_print_and_forward_display! { ConstValue::Slice(place, len), ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _), ) => { - let s = match (place, len) { + match (place, len) { (_, 0) => "", (Scalar::Ptr(ptr), len) => { let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id); assert_eq!(len as usize as u64, len); let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - ::std::str::from_utf8(slice).expect("non utf8 str from miri") + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + p!(write("{:?}", s)) }, _ => bug!("invalid slice: {:#?}", self), }; - p!(write("{:?}", s)) }, _ => p!(write("{:?} : ", self.val), print(self.ty)), } From 1468f2048c611a0d9cc2c9ed28d6a034166e5dcb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 11 Apr 2019 15:06:42 +0200 Subject: [PATCH 11/45] Make `ConstValue::Slice` solely take `[u8]` and `str` --- src/librustc/infer/freshen.rs | 2 +- src/librustc/mir/interpret/value.rs | 26 ++-- src/librustc/ty/print/pretty.rs | 28 ++-- src/librustc/ty/structural_impls.rs | 4 +- src/librustc/ty/sty.rs | 2 +- src/librustc_codegen_ssa/mir/operand.rs | 12 +- src/librustc_mir/const_eval.rs | 32 ++++- src/librustc_mir/hair/constant.rs | 10 +- src/librustc_mir/hair/pattern/_match.rs | 123 +++++++----------- src/librustc_mir/hair/pattern/mod.rs | 39 +++--- src/librustc_mir/interpret/operand.rs | 13 +- src/librustc_mir/monomorphize/collector.rs | 4 +- src/test/ui/pattern/slice-pattern-const-2.rs | 4 +- .../ui/pattern/slice-pattern-const-2.stderr | 20 +-- 14 files changed, 157 insertions(+), 162 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 679635bef13e5..8f52ef7a3f3a4 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ConstValue::Param(_) | ConstValue::Scalar(_) | - ConstValue::Slice(..) | + ConstValue::Slice { .. } | ConstValue::ByRef(..) | ConstValue::Unevaluated(..) => {} } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7e45568725f35..d99485f7af632 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -35,14 +35,12 @@ pub enum ConstValue<'tcx> { /// Not using the enum `Value` to encode that this must not be `Undef`. Scalar(Scalar), - /// Used only for slices and strings (`&[T]`, `&str`, `*const [T]`, `*mut str`, `Box`, - /// etc.). - /// - /// Empty slices don't necessarily have an address backed by an `AllocId`, thus we also need to - /// enable integer pointers. The `Scalar` type covers exactly those two cases. While we could - /// create dummy-`AllocId`s, the additional code effort for the conversions doesn't seem worth - /// it. - Slice(Scalar, u64), + /// Used only for `&[u8]` and `&str` + Slice { + data: &'tcx Allocation, + start: usize, + end: usize, + }, /// An allocation together with a pointer into the allocation. /// Invariant: the pointer's `AllocId` resolves to the allocation. @@ -54,7 +52,7 @@ pub enum ConstValue<'tcx> { } #[cfg(target_arch = "x86_64")] -static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 40); +static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 32); impl<'tcx> ConstValue<'tcx> { #[inline] @@ -65,7 +63,7 @@ impl<'tcx> ConstValue<'tcx> { ConstValue::Placeholder(_) | ConstValue::ByRef(..) | ConstValue::Unevaluated(..) | - ConstValue::Slice(..) => None, + ConstValue::Slice { .. } => None, ConstValue::Scalar(val) => Some(val), } } @@ -79,14 +77,6 @@ impl<'tcx> ConstValue<'tcx> { pub fn try_to_ptr(&self) -> Option { self.try_to_scalar()?.to_ptr().ok() } - - #[inline] - pub fn new_slice( - val: Scalar, - len: u64, - ) -> Self { - ConstValue::Slice(val, len) - } } /// A `Scalar` represents an immediate, primitive value existing outside of a diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 18683e4d0ff08..c542c0d6b3fe8 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1566,21 +1566,27 @@ define_print_and_forward_display! { => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())), (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), ( - ConstValue::Slice(place, len), - ty::Ref(_, &ty::TyS { sty: ty::Str, .. }, _), + ConstValue::Slice { data, start, end }, + ty::Ref(_, slice_ty, _), ) => { - match (place, len) { - (_, 0) => "", - (Scalar::Ptr(ptr), len) => { - let alloc = cx.tcx().alloc_map.lock().unwrap_memory(ptr.alloc_id); - assert_eq!(len as usize as u64, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + let slice = &data.bytes[start..end]; + match slice_ty.sty { + ty::Str => { + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); p!(write("{:?}", s)) }, + ty::Slice(elem) if elem == cx.tcx().types.u8 => { + p!(write("b\"")); + for &c in slice { + for e in std::ascii::escape_default(c) { + p!(write("{}", e)); + } + } + p!(write("\"")); + }, _ => bug!("invalid slice: {:#?}", self), - }; + } }, _ => p!(write("{:?} : ", self.val), print(self.ty)), } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 86883a14f687c..0daa567052d56 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1345,7 +1345,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)), ConstValue::Placeholder(p) => ConstValue::Placeholder(p), ConstValue::Scalar(a) => ConstValue::Scalar(a), - ConstValue::Slice(a, b) => ConstValue::Slice(a, b), + ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end }, ConstValue::Unevaluated(did, substs) => ConstValue::Unevaluated(did, substs.fold_with(folder)), } @@ -1358,7 +1358,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { ConstValue::Param(p) => p.visit_with(visitor), ConstValue::Placeholder(_) => false, ConstValue::Scalar(_) => false, - ConstValue::Slice(..) => false, + ConstValue::Slice { .. } => false, ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index c632e089841b9..75bb60674e7c5 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2207,7 +2207,7 @@ pub struct Const<'tcx> { } #[cfg(target_arch = "x86_64")] -static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 48); +static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 40); impl<'tcx> Const<'tcx> { #[inline] diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 670f2da161974..96b149dcf231e 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -1,7 +1,7 @@ -use rustc::mir::interpret::{ConstValue, ErrorHandled}; +use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar}; use rustc::mir; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size}; use crate::base; use crate::MemFlags; @@ -92,17 +92,21 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { ); OperandValue::Immediate(llval) }, - ConstValue::Slice(a, b) => { + ConstValue::Slice { data, start, end } => { let a_scalar = match layout.abi { layout::Abi::ScalarPair(ref a, _) => a, _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout) }; + let a = Scalar::from(Pointer::new( + bx.tcx().alloc_map.lock().allocate(data), + Size::from_bytes(start as u64), + )).into(); let a_llval = bx.scalar_to_backend( a, a_scalar, bx.scalar_pair_element_backend_type(layout, 0, true), ); - let b_llval = bx.const_usize(b); + let b_llval = bx.const_usize((end - start) as u64); OperandValue::Pair(a_llval, b_llval) }, ConstValue::ByRef(ptr, alloc) => { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 2bfc10f8e8c4e..776d4c242415a 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -5,6 +5,7 @@ use std::error::Error; use std::borrow::{Borrow, Cow}; use std::hash::Hash; use std::collections::hash_map::Entry; +use std::convert::TryInto; use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; @@ -89,7 +90,14 @@ fn op_to_const<'tcx>( // We do not normalize just any data. Only non-union scalars and slices. let normalize = match op.layout.abi { layout::Abi::Scalar(..) => op.layout.ty.ty_adt_def().map_or(true, |adt| !adt.is_union()), - layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(), + layout::Abi::ScalarPair(..) => match op.layout.ty.sty { + ty::Ref(_, inner, _) => match inner.sty { + ty::Slice(elem) => elem == ecx.tcx.types.u8, + ty::Str => true, + _ => false, + }, + _ => false, + }, _ => false, }; let normalized_op = if normalize { @@ -101,8 +109,26 @@ fn op_to_const<'tcx>( Ok(mplace) => return mplace_to_const(ecx, mplace), Err(Immediate::Scalar(x)) => ConstValue::Scalar(x.not_undef().unwrap()), - Err(Immediate::ScalarPair(a, b)) => - ConstValue::Slice(a.not_undef().unwrap(), b.to_usize(ecx).unwrap()), + Err(Immediate::ScalarPair(a, b)) => { + let (data, start) = match a.not_undef().unwrap() { + Scalar::Ptr(ptr) => ( + ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + ptr.offset.bytes(), + ), + Scalar::Bits { .. } => ( + ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())), + 0, + ), + }; + let len = b.to_usize(&ecx.tcx.tcx).unwrap(); + let start = start.try_into().unwrap(); + let len: usize = len.try_into().unwrap(); + ConstValue::Slice { + data, + start, + end: start + len, + } + }, }; ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty }) } diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index 5ed16abb9a672..d2c86d36238e1 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -33,14 +33,16 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( let lit = match *lit { LitKind::Str(ref s, _) => { let s = s.as_str(); - let id = tcx.allocate_bytes(s.as_bytes()); - ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64) + let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ()); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: s.len() } }, LitKind::Err(ref s) => { let s = s.as_str(); - let id = tcx.allocate_bytes(s.as_bytes()); + let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ()); + let allocation = tcx.intern_const_alloc(allocation); return Ok(tcx.mk_const(ty::Const { - val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64), + val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() }, ty: tcx.types.err, })); }, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 83e17514c08f8..29e9c425685e8 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -172,7 +172,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const}; use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size}; use rustc::mir::Field; -use rustc::mir::interpret::{ConstValue, Scalar, truncate}; +use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer}; use rustc::util::common::ErrorReported; use syntax::attr::{SignedInt, UnsignedInt}; @@ -186,6 +186,7 @@ use std::fmt; use std::iter::{FromIterator, IntoIterator}; use std::ops::RangeInclusive; use std::u128; +use std::convert::TryInto; pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>) -> &'a Pattern<'tcx> @@ -221,16 +222,17 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { // unsize array to slice if pattern is array but match value or other patterns are slice (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => { assert_eq!(t, u); - ConstValue::Slice( - Scalar::Ptr(p), - n.val.try_to_scalar() - .unwrap() - .to_usize(&self.tcx) - .unwrap(), - ) + ConstValue::Slice { + data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id), + start: p.offset.bytes().try_into().unwrap(), + end: n.unwrap_usize(self.tcx).try_into().unwrap(), + } }, // fat pointers stay the same - (ConstValue::Slice(..), _, _) => val, + | (ConstValue::Slice { .. }, _, _) + | (_, ty::Slice(_), ty::Slice(_)) + | (_, ty::Str, ty::Str) + => val, // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), } @@ -786,9 +788,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( max_fixed_len, n.unwrap_usize(cx.tcx), ), - (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max( + (ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max( max_fixed_len, - n, + (end - start) as u64, ), _ => {}, } @@ -1431,42 +1433,17 @@ fn slice_pat_covered_by_const<'tcx>( ) -> Result { let data: &[u8] = match (const_val.val, &const_val.ty.sty) { (ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } + assert_eq!(*t, tcx.types.u8); let n = n.assert_usize(tcx).unwrap(); alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap() }, - // a slice fat pointer to a zero length slice - (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } - &[] - }, - // - (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => { - if *t != tcx.types.u8 { - // FIXME(oli-obk): can't mix const patterns with slice patterns and get - // any sort of exhaustiveness/unreachable check yet - // This solely means that we don't lint about unreachable patterns, even if some - // are definitely unreachable. - return Ok(false); - } - tcx.alloc_map - .lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&tcx, ptr, Size::from_bytes(n)) - .unwrap() + (ConstValue::Slice { data, start, end }, ty::Slice(t)) => { + assert_eq!(*t, tcx.types.u8); + let ptr = Pointer::new(AllocId(0), Size::from_bytes(start as u64)); + data.get_bytes(&tcx, ptr, Size::from_bytes((end - start) as u64)).unwrap() }, + // FIXME(oli-obk): create a way to extract fat pointers from ByRef + (_, ty::Slice(_)) => return Ok(false), _ => bug!( "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}", const_val, prefix, slice, suffix, @@ -1774,11 +1751,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // necessarily point to memory, they are usually just integers. The only time // they should be pointing to memory is when they are subslices of nonzero // slices - let (opt_ptr, n, ty) = match value.ty.sty { + let (alloc, offset, n, ty) = match value.ty.sty { ty::Array(t, n) => { match value.val { ConstValue::ByRef(ptr, alloc) => ( - Some((ptr, alloc)), + alloc, + ptr.offset, n.unwrap_usize(cx.tcx), t, ), @@ -1790,14 +1768,16 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, ty::Slice(t) => { match value.val { - ConstValue::Slice(ptr, n) => ( - ptr.to_ptr().ok().map(|ptr| ( - ptr, - cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - )), - n, + ConstValue::Slice { data, start, end } => ( + data, + Size::from_bytes(start as u64), + (end - start) as u64, t, ), + ConstValue::ByRef(..) => { + // FIXME(oli-obk): implement `deref` for `ConstValue` + return None; + }, _ => span_bug!( pat.span, "slice pattern constant must be scalar pair but is {:?}", @@ -1814,31 +1794,22 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }; if wild_patterns.len() as u64 == n { // convert a constant slice/array pattern to a list of patterns. - match (n, opt_ptr) { - (0, _) => Some(SmallVec::new()), - (_, Some((ptr, alloc))) => { - let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; - (0..n).map(|i| { - let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; - let scalar = alloc.read_scalar( - &cx.tcx, ptr, layout.size, - ).ok()?; - let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); - let pattern = Pattern { - ty, - span: pat.span, - kind: box PatternKind::Constant { value }, - }; - Some(&*cx.pattern_arena.alloc(pattern)) - }).collect() - }, - (_, None) => span_bug!( - pat.span, - "non zero length slice with const-val {:?}", - value, - ), - } + let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; + let ptr = Pointer::new(AllocId(0), offset); + (0..n).map(|i| { + let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?; + let scalar = alloc.read_scalar( + &cx.tcx, ptr, layout.size, + ).ok()?; + let scalar = scalar.not_undef().ok()?; + let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let pattern = Pattern { + ty, + span: pat.span, + kind: box PatternKind::Constant { value }, + }; + Some(&*cx.pattern_arena.alloc(pattern)) + }).collect() } else { None } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 3223c3d583629..148211771ade9 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -12,11 +12,11 @@ use crate::hair::constant::*; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::mir::{UserTypeProjection}; -use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; +use rustc::mir::interpret::{GlobalId, ConstValue, sign_extend, AllocId, Pointer}; use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, UserType, DefIdTree}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; use rustc::ty::subst::{SubstsRef, Kind}; -use rustc::ty::layout::VariantIdx; +use rustc::ty::layout::{VariantIdx, Size}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -1292,22 +1292,25 @@ pub fn compare_const_vals<'a, 'gcx, 'tcx>( if let ty::Str = ty.value.sty { match (a.val, b.val) { ( - ConstValue::Slice( - Scalar::Ptr(ptr_a), - len_a, - ), - ConstValue::Slice( - Scalar::Ptr(ptr_b), - len_b, - ), - ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { - if len_a == len_b { - let map = tcx.alloc_map.lock(); - let alloc_a = map.unwrap_memory(ptr_a.alloc_id); - let alloc_b = map.unwrap_memory(ptr_b.alloc_id); - if alloc_a.bytes.len() as u64 == len_a { - return from_bool(alloc_a == alloc_b); - } + ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a }, + ConstValue::Slice { data: alloc_b, start: offset_b, end: end_b }, + ) => { + let len_a = end_a - offset_a; + let len_b = end_b - offset_b; + let a = alloc_a.get_bytes( + &tcx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(offset_a as u64)), + Size::from_bytes(len_a as u64), + ); + let b = alloc_b.get_bytes( + &tcx, + // invent a pointer, only the offset is relevant anyway + Pointer::new(AllocId(0), Size::from_bytes(offset_b as u64)), + Size::from_bytes(len_b as u64), + ); + if let (Ok(a), Ok(b)) = (a, b) { + return from_bool(a == b); } } _ => (), diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 9481dd3cb8f8f..407622dc2599b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -533,11 +533,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> MemPlace::from_ptr(ptr.with_default_tag(), alloc.align) ) }, - ConstValue::Slice(a, b) => + ConstValue::Slice { data, start, end } => Operand::Immediate(Immediate::ScalarPair( - a.with_default_tag().into(), - Scalar::from_uint(b, self.tcx.data_layout.pointer_size) - .with_default_tag().into(), + Scalar::from(Pointer::new( + self.tcx.alloc_map.lock().allocate(data), + Size::from_bytes(start as u64), + )).with_default_tag().into(), + Scalar::from_uint( + (end - start) as u64, + self.tcx.data_layout.pointer_size, + ).with_default_tag().into(), )), ConstValue::Scalar(x) => Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())), diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e0d6784789e2d..b90db7646d492 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1255,10 +1255,10 @@ fn collect_const<'a, 'tcx>( debug!("visiting const {:?}", constant); match constant.val { - ConstValue::Slice(Scalar::Ptr(ptr), _) | ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), - ConstValue::ByRef(_ptr, alloc) => { + ConstValue::Slice { data: alloc, start: _, end: _ } | + ConstValue::ByRef(_, alloc) => { for &((), id) in alloc.relocations.values() { collect_miri(tcx, id, output); } diff --git a/src/test/ui/pattern/slice-pattern-const-2.rs b/src/test/ui/pattern/slice-pattern-const-2.rs index 6cfef115d08dc..a36c550f530a9 100644 --- a/src/test/ui/pattern/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/slice-pattern-const-2.rs @@ -6,13 +6,13 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), //~ ERROR unreachable pattern + [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not _ => (), } match s { diff --git a/src/test/ui/pattern/slice-pattern-const-2.stderr b/src/test/ui/pattern/slice-pattern-const-2.stderr index e2c408a90e4e1..0c7401269dfc7 100644 --- a/src/test/ui/pattern/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:9:9 + --> $DIR/slice-pattern-const-2.rs:28:9 | -LL | [4, 5, 6, 7] => (), - | ^^^^^^^^^^^^ +LL | FOO => (), + | ^^^ | note: lint level defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,17 +10,5 @@ note: lint level defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:15:9 - | -LL | [4, 5, 6, 7] => (), - | ^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 - | -LL | FOO => (), - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to previous error From d46c964eafc2457a0e41ad92bc07c5cffc30012b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 11 Apr 2019 22:04:04 +0200 Subject: [PATCH 12/45] Render const byte slices in MIR --- src/librustc/ty/print/pretty.rs | 54 ++++++++++++++++++++------------- src/test/mir-opt/byte_slice.rs | 2 +- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index c542c0d6b3fe8..0030a35fe3f08 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -6,6 +6,7 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::middle::region; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; use crate::ty::subst::{Kind, Subst, UnpackedKind}; +use crate::ty::layout::Size; use crate::mir::interpret::{ConstValue, sign_extend, Scalar}; use syntax::symbol::{keywords, Symbol}; use syntax::ast; @@ -1536,6 +1537,7 @@ define_print_and_forward_display! { } &'tcx ty::Const<'tcx> { + let u8 = cx.tcx().types.u8; match (self.val, &self.ty.sty) { | (ConstValue::Unevaluated(..), _) | (ConstValue::Infer(..), _) @@ -1565,28 +1567,38 @@ define_print_and_forward_display! { (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())), (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), - ( - ConstValue::Slice { data, start, end }, - ty::Ref(_, slice_ty, _), - ) => { - let slice = &data.bytes[start..end]; - match slice_ty.sty { - ty::Str => { - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - p!(write("{:?}", s)) - }, - ty::Slice(elem) if elem == cx.tcx().types.u8 => { - p!(write("b\"")); - for &c in slice { - for e in std::ascii::escape_default(c) { - p!(write("{}", e)); - } + (_, ty::Ref(_, ref_ty, _)) => match (self.val, &ref_ty.sty) { + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { + let n = n.unwrap_usize(cx.tcx()); + let slice = cx.tcx() + .alloc_map.lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap(); + p!(write("b\"")); + for &c in slice { + for e in std::ascii::escape_default(c) { + p!(write("{}", e)); } - p!(write("\"")); - }, - _ => bug!("invalid slice: {:#?}", self), - } + } + p!(write("\"")); + }, + (ConstValue::Slice { data, start, end }, ty::Str) => { + let slice = &data.bytes[start..end]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + p!(write("{:?}", s)) + }, + (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { + let slice = &data.bytes[start..end]; + p!(write("b\"")); + for &c in slice { + for e in std::ascii::escape_default(c) { + p!(write("{}", e)); + } + } + p!(write("\"")); + }, + _ => p!(write("{:?} : ", self.val), print(self.ty)), }, _ => p!(write("{:?} : ", self.val), print(self.ty)), } diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs index ae5d7c4895f72..23faf7e16a7ed 100644 --- a/src/test/mir-opt/byte_slice.rs +++ b/src/test/mir-opt/byte_slice.rs @@ -8,7 +8,7 @@ fn main() { // END RUST SOURCE // START rustc.main.EraseRegions.after.mir // ... -// _1 = const Scalar(Ptr(Pointer { alloc_id: AllocId(0), offset: Size { raw: 0 }, tag: () })) : &[u8; 3]; +// _1 = const b"102111111"; // ... // _2 = [const 5u8, const 120u8]; // ... From 46704bf94f1af0fc323628dd86a68226f46b56a2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 15 Apr 2019 11:00:55 +0200 Subject: [PATCH 13/45] `u8` is printed as a number, not a character --- src/librustc/ty/print/pretty.rs | 4 ++-- src/test/mir-opt/byte_slice.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 0030a35fe3f08..fa197f3505227 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1577,7 +1577,7 @@ define_print_and_forward_display! { p!(write("b\"")); for &c in slice { for e in std::ascii::escape_default(c) { - p!(write("{}", e)); + p!(write("{}", e as char)); } } p!(write("\"")); @@ -1593,7 +1593,7 @@ define_print_and_forward_display! { p!(write("b\"")); for &c in slice { for e in std::ascii::escape_default(c) { - p!(write("{}", e)); + p!(write("{}", e as char)); } } p!(write("\"")); diff --git a/src/test/mir-opt/byte_slice.rs b/src/test/mir-opt/byte_slice.rs index 23faf7e16a7ed..7edfa3e1124db 100644 --- a/src/test/mir-opt/byte_slice.rs +++ b/src/test/mir-opt/byte_slice.rs @@ -8,7 +8,7 @@ fn main() { // END RUST SOURCE // START rustc.main.EraseRegions.after.mir // ... -// _1 = const b"102111111"; +// _1 = const b"foo"; // ... // _2 = [const 5u8, const 120u8]; // ... From 983f676d25135ac6cc478293a85b7cd8130d9b1a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 17 Apr 2019 17:29:38 +0200 Subject: [PATCH 14/45] Render unresolved anon consts like closures --- src/librustc/ty/print/pretty.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index fa197f3505227..15c2758a19e46 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1,5 +1,5 @@ use crate::hir; -use crate::hir::def::Namespace; +use crate::hir::def::{Namespace, Def}; use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::middle::cstore::{ExternCrate, ExternCrateSource}; @@ -1539,9 +1539,15 @@ define_print_and_forward_display! { &'tcx ty::Const<'tcx> { let u8 = cx.tcx().types.u8; match (self.val, &self.ty.sty) { - | (ConstValue::Unevaluated(..), _) - | (ConstValue::Infer(..), _) - => p!(write("_: "), print(self.ty)), + (ConstValue::Unevaluated(did, substs), _) => { + match cx.tcx().describe_def(did) { + | Some(Def::Static(_, _)) + | Some(Def::Const(_)) + | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))), + _ => p!(write("_")), + } + } + (ConstValue::Infer(..), _) => p!(write("_: "), print(self.ty)), (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")), (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")), From b7c094b146b8332403e88f1b3ab17bb4714bb0de Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 17 Apr 2019 17:50:47 +0200 Subject: [PATCH 15/45] Group common printing code during constant pretty printing --- src/librustc/ty/print/pretty.rs | 129 ++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 56 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 15c2758a19e46..a9aa575b7ad1c 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1538,76 +1538,93 @@ define_print_and_forward_display! { &'tcx ty::Const<'tcx> { let u8 = cx.tcx().types.u8; - match (self.val, &self.ty.sty) { - (ConstValue::Unevaluated(did, substs), _) => { - match cx.tcx().describe_def(did) { - | Some(Def::Static(_, _)) - | Some(Def::Const(_)) - | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))), - _ => p!(write("_")), + if let ty::FnDef(did, _) = self.ty.sty { + p!(write("{}", cx.tcx().def_path_str(did))); + return Ok(cx); + } + if let ConstValue::Unevaluated(did, substs) = self.val { + match cx.tcx().describe_def(did) { + | Some(Def::Static(_, _)) + | Some(Def::Const(_, false)) + | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))), + _ => p!(write("_")), + } + return Ok(cx); + } + if let ConstValue::Infer(..) = self.val { + p!(write("_: "), print(self.ty)); + return Ok(cx); + } + if let ConstValue::Param(ParamConst { name, .. }) = self.val { + p!(write("{}", name)); + return Ok(cx); + } + if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = self.val { + match self.ty.sty { + ty::Bool => { + p!(write("{}", if bits == 0 { "false" } else { "true" })); + return Ok(cx); + }, + ty::Float(ast::FloatTy::F32) => { + p!(write("{}f32", Single::from_bits(bits))); + return Ok(cx); + }, + ty::Float(ast::FloatTy::F64) => { + p!(write("{}f64", Double::from_bits(bits))); + return Ok(cx); + }, + ty::Uint(ui) => { + p!(write("{}{}", bits, ui)); + return Ok(cx); + }, + ty::Int(i) =>{ + let ty = cx.tcx().lift_to_global(&self.ty).unwrap(); + let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size; + p!(write("{}{}", sign_extend(bits, size) as i128, i)); + return Ok(cx); + }, + ty::Char => { + p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())); + return Ok(cx); } + _ => {}, } - (ConstValue::Infer(..), _) => p!(write("_: "), print(self.ty)), - (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), - (ConstValue::Scalar(Scalar::Bits { bits: 0, .. }), ty::Bool) => p!(write("false")), - (ConstValue::Scalar(Scalar::Bits { bits: 1, .. }), ty::Bool) => p!(write("true")), - (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F32)) => - p!(write( - "{}f32", - Single::from_bits(bits) - )), - (ConstValue::Scalar(Scalar::Bits { bits, .. }), ty::Float(ast::FloatTy::F64)) => - p!(write( - "{}f64", - Double::from_bits(bits) - )), - (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Uint(ui)) => - p!(write("{}{}", bits, ui)), - (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Int(i)) => { - let ty = cx.tcx().lift_to_global(&self.ty).unwrap(); - let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size; - p!(write("{}{}", sign_extend(bits, size) as i128, i)) - }, - (ConstValue::Scalar(Scalar::Bits { bits, ..}), ty::Char) - => p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())), - (_, ty::FnDef(did, _)) => p!(write("{}", cx.tcx().def_path_str(*did))), - (_, ty::Ref(_, ref_ty, _)) => match (self.val, &ref_ty.sty) { + } + if let ty::Ref(_, ref_ty, _) = self.ty.sty { + let byte_str = match (self.val, &ref_ty.sty) { (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { let n = n.unwrap_usize(cx.tcx()); - let slice = cx.tcx() + Some(cx.tcx() .alloc_map.lock() .unwrap_memory(ptr.alloc_id) - .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap(); - p!(write("b\"")); - for &c in slice { - for e in std::ascii::escape_default(c) { - p!(write("{}", e as char)); - } - } - p!(write("\"")); + .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap()) + }, + (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { + Some(&data.bytes[start..end]) }, (ConstValue::Slice { data, start, end }, ty::Str) => { let slice = &data.bytes[start..end]; let s = ::std::str::from_utf8(slice) .expect("non utf8 str from miri"); - p!(write("{:?}", s)) + p!(write("{:?}", s)); + return Ok(cx); }, - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - let slice = &data.bytes[start..end]; - p!(write("b\"")); - for &c in slice { - for e in std::ascii::escape_default(c) { - p!(write("{}", e as char)); - } + _ => None, + }; + if let Some(byte_str) = byte_str { + p!(write("b\"")); + for &c in byte_str { + for e in std::ascii::escape_default(c) { + p!(write("{}", e as char)); } - p!(write("\"")); - }, - _ => p!(write("{:?} : ", self.val), print(self.ty)), - }, - _ => p!(write("{:?} : ", self.val), print(self.ty)), + } + p!(write("\"")); + return Ok(cx); + } } + p!(write("{:?} : ", self.val), print(self.ty)); } ty::ParamTy { From f2d2250edc2936d1ef9339a24b700a07d4b10328 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 17 Apr 2019 18:19:59 +0200 Subject: [PATCH 16/45] Print generic args in function calls in MIR --- src/librustc/ty/print/pretty.rs | 4 ++-- src/test/mir-opt/box_expr.rs | 2 +- src/test/mir-opt/inline-trait-method.rs | 2 +- src/test/mir-opt/inline-trait-method_2.rs | 2 +- src/test/mir-opt/issue-49232.rs | 2 +- src/test/mir-opt/unusual-item-types.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index a9aa575b7ad1c..ec260530152e5 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1538,8 +1538,8 @@ define_print_and_forward_display! { &'tcx ty::Const<'tcx> { let u8 = cx.tcx().types.u8; - if let ty::FnDef(did, _) = self.ty.sty { - p!(write("{}", cx.tcx().def_path_str(did))); + if let ty::FnDef(did, substs) = self.ty.sty { + p!(print_value_path(did, substs)); return Ok(cx); } if let ConstValue::Unevaluated(did, substs) = self.val { diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index d4852db6d475e..4a5a4e0677aa4 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -54,7 +54,7 @@ impl Drop for S { // StorageDead(_2); // StorageLive(_4); // _4 = move _1; -// _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7]; +// _3 = const std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // } // // bb5: { diff --git a/src/test/mir-opt/inline-trait-method.rs b/src/test/mir-opt/inline-trait-method.rs index 0f79f43ee2df0..a2c5fb920cd30 100644 --- a/src/test/mir-opt/inline-trait-method.rs +++ b/src/test/mir-opt/inline-trait-method.rs @@ -25,7 +25,7 @@ impl X for () { // ... // bb0: { // ... -// _0 = const X::y(move _2) -> bb1; +// _0 = const ::y(move _2) -> bb1; // } // ... // END rustc.test.Inline.after.mir diff --git a/src/test/mir-opt/inline-trait-method_2.rs b/src/test/mir-opt/inline-trait-method_2.rs index 8f9f2535aa5f8..4ad4311113a3a 100644 --- a/src/test/mir-opt/inline-trait-method_2.rs +++ b/src/test/mir-opt/inline-trait-method_2.rs @@ -30,7 +30,7 @@ fn main() { // ... // bb0: { // ... -// _0 = const X::y(move _2) -> bb1; +// _0 = const ::y(move _2) -> bb1; // } // ... // END rustc.test2.Inline.after.mir diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 29446d2ecc23e..f72258dd9b998 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -96,7 +96,7 @@ fn main() { // StorageDead(_3); // StorageLive(_6); // _6 = &_2; -// _5 = const std::mem::drop(move _6) -> [return: bb19, unwind: bb4]; +// _5 = const std::mem::drop::<&i32>(move _6) -> [return: bb19, unwind: bb4]; // } // bb19: { // StorageDead(_6); diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 606503151c985..93f17d976e6a1 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -68,7 +68,7 @@ fn main() { // } // bb7: { // _2 = &mut (*_1); -// _3 = const std::ops::Drop::drop(move _2) -> [return: bb6, unwind: bb5]; +// _3 = const as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // } // END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir From 830ce7343e21c99c72e947523f4f68840eb15ea7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 24 Apr 2019 14:10:05 +0200 Subject: [PATCH 17/45] Fix tidy --- src/test/mir-opt/unusual-item-types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 93f17d976e6a1..67a55101d829f 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -1,5 +1,6 @@ // Test that we don't ICE when trying to dump MIR for unusual item types and // that we don't create filenames containing `<` and `>` +// ignore-tidy-linelength struct A; From bb6f156f11eac564adb6de01ac181157afb10a73 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 24 Apr 2019 14:10:31 +0200 Subject: [PATCH 18/45] Use `write_char` to skip the formatting infrastructure --- src/librustc/ty/print/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index ec260530152e5..6241e049ae4bd 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1617,7 +1617,7 @@ define_print_and_forward_display! { p!(write("b\"")); for &c in byte_str { for e in std::ascii::escape_default(c) { - p!(write("{}", e as char)); + cx.write_char(e as char)?; } } p!(write("\"")); From 05d8b4cfde2b89b32a824820370f2145e03e9014 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 24 Apr 2019 14:10:52 +0200 Subject: [PATCH 19/45] Print unevaluted constants as `_` or as their source representation --- src/librustc/ty/print/pretty.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 6241e049ae4bd..e0b737bff7a4c 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1544,10 +1544,19 @@ define_print_and_forward_display! { } if let ConstValue::Unevaluated(did, substs) = self.val { match cx.tcx().describe_def(did) { - | Some(Def::Static(_, _)) - | Some(Def::Const(_, false)) - | Some(Def::AssociatedConst(_)) => p!(write("{}", cx.tcx().def_path_str(did))), - _ => p!(write("_")), + | Some(Def::Static(_)) + | Some(Def::Const(_)) + | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)), + _ => if did.is_local() { + let span = cx.tcx().def_span(did); + if let Ok(snip) = cx.tcx().sess.source_map().span_to_snippet(span) { + p!(write("{}", snip)) + } else { + p!(write("_")) + } + } else { + p!(write("_")) + }, } return Ok(cx); } From 681680ddfa902f3818a73277483dff2460217e7c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 24 Apr 2019 16:12:53 +0200 Subject: [PATCH 20/45] Update ui tests --- src/test/ui/consts/const_let_refutable.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/const_let_refutable.stderr b/src/test/ui/consts/const_let_refutable.stderr index 20433bbf8b5c7..917bd76d48302 100644 --- a/src/test/ui/consts/const_let_refutable.stderr +++ b/src/test/ui/consts/const_let_refutable.stderr @@ -4,7 +4,7 @@ error[E0005]: refutable pattern in function argument: `&[]` not covered LL | const fn slice([a, b]: &[i32]) -> i32 { | ^^^^^^ pattern `&[]` not covered -error[E0723]: can only call other `const fn` within a `const fn`, but `const std::ops::Add::add` is not stable as `const fn` +error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn` --> $DIR/const_let_refutable.rs:4:5 | LL | a + b From 816f75578de5df169640ec97b22ffd99820a70cc Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 18 Mar 2019 12:50:57 +0200 Subject: [PATCH 21/45] rustc: integrate ty::Const into ty::print as print_const. --- src/librustc/infer/error_reporting/mod.rs | 8 + src/librustc/lint/context.rs | 10 +- src/librustc/ty/print/mod.rs | 14 ++ src/librustc/ty/print/pretty.rs | 227 +++++++++++---------- src/librustc_codegen_utils/symbol_names.rs | 8 + 5 files changed, 160 insertions(+), 107 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 4b6e7da333081..a2c8558be4643 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -462,6 +462,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { type Region = !; type Type = !; type DynExistential = !; + type Const = !; fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx @@ -488,6 +489,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Err(NonTrivialPath) } + fn print_const( + self, + _ct: &'tcx ty::Const<'tcx>, + ) -> Result { + Err(NonTrivialPath) + } + fn path_crate( self, cnum: CrateNum, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e713cf8d80553..03acfa4c229cf 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -791,6 +791,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { type Region = (); type Type = (); type DynExistential = (); + type Const = (); fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx @@ -807,7 +808,14 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { fn print_dyn_existential( self, _predicates: &'tcx ty::List>, - ) -> Result { + ) -> Result { + Ok(()) + } + + fn print_const( + self, + _ct: &'tcx ty::Const<'tcx>, + ) -> Result { Ok(()) } diff --git a/src/librustc/ty/print/mod.rs b/src/librustc/ty/print/mod.rs index d5d4f64844463..53d4466cfef68 100644 --- a/src/librustc/ty/print/mod.rs +++ b/src/librustc/ty/print/mod.rs @@ -31,6 +31,7 @@ pub trait Printer<'gcx: 'tcx, 'tcx>: Sized { type Region; type Type; type DynExistential; + type Const; fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; @@ -66,6 +67,11 @@ pub trait Printer<'gcx: 'tcx, 'tcx>: Sized { predicates: &'tcx ty::List>, ) -> Result; + fn print_const( + self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result; + fn path_crate( self, cnum: CrateNum, @@ -325,3 +331,11 @@ impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> cx.print_dyn_existential(self) } } + +impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for &'tcx ty::Const<'tcx> { + type Output = P::Const; + type Error = P::Error; + fn print(&self, cx: P) -> Result { + cx.print_const(self) + } +} diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index e0b737bff7a4c..19fbf498034be 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -175,6 +175,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: Region = Self, Type = Self, DynExistential = Self, + Const = Self, > + fmt::Write { @@ -667,12 +668,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: }, ty::Array(ty, sz) => { p!(write("["), print(ty), write("; ")); - match sz.val { - ConstValue::Unevaluated(..) | - ConstValue::Infer(..) => p!(write("_")), - ConstValue::Param(ParamConst { name, .. }) => - p!(write("{}", name)), - _ => p!(write("{}", sz.unwrap_usize(self.tcx()))), + if let Some(n) = sz.assert_usize(self.tcx()) { + p!(write("{}", n)); + } else { + p!(print(sz)); } p!(write("]")) } @@ -810,6 +809,113 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: Ok(self) } + + fn pretty_print_const( + mut self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + define_scoped_cx!(self); + + let u8 = self.tcx().types.u8; + if let ty::FnDef(did, substs) = ct.ty.sty { + p!(print_value_path(did, substs)); + return Ok(self); + } + if let ConstValue::Unevaluated(did, substs) = ct.val { + match self.tcx().describe_def(did) { + | Some(Def::Static(_)) + | Some(Def::Const(_)) + | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)), + _ => if did.is_local() { + let span = self.tcx().def_span(did); + if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { + p!(write("{}", snip)) + } else { + p!(write("_")) + } + } else { + p!(write("_")) + }, + } + return Ok(self); + } + if let ConstValue::Infer(..) = ct.val { + p!(write("_: "), print(ct.ty)); + return Ok(self); + } + if let ConstValue::Param(ParamConst { name, .. }) = ct.val { + p!(write("{}", name)); + return Ok(self); + } + if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = ct.val { + match ct.ty.sty { + ty::Bool => { + p!(write("{}", if bits == 0 { "false" } else { "true" })); + return Ok(self); + }, + ty::Float(ast::FloatTy::F32) => { + p!(write("{}f32", Single::from_bits(bits))); + return Ok(self); + }, + ty::Float(ast::FloatTy::F64) => { + p!(write("{}f64", Double::from_bits(bits))); + return Ok(self); + }, + ty::Uint(ui) => { + p!(write("{}{}", bits, ui)); + return Ok(self); + }, + ty::Int(i) =>{ + let ty = self.tcx().lift_to_global(&ct.ty).unwrap(); + let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size; + p!(write("{}{}", sign_extend(bits, size) as i128, i)); + return Ok(self); + }, + ty::Char => { + p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())); + return Ok(self); + } + _ => {}, + } + } + if let ty::Ref(_, ref_ty, _) = ct.ty.sty { + let byte_str = match (ct.val, &ref_ty.sty) { + (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { + let n = n.unwrap_usize(self.tcx()); + Some(self.tcx() + .alloc_map.lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) + }, + (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { + Some(&data.bytes[start..end]) + }, + (ConstValue::Slice { data, start, end }, ty::Str) => { + let slice = &data.bytes[start..end]; + let s = ::std::str::from_utf8(slice) + .expect("non utf8 str from miri"); + p!(write("{:?}", s)); + return Ok(self); + }, + _ => None, + }; + if let Some(byte_str) = byte_str { + p!(write("b\"")); + for &c in byte_str { + for e in std::ascii::escape_default(c) { + self.write_char(e as char)?; + } + } + p!(write("\"")); + return Ok(self); + } + } + p!(write("{:?} : ", ct.val), print(ct.ty)); + + Ok(self) + } } // HACK(eddyb) boxed to avoid moving around a large struct by-value. @@ -902,6 +1008,7 @@ impl Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> { type Region = Self; type Type = Self; type DynExistential = Self; + type Const = Self; fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx @@ -977,6 +1084,13 @@ impl Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> { self.pretty_print_dyn_existential(predicates) } + fn print_const( + self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + self.pretty_print_const(ct) + } + fn path_crate( mut self, cnum: CrateNum, @@ -1447,6 +1561,7 @@ impl fmt::Display for ty::RegionKind { forward_display_to_print! { Ty<'tcx>, &'tcx ty::List>, + &'tcx ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'gcx: 'tcx, 'tcx>` isn't possible yet. @@ -1536,106 +1651,6 @@ define_print_and_forward_display! { p!(print_def_path(self.def_id, self.substs)); } - &'tcx ty::Const<'tcx> { - let u8 = cx.tcx().types.u8; - if let ty::FnDef(did, substs) = self.ty.sty { - p!(print_value_path(did, substs)); - return Ok(cx); - } - if let ConstValue::Unevaluated(did, substs) = self.val { - match cx.tcx().describe_def(did) { - | Some(Def::Static(_)) - | Some(Def::Const(_)) - | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)), - _ => if did.is_local() { - let span = cx.tcx().def_span(did); - if let Ok(snip) = cx.tcx().sess.source_map().span_to_snippet(span) { - p!(write("{}", snip)) - } else { - p!(write("_")) - } - } else { - p!(write("_")) - }, - } - return Ok(cx); - } - if let ConstValue::Infer(..) = self.val { - p!(write("_: "), print(self.ty)); - return Ok(cx); - } - if let ConstValue::Param(ParamConst { name, .. }) = self.val { - p!(write("{}", name)); - return Ok(cx); - } - if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = self.val { - match self.ty.sty { - ty::Bool => { - p!(write("{}", if bits == 0 { "false" } else { "true" })); - return Ok(cx); - }, - ty::Float(ast::FloatTy::F32) => { - p!(write("{}f32", Single::from_bits(bits))); - return Ok(cx); - }, - ty::Float(ast::FloatTy::F64) => { - p!(write("{}f64", Double::from_bits(bits))); - return Ok(cx); - }, - ty::Uint(ui) => { - p!(write("{}{}", bits, ui)); - return Ok(cx); - }, - ty::Int(i) =>{ - let ty = cx.tcx().lift_to_global(&self.ty).unwrap(); - let size = cx.tcx().layout_of(ty::ParamEnv::empty().and(ty)) - .unwrap() - .size; - p!(write("{}{}", sign_extend(bits, size) as i128, i)); - return Ok(cx); - }, - ty::Char => { - p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())); - return Ok(cx); - } - _ => {}, - } - } - if let ty::Ref(_, ref_ty, _) = self.ty.sty { - let byte_str = match (self.val, &ref_ty.sty) { - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { - let n = n.unwrap_usize(cx.tcx()); - Some(cx.tcx() - .alloc_map.lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&cx.tcx(), ptr, Size::from_bytes(n)).unwrap()) - }, - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - Some(&data.bytes[start..end]) - }, - (ConstValue::Slice { data, start, end }, ty::Str) => { - let slice = &data.bytes[start..end]; - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - p!(write("{:?}", s)); - return Ok(cx); - }, - _ => None, - }; - if let Some(byte_str) = byte_str { - p!(write("b\"")); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - cx.write_char(e as char)?; - } - } - p!(write("\"")); - return Ok(cx); - } - } - p!(write("{:?} : ", self.val), print(self.ty)); - } - ty::ParamTy { p!(write("{}", self.name)) } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index d50a9a1607b24..deebfbadec658 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -391,6 +391,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { type Region = Self; type Type = Self; type DynExistential = Self; + type Const = Self; fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx @@ -436,6 +437,13 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { Ok(self) } + fn print_const( + self, + ct: &'tcx ty::Const<'tcx>, + ) -> Result { + self.pretty_print_const(ct) + } + fn path_crate( mut self, cnum: CrateNum, From ed68cbeb9706b4248510145701e5e4d6056b082b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 3 May 2019 10:59:04 +0200 Subject: [PATCH 22/45] Break cycle during array length printing --- src/librustc/ty/print/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 19fbf498034be..4e3128bae7404 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -671,7 +671,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: if let Some(n) = sz.assert_usize(self.tcx()) { p!(write("{}", n)); } else { - p!(print(sz)); + p!(write("_")); } p!(write("]")) } From b4bbf9513ae7c4ca2299019e02f536b9aabefd0b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 7 May 2019 17:47:52 +0200 Subject: [PATCH 23/45] Fix rebase fallout --- src/librustc/ty/print/pretty.rs | 10 +++++----- src/librustc_mir/monomorphize/item.rs | 2 +- .../ui/const-generics/cannot-infer-const-args.stderr | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 4e3128bae7404..aea8baf4089c3 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1,5 +1,5 @@ use crate::hir; -use crate::hir::def::{Namespace, Def}; +use crate::hir::def::{Namespace, DefKind}; use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::middle::cstore::{ExternCrate, ExternCrateSource}; @@ -822,10 +822,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: return Ok(self); } if let ConstValue::Unevaluated(did, substs) = ct.val { - match self.tcx().describe_def(did) { - | Some(Def::Static(_)) - | Some(Def::Const(_)) - | Some(Def::AssociatedConst(_)) => p!(print_value_path(did, substs)), + match self.tcx().def_kind(did) { + | Some(DefKind::Static) + | Some(DefKind::Const) + | Some(DefKind::AssociatedConst) => p!(print_value_path(did, substs)), _ => if did.is_local() { let span = self.tcx().def_span(did); if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 999e7402afd93..f46c5ff9a2b8e 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { // as well as the unprintable types of constants (see `push_type_name` for more details). pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) { match c.val { - ConstValue::Scalar(..) | ConstValue::Slice(..) | ConstValue::ByRef(..) => { + ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => { // FIXME(const_generics): we could probably do a better job here. write!(output, "{:?}", c).unwrap() } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 5528c2fca6a3b..544cd05cdbebf 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -8,7 +8,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for `fn() -> usize {foo::<_>}` + | ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}` error: aborting due to previous error From 7902347d5e88681d1a691ecfc105cd3664cc22b3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 11 May 2019 15:48:47 +0200 Subject: [PATCH 24/45] Print types for unevaluated constants --- src/librustc/ty/print/pretty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index aea8baf4089c3..6e3f283a44338 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -831,10 +831,10 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { p!(write("{}", snip)) } else { - p!(write("_")) + p!(write("_: "), print(ct.ty)) } } else { - p!(write("_")) + p!(write("_: "), print(ct.ty)) }, } return Ok(self); From 15acc323ea17b2285383f4c14344267d3de99e42 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 11 May 2019 15:48:57 +0200 Subject: [PATCH 25/45] Update ui tests --- src/test/ui/pattern/const-pat-ice.stderr | 2 +- src/test/ui/symbol-names/impl2.rs | 14 ++++++++++++++ src/test/ui/symbol-names/impl2.stderr | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/symbol-names/impl2.rs create mode 100644 src/test/ui/symbol-names/impl2.stderr diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 260c2e04d74f7..fabaea0535f5b 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -1,4 +1,4 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5 +thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1085:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: internal compiler error: unexpected panic diff --git a/src/test/ui/symbol-names/impl2.rs b/src/test/ui/symbol-names/impl2.rs new file mode 100644 index 0000000000000..d48b182f2a200 --- /dev/null +++ b/src/test/ui/symbol-names/impl2.rs @@ -0,0 +1,14 @@ +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Foo { + fn baz(); +} + +impl Foo for [u8; 1 + 2] { + #[rustc_def_path] //~ ERROR def-path(<[u8; _] as Foo>::baz) + fn baz() { } +} + +fn main() { +} diff --git a/src/test/ui/symbol-names/impl2.stderr b/src/test/ui/symbol-names/impl2.stderr new file mode 100644 index 0000000000000..de26fed44139e --- /dev/null +++ b/src/test/ui/symbol-names/impl2.stderr @@ -0,0 +1,8 @@ +error: def-path(<[u8; _] as Foo>::baz) + --> $DIR/impl2.rs:9:5 + | +LL | #[rustc_def_path] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 6a08e4ee2c8162e9952eb3d1010393ad14e13a0e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 11 May 2019 16:04:14 +0200 Subject: [PATCH 26/45] Only print integers in symbol path's constants --- src/librustc_codegen_utils/symbol_names.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index deebfbadec658..33ed0bfe1e451 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -96,6 +96,7 @@ use rustc::ty::print::{PrettyPrinter, Printer, Print}; use rustc::ty::query::Providers; use rustc::ty::subst::{Kind, SubstsRef, UnpackedKind}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::mir::interpret::{ConstValue, Scalar}; use rustc::util::common::record_time; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt}; @@ -438,10 +439,17 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { } fn print_const( - self, + mut self, ct: &'tcx ty::Const<'tcx>, ) -> Result { - self.pretty_print_const(ct) + // only print integers + if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val { + if ct.ty.is_integral() { + return self.pretty_print_const(ct); + } + } + self.write_str("_")?; + Ok(self) } fn path_crate( From d29f0d23c3624047a3f3671a8e352783e8796373 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 12 May 2019 19:55:16 +0300 Subject: [PATCH 27/45] Move token tree related lexer state to a separate struct We only used a bunch of fields when tokenizing into a token tree, so let's move them out of the base lexer --- src/libsyntax/parse/lexer/mod.rs | 14 +--- src/libsyntax/parse/lexer/tokentrees.rs | 96 +++++++++++++++++-------- src/libsyntax/parse/mod.rs | 9 +-- 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 2882acb0e780c..60494a6a2bdc7 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -66,15 +66,7 @@ pub struct StringReader<'a> { span: Span, /// The raw source span which *does not* take `override_span` into account span_src_raw: Span, - /// Stack of open delimiters and their spans. Used for error message. - open_braces: Vec<(token::DelimToken, Span)>, - crate unmatched_braces: Vec, - /// The type and spans for all braces - /// - /// Used only for error recovery when arriving to EOF with mismatched braces. - matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, - crate override_span: Option, - last_unclosed_found_span: Option, + override_span: Option, } impl<'a> StringReader<'a> { @@ -254,11 +246,7 @@ impl<'a> StringReader<'a> { token: token::Eof, span: syntax_pos::DUMMY_SP, span_src_raw: syntax_pos::DUMMY_SP, - open_braces: Vec::new(), - unmatched_braces: Vec::new(), - matching_delim_spans: Vec::new(), override_span, - last_unclosed_found_span: None, } } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 0db36c84cdfeb..a6e176c02a09b 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,14 +1,42 @@ +use syntax_pos::Span; + use crate::print::pprust::token_to_string; use crate::parse::lexer::{StringReader, UnmatchedBrace}; use crate::parse::{token, PResult}; use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint}; impl<'a> StringReader<'a> { + crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + let mut tt_reader = TokenTreesReader { + string_reader: self, + open_braces: Vec::new(), + unmatched_braces: Vec::new(), + matching_delim_spans: Vec::new(), + last_unclosed_found_span: None, + }; + let res = tt_reader.parse_all_token_trees(); + (res, tt_reader.unmatched_braces) + } +} + +struct TokenTreesReader<'a> { + string_reader: StringReader<'a>, + /// Stack of open delimiters and their spans. Used for error message. + open_braces: Vec<(token::DelimToken, Span)>, + unmatched_braces: Vec, + /// The type and spans for all braces + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, + last_unclosed_found_span: Option, +} + +impl<'a> TokenTreesReader<'a> { // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. - crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { + fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut tts = Vec::new(); - while self.token != token::Eof { + while self.string_reader.token != token::Eof { tts.push(self.parse_token_tree()?); } @@ -19,7 +47,7 @@ impl<'a> StringReader<'a> { fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { let mut tts = vec![]; loop { - if let token::CloseDelim(..) = self.token { + if let token::CloseDelim(..) = self.string_reader.token { return TokenStream::new(tts); } @@ -34,11 +62,12 @@ impl<'a> StringReader<'a> { } fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { - let sm = self.sess.source_map(); - match self.token { + let sm = self.string_reader.sess.source_map(); + match self.string_reader.token { token::Eof => { let msg = "this file contains an un-closed delimiter"; - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.span(), msg); for &(_, sp) in &self.open_braces { err.span_label(sp, "un-closed delimiter"); } @@ -46,13 +75,12 @@ impl<'a> StringReader<'a> { if let Some((delim, _)) = self.open_braces.last() { if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter() .filter(|(d, open_sp, close_sp)| { - - if let Some(close_padding) = sm.span_to_margin(*close_sp) { - if let Some(open_padding) = sm.span_to_margin(*open_sp) { - return delim == d && close_padding != open_padding; + if let Some(close_padding) = sm.span_to_margin(*close_sp) { + if let Some(open_padding) = sm.span_to_margin(*open_sp) { + return delim == d && close_padding != open_padding; + } } - } - false + false }).next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close err.span_label( @@ -69,11 +97,11 @@ impl<'a> StringReader<'a> { }, token::OpenDelim(delim) => { // The span for beginning of the delimited section - let pre_span = self.span; + let pre_span = self.span(); // Parse the open delimiter. - self.open_braces.push((delim, self.span)); - self.real_token(); + self.open_braces.push((delim, self.span())); + self.string_reader.real_token(); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -81,9 +109,9 @@ impl<'a> StringReader<'a> { let tts = self.parse_token_trees_until_close_delim(); // Expand to cover the entire delimited token tree - let delim_span = DelimSpan::from_pair(pre_span, self.span); + let delim_span = DelimSpan::from_pair(pre_span, self.span()); - match self.token { + match self.string_reader.token { // Correct delimiter. token::CloseDelim(d) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); @@ -93,26 +121,26 @@ impl<'a> StringReader<'a> { self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.span), + (open_brace, open_brace_span, self.span()), ); } // Parse the close delimiter. - self.real_token(); + self.string_reader.real_token(); } // Incorrect delimiter. token::CloseDelim(other) => { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.span) { + if self.last_unclosed_found_span != Some(self.span()) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.span); + self.last_unclosed_found_span = Some(self.span()); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. if let Some(&(_, sp)) = self.open_braces.last() { unclosed_delimiter = Some(sp); }; - if let Some(current_padding) = sm.span_to_margin(self.span) { + if let Some(current_padding) = sm.span_to_margin(self.span()) { for (brace, brace_span) in &self.open_braces { if let Some(padding) = sm.span_to_margin(*brace_span) { // high likelihood of these two corresponding @@ -126,7 +154,7 @@ impl<'a> StringReader<'a> { self.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: other, - found_span: self.span, + found_span: self.span(), unclosed_span: unclosed_delimiter, candidate_span: candidate, }); @@ -142,7 +170,7 @@ impl<'a> StringReader<'a> { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` if !self.open_braces.iter().any(|&(b, _)| b == other) { - self.real_token(); + self.string_reader.real_token(); } } token::Eof => { @@ -162,22 +190,28 @@ impl<'a> StringReader<'a> { token::CloseDelim(_) => { // An unexpected closing delimiter (i.e., there is no // matching opening delimiter). - let token_str = token_to_string(&self.token); + let token_str = token_to_string(&self.string_reader.token); let msg = format!("unexpected close delimiter: `{}`", token_str); - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg); - err.span_label(self.span, "unexpected close delimiter"); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.span(), &msg); + err.span_label(self.span(), "unexpected close delimiter"); Err(err) }, _ => { - let tt = TokenTree::Token(self.span, self.token.clone()); + let tt = TokenTree::Token(self.span(), self.string_reader.token.clone()); // Note that testing for joint-ness here is done via the raw // source span as the joint-ness is a property of the raw source // rather than wanting to take `override_span` into account. - let raw = self.span_src_raw; - self.real_token(); - let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token); + let raw = self.string_reader.span_src_raw; + self.string_reader.real_token(); + let is_joint = raw.hi() == self.string_reader.span_src_raw.lo() + && token::is_op(&self.string_reader.token); Ok((tt, if is_joint { Joint } else { NonJoint })) } } } + + fn span(&self) -> Span { + self.string_reader.span + } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index be44b964ba5a7..1ddafb969c4b3 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -295,7 +295,7 @@ pub fn source_file_to_stream( } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from -/// parsing the token tream. +/// parsing the token stream. pub fn maybe_file_to_stream( sess: &ParseSess, source_file: Lrc, @@ -303,14 +303,15 @@ pub fn maybe_file_to_stream( ) -> Result<(TokenStream, Vec), Vec> { let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; srdr.real_token(); + let (token_trees, unmatched_braces) = srdr.into_token_trees(); - match srdr.parse_all_token_trees() { - Ok(stream) => Ok((stream, srdr.unmatched_braces)), + match token_trees { + Ok(stream) => Ok((stream, unmatched_braces)), Err(err) => { let mut buffer = Vec::with_capacity(1); err.buffer(&mut buffer); // Not using `emit_unclosed_delims` to use `db.buffer` - for unmatched in srdr.unmatched_braces { + for unmatched in unmatched_braces { let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( "incorrect close delimiter: `{}`", token_to_string(&token::Token::CloseDelim(unmatched.found_delim)), From b91e0a378690871fa744768f38d42bd90830bcd0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 13 May 2019 12:06:37 +0300 Subject: [PATCH 28/45] move span and token to tt reader --- src/libsyntax/parse/lexer/mod.rs | 12 ----- src/libsyntax/parse/lexer/tokentrees.rs | 60 ++++++++++++++----------- src/libsyntax/parse/mod.rs | 3 +- 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 60494a6a2bdc7..9caa9ea807c1d 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -62,10 +62,6 @@ pub struct StringReader<'a> { // cache a direct reference to the source text, so that we don't have to // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time. src: Lrc, - token: token::Token, - span: Span, - /// The raw source span which *does not* take `override_span` into account - span_src_raw: Span, override_span: Option, } @@ -113,8 +109,6 @@ impl<'a> StringReader<'a> { sp: self.peek_span, }; self.advance_token()?; - self.span_src_raw = self.peek_span_src_raw; - Ok(ret_val) } @@ -151,9 +145,6 @@ impl<'a> StringReader<'a> { } } - self.token = t.tok.clone(); - self.span = t.sp; - Ok(t) } @@ -243,9 +234,6 @@ impl<'a> StringReader<'a> { peek_span_src_raw: syntax_pos::DUMMY_SP, src, fatal_errs: Vec::new(), - token: token::Eof, - span: syntax_pos::DUMMY_SP, - span_src_raw: syntax_pos::DUMMY_SP, override_span, } } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index a6e176c02a09b..1070d6dcb1b34 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -9,6 +9,8 @@ impl<'a> StringReader<'a> { crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { string_reader: self, + token: token::Eof, + span: syntax_pos::DUMMY_SP, open_braces: Vec::new(), unmatched_braces: Vec::new(), matching_delim_spans: Vec::new(), @@ -21,6 +23,8 @@ impl<'a> StringReader<'a> { struct TokenTreesReader<'a> { string_reader: StringReader<'a>, + token: token::Token, + span: Span, /// Stack of open delimiters and their spans. Used for error message. open_braces: Vec<(token::DelimToken, Span)>, unmatched_braces: Vec, @@ -36,7 +40,8 @@ impl<'a> TokenTreesReader<'a> { fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut tts = Vec::new(); - while self.string_reader.token != token::Eof { + self.real_token(); + while self.token != token::Eof { tts.push(self.parse_token_tree()?); } @@ -47,7 +52,7 @@ impl<'a> TokenTreesReader<'a> { fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { let mut tts = vec![]; loop { - if let token::CloseDelim(..) = self.string_reader.token { + if let token::CloseDelim(..) = self.token { return TokenStream::new(tts); } @@ -63,11 +68,11 @@ impl<'a> TokenTreesReader<'a> { fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { let sm = self.string_reader.sess.source_map(); - match self.string_reader.token { + match self.token { token::Eof => { let msg = "this file contains an un-closed delimiter"; let mut err = self.string_reader.sess.span_diagnostic - .struct_span_err(self.span(), msg); + .struct_span_err(self.span, msg); for &(_, sp) in &self.open_braces { err.span_label(sp, "un-closed delimiter"); } @@ -97,11 +102,11 @@ impl<'a> TokenTreesReader<'a> { }, token::OpenDelim(delim) => { // The span for beginning of the delimited section - let pre_span = self.span(); + let pre_span = self.span; // Parse the open delimiter. - self.open_braces.push((delim, self.span())); - self.string_reader.real_token(); + self.open_braces.push((delim, self.span)); + self.real_token(); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -109,9 +114,9 @@ impl<'a> TokenTreesReader<'a> { let tts = self.parse_token_trees_until_close_delim(); // Expand to cover the entire delimited token tree - let delim_span = DelimSpan::from_pair(pre_span, self.span()); + let delim_span = DelimSpan::from_pair(pre_span, self.span); - match self.string_reader.token { + match self.token { // Correct delimiter. token::CloseDelim(d) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); @@ -121,26 +126,26 @@ impl<'a> TokenTreesReader<'a> { self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.span()), + (open_brace, open_brace_span, self.span), ); } // Parse the close delimiter. - self.string_reader.real_token(); + self.real_token(); } // Incorrect delimiter. token::CloseDelim(other) => { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.span()) { + if self.last_unclosed_found_span != Some(self.span) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.span()); + self.last_unclosed_found_span = Some(self.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. if let Some(&(_, sp)) = self.open_braces.last() { unclosed_delimiter = Some(sp); }; - if let Some(current_padding) = sm.span_to_margin(self.span()) { + if let Some(current_padding) = sm.span_to_margin(self.span) { for (brace, brace_span) in &self.open_braces { if let Some(padding) = sm.span_to_margin(*brace_span) { // high likelihood of these two corresponding @@ -154,7 +159,7 @@ impl<'a> TokenTreesReader<'a> { self.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: other, - found_span: self.span(), + found_span: self.span, unclosed_span: unclosed_delimiter, candidate_span: candidate, }); @@ -170,7 +175,7 @@ impl<'a> TokenTreesReader<'a> { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` if !self.open_braces.iter().any(|&(b, _)| b == other) { - self.string_reader.real_token(); + self.real_token(); } } token::Eof => { @@ -190,28 +195,31 @@ impl<'a> TokenTreesReader<'a> { token::CloseDelim(_) => { // An unexpected closing delimiter (i.e., there is no // matching opening delimiter). - let token_str = token_to_string(&self.string_reader.token); + let token_str = token_to_string(&self.token); let msg = format!("unexpected close delimiter: `{}`", token_str); let mut err = self.string_reader.sess.span_diagnostic - .struct_span_err(self.span(), &msg); - err.span_label(self.span(), "unexpected close delimiter"); + .struct_span_err(self.span, &msg); + err.span_label(self.span, "unexpected close delimiter"); Err(err) }, _ => { - let tt = TokenTree::Token(self.span(), self.string_reader.token.clone()); + let tt = TokenTree::Token(self.span, self.token.clone()); // Note that testing for joint-ness here is done via the raw // source span as the joint-ness is a property of the raw source // rather than wanting to take `override_span` into account. - let raw = self.string_reader.span_src_raw; - self.string_reader.real_token(); - let is_joint = raw.hi() == self.string_reader.span_src_raw.lo() - && token::is_op(&self.string_reader.token); + let raw = self.string_reader.peek_span_src_raw; + self.real_token(); + let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo() + && token::is_op(&self.token); Ok((tt, if is_joint { Joint } else { NonJoint })) } } } - fn span(&self) -> Span { - self.string_reader.span + fn real_token(&mut self) { + let t = self.string_reader.real_token(); + self.token = t.tok; + self.span = t.sp; } } + diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1ddafb969c4b3..4a9a7aec6adde 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -301,8 +301,7 @@ pub fn maybe_file_to_stream( source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; - srdr.real_token(); + let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; let (token_trees, unmatched_braces) = srdr.into_token_trees(); match token_trees { From e249f2e526cca687b78a766769c481cfb638f02e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 13 May 2019 14:30:18 +0300 Subject: [PATCH 29/45] move raw span to tt reader See https://github.com/rust-lang/rust/pull/50838/files#r283296243 for explanation how jointness checking works with *next* pair --- src/libsyntax/parse/lexer/tokentrees.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 1070d6dcb1b34..4bfc5bb16c0bb 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -207,6 +207,8 @@ impl<'a> TokenTreesReader<'a> { // Note that testing for joint-ness here is done via the raw // source span as the joint-ness is a property of the raw source // rather than wanting to take `override_span` into account. + // Additionally, we actually check if the *next* pair of tokens + // is joint, but this is equivalent to checking the current pair. let raw = self.string_reader.peek_span_src_raw; self.real_token(); let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo() @@ -222,4 +224,3 @@ impl<'a> TokenTreesReader<'a> { self.span = t.sp; } } - From 19a9109d332f596f77bb2b4e740650775193e496 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 21:49:52 +0000 Subject: [PATCH 30/45] Remove unused parameter from in(_opt)?_scope --- src/librustc_mir/build/block.rs | 12 ++++++------ src/librustc_mir/build/expr/as_operand.rs | 2 +- src/librustc_mir/build/expr/as_place.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/mod.rs | 4 ++-- src/librustc_mir/build/scope.rs | 8 ++++---- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 7469aceee3a9e..d93223a4292c4 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -23,8 +23,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { safety_mode } = self.hir.mirror(ast_block); - self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| { - this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| { + self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), move |this| { + this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { // This is a `break`-able block let exit_block = this.cfg.start_new_block(); @@ -83,9 +83,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); unpack!(block = this.in_opt_scope( - opt_destruction_scope.map(|de|(de, source_info)), block, |this| { + opt_destruction_scope.map(|de|(de, source_info)), |this| { let si = (scope, source_info); - this.in_scope(si, LintLevel::Inherited, block, |this| { + this.in_scope(si, LintLevel::Inherited, |this| { let expr = this.hir.mirror(expr); this.stmt_expr(block, expr, Some(stmt_span)) }) @@ -128,9 +128,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Some((None, initializer_span)), ); unpack!(block = this.in_opt_scope( - opt_destruction_scope.map(|de|(de, source_info)), block, |this| { + opt_destruction_scope.map(|de|(de, source_info)), |this| { let scope = (init_scope, source_info); - this.in_scope(scope, lint_level, block, |this| { + this.in_scope(scope, lint_level, |this| { this.expr_into_pattern(block, pattern, init) }) })); diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index e354a2ee8160b..ed80cb1a16369 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); - return this.in_scope(region_scope, lint_level, block, |this| { + return this.in_scope(region_scope, lint_level, |this| { this.as_operand(block, scope, value) }); } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 5f444d4ceeb88..a956eacb0699f 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { region_scope, lint_level, value, - } => this.in_scope((region_scope, source_info), lint_level, block, |this| { + } => this.in_scope((region_scope, source_info), lint_level, |this| { if mutability == Mutability::Not { this.as_read_only_place(block, value) } else { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index fbc4835a6557b..a0b504a99de9a 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, block, |this| { + this.in_scope(region_scope, lint_level, |this| { this.as_rvalue(block, scope, value) }) } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index cba771f27065d..c60e197010067 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -43,7 +43,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } = expr.kind { - return this.in_scope((region_scope, source_info), lint_level, block, |this| { + return this.in_scope((region_scope, source_info), lint_level, |this| { this.as_temp(block, temp_lifetime, value, mutability) }); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 15795a64e3b7d..7bdfdf0b0895f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, block, |this| { + this.in_scope(region_scope, lint_level, |this| { this.into(destination, block, value) }) } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index b58914b017fd4..ac690f89264bf 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -29,7 +29,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value, } => { let value = this.hir.mirror(value); - this.in_scope((region_scope, source_info), lint_level, block, |this| { + this.in_scope((region_scope, source_info), lint_level, |this| { this.stmt_expr(block, value, opt_stmt_span) }) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 16ab233bd2e36..b432ed47d0b8d 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -702,13 +702,13 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let mut block = START_BLOCK; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); - unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| { + unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { if should_abort_on_panic(tcx, fn_def_id, abi) { builder.schedule_abort(); } let arg_scope_s = (arg_scope, source_info); - unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| { + unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(block, &arguments, arg_scope, &body.value) })); // Attribute epilogue to function's closing brace diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 4aa463b37ab77..471304012c9a8 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -279,13 +279,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn in_opt_scope(&mut self, opt_scope: Option<(region::Scope, SourceInfo)>, - mut block: BasicBlock, f: F) -> BlockAnd where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { - debug!("in_opt_scope(opt_scope={:?}, block={:?})", opt_scope, block); + debug!("in_opt_scope(opt_scope={:?})", opt_scope); if let Some(region_scope) = opt_scope { self.push_scope(region_scope); } + let mut block; let rv = unpack!(block = f(self)); if let Some(region_scope) = opt_scope { unpack!(block = self.pop_scope(region_scope, block)); @@ -299,12 +299,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn in_scope(&mut self, region_scope: (region::Scope, SourceInfo), lint_level: LintLevel, - mut block: BasicBlock, f: F) -> BlockAnd where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { - debug!("in_scope(region_scope={:?}, block={:?})", region_scope, block); + debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; let tcx = self.hir.tcx(); if let LintLevel::Explicit(current_hir_id) = lint_level { @@ -330,6 +329,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } self.push_scope(region_scope); + let mut block; let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(region_scope, block)); self.source_scope = source_scope; From 63f47b798f23f4d8fc0f5ca9feb252cf1328cc98 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 22:54:29 +0000 Subject: [PATCH 31/45] Give match arms an HirId and a Span --- src/librustc/hir/intravisit.rs | 1 + src/librustc/hir/lowering.rs | 8 ++++++++ src/librustc/hir/map/collector.rs | 10 ++++++++++ src/librustc/hir/map/mod.rs | 7 +++++++ src/librustc/hir/mod.rs | 4 ++++ src/librustc/hir/print.rs | 2 +- src/librustc_passes/hir_stats.rs | 2 +- src/librustc_typeck/check/_match.rs | 15 +++++++++------ src/libsyntax/ast.rs | 1 + src/libsyntax/ext/build.rs | 3 ++- src/libsyntax/mut_visit.rs | 6 +++++- src/libsyntax/parse/parser.rs | 4 ++++ 12 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 38d6d710868c0..517c99f99efea 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1102,6 +1102,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { + visitor.visit_id(arm.hir_id); walk_list!(visitor, visit_pat, &arm.pats); if let Some(ref g) = arm.guard { match g { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd0d13d8f5a6a..75e1003374940 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1312,7 +1312,10 @@ impl<'a> LoweringContext<'a> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::Arm { + hir_id, attrs: self.lower_attrs(&arm.attrs), pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), guard: match arm.guard { @@ -1320,6 +1323,7 @@ impl<'a> LoweringContext<'a> { _ => None, }, body: P(self.lower_expr(&arm.body)), + span: arm.span, } } @@ -5022,10 +5026,14 @@ impl<'a> LoweringContext<'a> { // Helper methods for building HIR. fn arm(&mut self, pats: hir::HirVec>, expr: P) -> hir::Arm { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::Arm { + hir_id, attrs: hir_vec![], pats, guard: None, + span: expr.span, body: expr, } } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index a1cf338bf12ea..accf8adcf9bdb 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -430,6 +430,16 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_arm(&mut self, arm: &'hir Arm) { + let node = Node::Arm(arm); + + self.insert(arm.span, arm.hir_id, node); + + self.with_parent(arm.hir_id, |this| { + intravisit::walk_arm(this, arm); + }); + } + fn visit_anon_const(&mut self, constant: &'hir AnonConst) { self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b8ee98551a20e..1da23dd8919d4 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -373,6 +373,7 @@ impl<'hir> Map<'hir> { Node::Pat(_) | Node::Binding(_) | Node::Local(_) | + Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) | Node::Block(_) | @@ -1000,6 +1001,7 @@ impl<'hir> Map<'hir> { Some(Node::Field(ref f)) => Some(&f.attrs[..]), Some(Node::Expr(ref e)) => Some(&*e.attrs), Some(Node::Stmt(ref s)) => Some(s.node.attrs()), + Some(Node::Arm(ref a)) => Some(&*a.attrs), Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), // Unit/tuple structs/variants take the attributes straight from // the struct/variant definition. @@ -1073,6 +1075,7 @@ impl<'hir> Map<'hir> { Some(Node::TraitRef(tr)) => tr.path.span, Some(Node::Binding(pat)) => pat.span, Some(Node::Pat(pat)) => pat.span, + Some(Node::Arm(arm)) => arm.span, Some(Node::Block(block)) => block.span, Some(Node::Ctor(..)) => match self.find_by_hir_id( self.get_parent_node_by_hir_id(hir_id)) @@ -1288,6 +1291,7 @@ impl<'a> print::State<'a> { Node::TraitRef(a) => self.print_trait_ref(&a), Node::Binding(a) | Node::Pat(a) => self.print_pat(&a), + Node::Arm(a) => self.print_arm(&a), Node::Block(a) => { use syntax::print::pprust::PrintState; @@ -1417,6 +1421,9 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Pat(_)) => { format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } + Some(Node::Arm(_)) => { + format!("arm {}{}", map.hir_to_pretty_string(id), id_str) + } Some(Node::Block(_)) => { format!("block {}{}", map.hir_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f407be4e87b82..43b9487dac582 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1228,6 +1228,9 @@ pub struct Local { /// ` (if ) => `. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct Arm { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub span: Span, pub attrs: HirVec, /// Multiple patterns can be combined with `|` pub pats: HirVec>, @@ -2656,6 +2659,7 @@ pub enum Node<'hir> { TraitRef(&'hir TraitRef), Binding(&'hir Pat), Pat(&'hir Pat), + Arm(&'hir Arm), Block(&'hir Block), Local(&'hir Local), MacroDef(&'hir MacroDef), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 8a9028e544391..ef9fee5cab694 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1862,7 +1862,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> { + pub fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> { // I have no idea why this check is necessary, but here it // is :( if arm.attrs.is_empty() { diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index c74314ce0c4b5..0088c97679c66 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -149,7 +149,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } fn visit_arm(&mut self, a: &'v hir::Arm) { - self.record("Arm", Id::None, a); + self.record("Arm", Id::Node(a.hir_id), a); hir_visit::walk_arm(self, a) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a69f639e8941f..99b350b833274 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -781,14 +781,17 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { use hir::Node::{Block, Item, Local}; - let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(hir_id), - )); + let hir = self.tcx.hir(); + let arm_id = hir.get_parent_node_by_hir_id(hir_id); + let match_id = hir.get_parent_node_by_hir_id(arm_id); + let containing_id = hir.get_parent_node_by_hir_id(match_id); + + let node = hir.get_by_hir_id(containing_id); if let Block(block) = node { // check that the body's parent is an fn - let parent = self.tcx.hir().get_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(block.hir_id), + let parent = hir.get_by_hir_id( + hir.get_parent_node_by_hir_id( + hir.get_parent_node_by_hir_id(block.hir_id), ), ); if let (Some(expr), Item(hir::Item { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d12240655e628..14c77e589a6a1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -912,6 +912,7 @@ pub struct Arm { pub pats: Vec>, pub guard: Option, pub body: P, + pub span: Span, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index d24106f697e19..cb967a76822c9 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -890,12 +890,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - fn arm(&self, _span: Span, pats: Vec>, expr: P) -> ast::Arm { + fn arm(&self, span: Span, pats: Vec>, expr: P) -> ast::Arm { ast::Arm { attrs: vec![], pats, guard: None, body: expr, + span, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f587e63e12b94..cb21014ec7646 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -392,11 +392,15 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm(Arm { attrs, pats, guard, body }: &mut Arm, vis: &mut T) { +pub fn noop_visit_arm( + Arm { attrs, pats, guard, body, span }: &mut Arm, + vis: &mut T, +) { visit_attrs(attrs, vis); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_guard(guard)); vis.visit_expr(body); + vis.visit_span(span); } pub fn noop_visit_guard(g: &mut Guard, vis: &mut T) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2d6c8c5407583..1c897f1bda944 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4041,6 +4041,7 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; + let lo = self.span; let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { Some(Guard::If(self.parse_expr()?)) @@ -4060,6 +4061,8 @@ impl<'a> Parser<'a> { let require_comma = classify::expr_requires_semi_to_be_stmt(&expr) && self.token != token::CloseDelim(token::Brace); + let hi = self.span; + if require_comma { let cm = self.sess.source_map(); self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) @@ -4103,6 +4106,7 @@ impl<'a> Parser<'a> { pats, guard, body: expr, + span: lo.to(hi), }) } From 7a53e03eef488d8433091b6b6271382e7dbd60af Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 30 Mar 2019 23:00:07 +0000 Subject: [PATCH 32/45] Respect lint attributes on match arms --- src/librustc/lint/mod.rs | 6 ++++++ src/test/ui/lint/lint-match-arms.rs | 18 ++++++++++++++++++ src/test/ui/lint/lint-match-arms.stderr | 14 ++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/test/ui/lint/lint-match-arms.rs create mode 100644 src/test/ui/lint/lint-match-arms.stderr diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 68b65f9b4a1cc..3682552d22d75 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -849,6 +849,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> { }) } + fn visit_arm(&mut self, a: &'tcx hir::Arm) { + self.with_lint_attrs(a.hir_id, &a.attrs, |builder| { + intravisit::walk_arm(builder, a); + }) + } + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |builder| { intravisit::walk_trait_item(builder, trait_item); diff --git a/src/test/ui/lint/lint-match-arms.rs b/src/test/ui/lint/lint-match-arms.rs new file mode 100644 index 0000000000000..2c471a61054b2 --- /dev/null +++ b/src/test/ui/lint/lint-match-arms.rs @@ -0,0 +1,18 @@ +fn deny_on_arm() { + match 0 { + #[deny(unused_variables)] + //~^ NOTE lint level defined here + y => (), + //~^ ERROR unused variable + } +} + +#[deny(unused_variables)] +fn allow_on_arm() { + match 0 { + #[allow(unused_variables)] + y => (), // OK + } +} + +fn main() {} diff --git a/src/test/ui/lint/lint-match-arms.stderr b/src/test/ui/lint/lint-match-arms.stderr new file mode 100644 index 0000000000000..e4e3adab0a9b2 --- /dev/null +++ b/src/test/ui/lint/lint-match-arms.stderr @@ -0,0 +1,14 @@ +error: unused variable: `y` + --> $DIR/lint-match-arms.rs:5:9 + | +LL | y => (), + | ^ help: consider prefixing with an underscore: `_y` + | +note: lint level defined here + --> $DIR/lint-match-arms.rs:3:16 + | +LL | #[deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From ca8db942fc551aac89fcf373863768e8280f12cc Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 2 Apr 2019 22:29:28 +0100 Subject: [PATCH 33/45] Handle the visibility/lint scope distinction better * Don't generate an extra lint scope for each `let` statement. * Place match guards inside the visiblility scope of the bindings for their arm. --- src/librustc/hir/lowering.rs | 8 ++--- src/librustc_mir/build/block.rs | 36 +++++++++++-------- src/librustc_mir/build/matches/mod.rs | 27 ++++---------- src/librustc_mir/build/mod.rs | 11 +++--- src/librustc_mir/hair/mod.rs | 11 ++---- src/test/mir-opt/box_expr.rs | 4 +-- src/test/mir-opt/issue-41110.rs | 7 ++-- src/test/mir-opt/issue-49232.rs | 4 +-- .../mir-opt/packed-struct-drop-aligned.rs | 4 +-- 9 files changed, 45 insertions(+), 67 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 75e1003374940..05aa7690663e1 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1312,10 +1312,8 @@ impl<'a> LoweringContext<'a> { } fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { - let LoweredNodeId { node_id: _, hir_id } = self.next_id(); - hir::Arm { - hir_id, + hir_id: self.next_id(), attrs: self.lower_attrs(&arm.attrs), pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), guard: match arm.guard { @@ -5026,10 +5024,8 @@ impl<'a> LoweringContext<'a> { // Helper methods for building HIR. fn arm(&mut self, pats: hir::HirVec>, expr: P) -> hir::Arm { - let LoweredNodeId { node_id: _, hir_id } = self.next_id(); - hir::Arm { - hir_id, + hir_id: self.next_id(), attrs: hir_vec![], pats, guard: None, diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index d93223a4292c4..b5bab1585342a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -113,31 +113,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let remainder_span = remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree); - let scope; + let visibility_scope = + Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); // Evaluate the initializer, if present. if let Some(init) = initializer { let initializer_span = init.span(); - scope = this.declare_bindings( - None, - remainder_span, - lint_level, - &pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); unpack!(block = this.in_opt_scope( opt_destruction_scope.map(|de|(de, source_info)), |this| { let scope = (init_scope, source_info); this.in_scope(scope, lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + &pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); this.expr_into_pattern(block, pattern, init) }) })); } else { - scope = this.declare_bindings( - None, remainder_span, lint_level, &pattern, - ArmHasGuard(false), None); + let scope = (init_scope, source_info); + unpack!(this.in_scope(scope, lint_level, |this| { + this.declare_bindings( + visibility_scope, + remainder_span, + &pattern, + ArmHasGuard(false), + None, + ); + block.unit() + })); debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_bindings( @@ -149,8 +157,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }) } - // Enter the source scope, after evaluating the initializer. - if let Some(source_scope) = scope { + // Enter the visibility scope, after evaluating the initializer. + if let Some(source_scope) = visibility_scope { this.source_scope = source_scope; } } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 51d5c96083d8f..93a702dc44e25 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -259,12 +259,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let scope = self.declare_bindings( None, body.span, - LintLevel::Inherited, &arm.patterns[0], ArmHasGuard(arm.guard.is_some()), Some((Some(&scrutinee_place), scrutinee_span)), ); + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } + for candidate in candidates { self.bind_and_guard_matched_candidate( candidate, @@ -275,9 +278,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); } - if let Some(source_scope) = scope { - self.source_scope = source_scope; - } unpack!(arm_block = self.into(destination, arm_block, body)); @@ -489,33 +489,20 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &mut self, mut visibility_scope: Option, scope_span: Span, - lint_level: LintLevel, pattern: &Pattern<'tcx>, has_guard: ArmHasGuard, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { - assert!( - !(visibility_scope.is_some() && lint_level.is_explicit()), - "can't have both a visibility and a lint scope at the same time" - ); - let mut scope = self.source_scope; debug!("declare_bindings: pattern={:?}", pattern); self.visit_bindings( &pattern, UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { - // If we have lints, create a new source scope - // that marks the lints for the locals. See the comment - // on the `source_info` field for why this is needed. - if lint_level.is_explicit() { - scope = this.new_source_scope(scope_span, lint_level, None); - } - visibility_scope = Some(this.new_source_scope(scope_span, - LintLevel::Inherited, - None)); + visibility_scope = + Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); } - let source_info = SourceInfo { span, scope }; + let source_info = SourceInfo { span, this.source_scope }; let visibility_scope = visibility_scope.unwrap(); this.declare_binding( source_info, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b432ed47d0b8d..8cd4ac0ad3ade 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -945,10 +945,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.var_indices.insert(var, LocalsForNode::One(local)); } _ => { - scope = self.declare_bindings(scope, ast_body.span, - LintLevel::Inherited, &pattern, - matches::ArmHasGuard(false), - Some((Some(&place), span))); + scope = self.declare_bindings( + scope, + ast_body.span, + &pattern, + matches::ArmHasGuard(false), + Some((Some(&place), span)), + ); unpack!(block = self.place_into_pattern(block, pattern, &place, false)); } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index d4f139e103a64..8e19913f4df26 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -31,15 +31,6 @@ pub enum LintLevel { Explicit(hir::HirId) } -impl LintLevel { - pub fn is_explicit(self) -> bool { - match self { - LintLevel::Inherited => false, - LintLevel::Explicit(_) => true - } - } -} - #[derive(Clone, Debug)] pub struct Block<'tcx> { pub targeted_by_break: bool, @@ -311,6 +302,8 @@ pub struct Arm<'tcx> { pub guard: Option>, pub body: ExprRef<'tcx>, pub lint_level: LintLevel, + pub scope: region::Scope, + pub span: Span, } #[derive(Clone, Debug)] diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index d4852db6d475e..ee6adfefe3e36 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -22,13 +22,11 @@ impl Drop for S { // END RUST SOURCE // START rustc.main.ElaborateDrops.before.mir // let mut _0: (); +// let _1: std::boxed::Box; // let mut _2: std::boxed::Box; // let mut _3: (); // let mut _4: std::boxed::Box; // scope 1 { -// let _1: std::boxed::Box; -// } -// scope 2 { // } // bb0: { // StorageLive(_1); diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index 023440af0eb10..0b678be2ab319 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -29,27 +29,24 @@ impl S { // END RUST SOURCE // START rustc.main.ElaborateDrops.after.mir // let mut _0: (); +// let _1: (); // let mut _2: S; // let mut _3: S; // let mut _4: S; // let mut _5: bool; // scope 1 { -// let _1: (); -// } -// scope 2 { // } // ... // bb0: { // END rustc.main.ElaborateDrops.after.mir // START rustc.test.ElaborateDrops.after.mir // let mut _0: (); +// let _1: S; // let mut _3: (); // let mut _4: S; // let mut _5: S; // let mut _6: bool; // ... -// let _1: S; -// ... // let mut _2: S; // ... // bb0: { diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 29446d2ecc23e..3910183dee789 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -18,14 +18,12 @@ fn main() { // fn main() -> (){ // let mut _0: (); // let mut _1: (); +// let _2: i32; // let mut _3: bool; // let mut _4: !; // let mut _5: (); // let mut _6: &i32; // scope 1 { -// let _2: i32; -// } -// scope 2 { // } // bb0: { // goto -> bb1; diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 7e8c58e64c28d..da73cc96348f0 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -18,15 +18,13 @@ impl Drop for Droppy { // START rustc.main.EraseRegions.before.mir // fn main() -> () { // let mut _0: (); +// let mut _1: Packed; // let mut _2: Aligned; // let mut _3: Droppy; // let mut _4: Aligned; // let mut _5: Droppy; // let mut _6: Aligned; // scope 1 { -// let mut _1: Packed; -// } -// scope 2 { // } // // bb0: { From 531c2f8479c2d5e3078190ef37db524727ecd0ab Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Apr 2019 19:21:51 +0100 Subject: [PATCH 34/45] Give match arms a drop/region scope Also give arms the correct lint scope in MIR. --- src/librustc/cfg/construct.rs | 10 +- src/librustc/middle/region.rs | 34 +++-- src/librustc_mir/build/matches/mod.rs | 87 +++++++----- src/librustc_mir/build/scope.rs | 84 +++++++++++- src/librustc_mir/hair/cx/expr.rs | 8 +- src/test/mir-opt/match_false_edges.rs | 126 +++++++++++------- src/test/mir-opt/match_test.rs | 33 ++--- src/test/mir-opt/remove_fake_borrows.rs | 50 +++---- src/test/ui/lint/lint-unused-mut-variables.rs | 8 ++ .../ui/lint/lint-unused-mut-variables.stderr | 4 +- 10 files changed, 299 insertions(+), 145 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 2e54165be1f1b..ef0d4be268eaf 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -419,7 +419,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { for arm in arms { // Add an exit node for when we've visited all the // patterns and the guard (if there is one) in the arm. - let arm_exit = self.add_dummy_node(&[]); + let bindings_exit = self.add_dummy_node(&[]); for pat in &arm.pats { // Visit the pattern, coming from the discriminant exit @@ -453,14 +453,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // Add an edge from the exit of this pattern to the // exit of the arm - self.add_contained_edge(pat_exit, arm_exit); + self.add_contained_edge(pat_exit, bindings_exit); } // Visit the body of this arm - let body_exit = self.expr(&arm.body, arm_exit); + let body_exit = self.expr(&arm.body, bindings_exit); + + let arm_exit = self.add_ast_node(arm.hir_id.local_id, &[body_exit]); // Link the body to the exit of the expression - self.add_contained_edge(body_exit, expr_exit); + self.add_contained_edge(arm_exit, expr_exit); } expr_exit diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 8ef4e9ac8f45f..4f70d72cbffa8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -119,18 +119,18 @@ impl fmt::Debug for Scope { pub enum ScopeData { Node, - // Scope of the call-site for a function or closure - // (outlives the arguments as well as the body). + /// Scope of the call-site for a function or closure + /// (outlives the arguments as well as the body). CallSite, - // Scope of arguments passed to a function or closure - // (they outlive its body). + /// Scope of arguments passed to a function or closure + /// (they outlive its body). Arguments, - // Scope of destructors for temporaries of node-id. + /// Scope of destructors for temporaries of node-id. Destruction, - // Scope following a `let id = expr;` binding in a block. + /// Scope following a `let id = expr;` binding in a block. Remainder(FirstStatementIndex) } @@ -152,11 +152,11 @@ newtype_index! { /// /// * The subscope with `first_statement_index == 1` is scope of `c`, /// and thus does not include EXPR_2, but covers the `...`. - pub struct FirstStatementIndex { .. } + pub struct FirstStatementIndex { + derive [HashStable] + } } -impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private }); - // compilation error if size of `ScopeData` is not the same as a `u32` static_assert!(ASSERT_SCOPE_DATA: mem::size_of::() == 4); @@ -814,6 +814,16 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: } fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) { + let prev_cx = visitor.cx; + + visitor.enter_scope( + Scope { + id: arm.hir_id.local_id, + data: ScopeData::Node, + } + ); + visitor.cx.var_parent = visitor.cx.parent; + visitor.terminating_scopes.insert(arm.body.hir_id.local_id); if let Some(hir::Guard::If(ref expr)) = arm.guard { @@ -821,6 +831,8 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: & } intravisit::walk_arm(visitor, arm); + + visitor.cx = prev_cx; } fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) { @@ -893,10 +905,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: terminating(body.hir_id.local_id); } - hir::ExprKind::Match(..) => { - visitor.cx.var_parent = visitor.cx.parent; - } - hir::ExprKind::DropTemps(ref expr) => { // `DropTemps(expr)` does not denote a conditional scope. // Rather, we want to achieve the same behavior as `{ let _t = expr; _t }`. diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 93a702dc44e25..091e39630d6cb 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -12,6 +12,7 @@ use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use crate::hair::{self, *}; use rustc::hir::HirId; use rustc::mir::*; +use rustc::middle::region; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc::ty::layout::VariantIdx; use rustc_data_structures::bit_set::BitSet; @@ -251,37 +252,39 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Step 5. Create everything else: the guards and the arms. - let outer_source_info = self.source_info(span); let arm_end_blocks: Vec<_> = arm_candidates.into_iter().map(|(arm, candidates)| { - let mut arm_block = self.cfg.start_new_block(); - - let body = self.hir.mirror(arm.body.clone()); - let scope = self.declare_bindings( - None, - body.span, - &arm.patterns[0], - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } - - for candidate in candidates { - self.bind_and_guard_matched_candidate( - candidate, - arm.guard.clone(), - arm_block, - &fake_borrow_temps, - scrutinee_span, + let arm_source_info = self.source_info(arm.span); + let region_scope = (arm.scope, arm_source_info); + self.in_scope(region_scope, arm.lint_level, |this| { + let arm_block = this.cfg.start_new_block(); + + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.patterns[0], + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), ); - } + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } - unpack!(arm_block = self.into(destination, arm_block, body)); + for candidate in candidates { + this.clear_top_scope(arm.scope); + this.bind_and_guard_matched_candidate( + candidate, + arm.guard.clone(), + arm_block, + &fake_borrow_temps, + scrutinee_span, + region_scope, + ); + } - arm_block + this.into(destination, arm_block, body) + }) }).collect(); // all the arm blocks will rejoin here @@ -289,7 +292,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for arm_block in arm_end_blocks { self.cfg.terminate( - arm_block, + unpack!(arm_block), outer_source_info, TerminatorKind::Goto { target: end_block }, ); @@ -502,7 +505,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { visibility_scope = Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); } - let source_info = SourceInfo { span, this.source_scope }; + let source_info = SourceInfo { span, scope: this.source_scope }; let visibility_scope = visibility_scope.unwrap(); this.declare_binding( source_info, @@ -1315,6 +1318,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm_block: BasicBlock, fake_borrows: &Vec<(&Place<'tcx>, Local)>, scrutinee_span: Span, + region_scope: (region::Scope, SourceInfo), ) { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -1497,17 +1501,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // // and that is clearly not correct. let post_guard_block = self.cfg.start_new_block(); + let otherwise_post_guard_block = self.cfg.start_new_block(); self.cfg.terminate( block, source_info, TerminatorKind::if_( self.hir.tcx(), - cond, + cond.clone(), post_guard_block, - candidate.otherwise_block.unwrap() + otherwise_post_guard_block, ), ); + self.exit_scope( + source_info.span, + region_scope, + otherwise_post_guard_block, + candidate.otherwise_block.unwrap(), + ); + + if let Operand::Copy(cond_place) | Operand::Move(cond_place) = cond { + if let Place::Base(PlaceBase::Local(cond_temp)) = cond_place { + // We will call `clear_top_scope` if there's another guard. So + // we have to drop this variable now or it will be "storage + // leaked". + self.pop_variable( + post_guard_block, + region_scope.0, + cond_temp + ); + } else { + bug!("Expected as_local_operand to produce a temporary"); + } + } + let by_value_bindings = candidate.bindings.iter().filter(|binding| { if let BindingMode::ByValue = binding.binding_mode { true } else { false } }); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 471304012c9a8..0d1d40a8af633 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -19,13 +19,18 @@ paragraph). This is because region scopes are tied to them. Eventually, when we shift to non-lexical lifetimes, there should be no need to remember this mapping. -There is one additional wrinkle, actually, that I wanted to hide from -you but duty compels me to mention. In the course of building -matches, it sometimes happen that certain code (namely guards) gets -executed multiple times. This means that the scope lexical scope may -in fact correspond to multiple, disjoint SEME regions. So in fact our +### Not so SEME Regions + +In the course of building matches, it sometimes happens that certain code +(namely guards) gets executed multiple times. This means that the scope lexical +scope may in fact correspond to multiple, disjoint SEME regions. So in fact our mapping is from one scope to a vector of SEME regions. +Also in matches, the scopes assigned to arms are not even SEME regions! Each +arm has a single region with one entry for each pattern. We manually +manipulate the scheduled drops in this scope to avoid dropping things multiple +times, although drop elaboration would clean this up for value drops. + ### Drops The primary purpose for scopes is to insert drops: while building @@ -731,7 +736,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Note that this code iterates scopes from the inner-most to the outer-most, // invalidating caches of each scope visited. This way bare minimum of the // caches gets invalidated. i.e., if a new drop is added into the middle scope, the - // cache of outer scpoe stays intact. + // cache of outer scope stays intact. scope.invalidate_cache(!needs_drop, this_scope); if this_scope { if let DropKind::Value { .. } = drop_kind { @@ -873,6 +878,73 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success_block } + + // `match` arm scopes + // ================== + /// Unschedules any drops in the top scope. + /// + /// This is only needed for `match` arm scopes, because they have one + /// entrance per pattern, but only one exit. + pub fn clear_top_scope(&mut self, region_scope: region::Scope) { + let top_scope = self.scopes.last_mut().unwrap(); + + assert_eq!(top_scope.region_scope, region_scope); + + top_scope.drops.clear(); + top_scope.invalidate_cache(false, true); + } + + /// Drops the single variable provided + /// + /// * The scope must be the top scope. + /// * The variable must be in that scope. + /// * The variable must be at the top of that scope: it's the next thing + /// scheduled to drop. + /// * The drop must be of DropKind::Storage. + /// + /// This is used for the boolean holding the result of the match guard. We + /// do this because: + /// + /// * The boolean is different for each pattern + /// * There is only one exit for the arm scope + /// * The guard expression scope is too short, it ends just before the + /// boolean is tested. + pub fn pop_variable( + &mut self, + block: BasicBlock, + region_scope: region::Scope, + variable: Local, + ) { + let top_scope = self.scopes.last_mut().unwrap(); + + assert_eq!(top_scope.region_scope, region_scope); + + let top_drop_data = top_scope.drops.pop().unwrap(); + + match top_drop_data.kind { + DropKind::Value { .. } => { + bug!("Should not be calling pop_top_variable on non-copy type!") + } + DropKind::Storage => { + // Drop the storage for both value and storage drops. + // Only temps and vars need their storage dead. + match top_drop_data.location { + Place::Base(PlaceBase::Local(index)) => { + let source_info = top_scope.source_info(top_drop_data.span); + assert_eq!(index, variable); + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::StorageDead(index) + }); + } + _ => unreachable!(), + } + } + } + + top_scope.invalidate_cache(true, true); + } + } /// Builds drops for pop_scope and exit_scope. diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 50140880a368d..d623f149988c7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -879,8 +879,12 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) _ => None, }, body: arm.body.to_ref(), - // BUG: fix this - lint_level: LintLevel::Inherited, + lint_level: LintLevel::Explicit(arm.hir_id), + scope: region::Scope { + id: arm.hir_id.local_id, + data: region::ScopeData::Node + }, + span: arm.span, } } diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 7ac36a22274f3..0850c552536c5 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -45,13 +45,13 @@ fn main() { // _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7]; +// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb6]; // } // bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb8, imaginary: bb3]; //pre_binding1 +// falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1 // } // bb3: { // falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2 @@ -62,48 +62,56 @@ fn main() { // bb5: { // unreachable; // } -// bb6: { // to pre_binding2 -// falseEdges -> [real: bb3, imaginary: bb3]; -// } -// bb7: { +// bb6: { // unreachable; // } -// bb8: { // binding1 and guard +// bb7: { // binding1 and guard // StorageLive(_6); // _6 = &(((promoted[0]: std::option::Option) as Some).0: i32); // _4 = &shallow _2; // StorageLive(_7); -// _7 = const guard() -> [return: bb9, unwind: bb1]; +// _7 = const guard() -> [return: bb8, unwind: bb1]; // } -// bb9: { +// bb8: { // end of guard // FakeRead(ForMatchGuard, _4); // FakeRead(ForGuardBinding, _6); -// switchInt(move _7) -> [false: bb6, otherwise: bb10]; +// switchInt(move _7) -> [false: bb10, otherwise: bb9]; // } -// bb10: { +// bb9: { // arm1 +// StorageDead(_7); // StorageLive(_5); // _5 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _5; // _1 = (const 1i32, move _8); // StorageDead(_8); +// StorageDead(_5); +// StorageDead(_6); // goto -> bb13; // } -// bb11: { +// bb10: { // to pre_binding2 +// StorageDead(_7); +// StorageDead(_6); +// falseEdges -> [real: bb3, imaginary: bb3]; +// } +// bb11: { // arm2 // StorageLive(_9); // _9 = ((_2 as Some).0: i32); // StorageLive(_10); // _10 = _9; // _1 = (const 2i32, move _10); // StorageDead(_10); +// StorageDead(_9); // goto -> bb13; // } -// bb12: { +// bb12: { // arm3 // _1 = (const 3i32, const 3i32); // goto -> bb13; // } // bb13: { -// ... +// StorageDead(_1); +// StorageDead(_2); +// _0 = (); // return; // } // END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir @@ -114,13 +122,13 @@ fn main() { // _2 = std::option::Option::::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _3 = discriminant(_2); -// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7]; +// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb6]; // } // bb1 (cleanup): { // resume; // } // bb2: { -// falseEdges -> [real: bb8, imaginary: bb3]; +// falseEdges -> [real: bb7, imaginary: bb3]; // } // bb3: { // falseEdges -> [real: bb11, imaginary: bb4]; @@ -131,33 +139,38 @@ fn main() { // bb5: { // unreachable; // } -// bb6: { // to pre_binding3 (can skip 2 since this is `Some`) -// falseEdges -> [real: bb4, imaginary: bb3]; -// } -// bb7: { +// bb6: { // unreachable; // } -// bb8: { // binding1 and guard +// bb7: { // binding1 and guard // StorageLive(_6); // _6 = &((_2 as Some).0: i32); // _4 = &shallow _2; // StorageLive(_7); -// _7 = const guard() -> [return: bb9, unwind: bb1]; +// _7 = const guard() -> [return: bb8, unwind: bb1]; // } -// bb9: { // end of guard +// bb8: { // end of guard // FakeRead(ForMatchGuard, _4); // FakeRead(ForGuardBinding, _6); -// switchInt(move _7) -> [false: bb6, otherwise: bb10]; +// switchInt(move _7) -> [false: bb10, otherwise: bb9]; // } -// bb10: { // arm1 +// bb9: { // arm1 +// StorageDead(_7); // StorageLive(_5); // _5 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _5; // _1 = (const 1i32, move _8); // StorageDead(_8); +// StorageDead(_5); +// StorageDead(_6); // goto -> bb13; // } +// bb10: { // to pre_binding3 (can skip 2 since this is `Some`) +// StorageDead(_7); +// StorageDead(_6); +// falseEdges -> [real: bb4, imaginary: bb3]; +// } // bb11: { // arm2 // _1 = (const 3i32, const 3i32); // goto -> bb13; @@ -169,16 +182,19 @@ fn main() { // _10 = _9; // _1 = (const 2i32, move _10); // StorageDead(_10); +// StorageDead(_9); // goto -> bb13; // } // bb13: { -// ... +// StorageDead(_1); +// StorageDead(_2); +// _0 = (); // return; // } // END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir // // START rustc.main.QualifyAndPromoteConstants.before.mir -// bb0: { +// bb0: { // ... // _2 = std::option::Option::::Some(const 1i32,); // FakeRead(ForMatchedPlace, _2); @@ -189,13 +205,13 @@ fn main() { // resume; // } // bb2: { -// falseEdges -> [real: bb9, imaginary: bb3]; +// falseEdges -> [real: bb7, imaginary: bb3]; // } // bb3: { -// falseEdges -> [real: bb12, imaginary: bb4]; +// falseEdges -> [real: bb11, imaginary: bb4]; // } // bb4: { -// falseEdges -> [real: bb13, imaginary: bb5]; +// falseEdges -> [real: bb12, imaginary: bb5]; // } // bb5: { // falseEdges -> [real: bb16, imaginary: bb6]; @@ -203,65 +219,79 @@ fn main() { // bb6: { // unreachable; // } -// bb7: { -// falseEdges -> [real: bb3, imaginary: bb3]; -// } -// bb8: { -// falseEdges -> [real: bb5, imaginary: bb5]; -// } -// bb9: { // binding1: Some(w) if guard() +// bb7: { // binding1: Some(w) if guard() // StorageLive(_7); // _7 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_8); -// _8 = const guard() -> [return: bb10, unwind: bb1]; +// _8 = const guard() -> [return: bb8, unwind: bb1]; // } -// bb10: { //end of guard +// bb8: { //end of guard1 // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _7); -// switchInt(move _8) -> [false: bb7, otherwise: bb11]; +// switchInt(move _8) -> [false: bb10, otherwise: bb9]; // } -// bb11: { // set up bindings for arm1 +// bb9: { +// StorageDead(_8); // StorageLive(_6); // _6 = ((_2 as Some).0: i32); // _1 = const 1i32; +// StorageDead(_6); +// StorageDead(_7); // goto -> bb17; // } -// bb12: { // binding2 & arm2 +// bb10: { +// StorageDead(_8); +// StorageDead(_7); +// falseEdges -> [real: bb3, imaginary: bb3]; +// } +// bb11: { // binding2 & arm2 // StorageLive(_9); // _9 = _2; // _1 = const 2i32; +// StorageDead(_9); // goto -> bb17; // } -// bb13: { // binding3: Some(y) if guard2(y) +// bb12: { // binding3: Some(y) if guard2(y) // StorageLive(_11); // _11 = &((_2 as Some).0: i32); // _5 = &shallow _2; // StorageLive(_12); // StorageLive(_13); // _13 = (*_11); -// _12 = const guard2(move _13) -> [return: bb14, unwind: bb1]; +// _12 = const guard2(move _13) -> [return: bb13, unwind: bb1]; // } -// bb14: { // end of guard2 +// bb13: { // end of guard2 // StorageDead(_13); // FakeRead(ForMatchGuard, _5); // FakeRead(ForGuardBinding, _11); -// switchInt(move _12) -> [false: bb8, otherwise: bb15]; +// switchInt(move _12) -> [false: bb15, otherwise: bb14]; // } -// bb15: { // binding4 & arm4 +// bb14: { // binding4 & arm4 +// StorageDead(_12); // StorageLive(_10); // _10 = ((_2 as Some).0: i32); // _1 = const 3i32; +// StorageDead(_10); +// StorageDead(_11); // goto -> bb17; // } +// bb15: { +// StorageDead(_12); +// StorageDead(_11); +// falseEdges -> [real: bb5, imaginary: bb5]; +// } // bb16: { // StorageLive(_14); // _14 = _2; // _1 = const 4i32; +// StorageDead(_14); // goto -> bb17; // } // bb17: { -// ... +// StorageDead(_1); +// StorageDead(_2); +// _0 = (); // return; // } // END rustc.main.QualifyAndPromoteConstants.before.mir diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs index a5317f98ef188..2ef9520c12c63 100644 --- a/src/test/mir-opt/match_test.rs +++ b/src/test/mir-opt/match_test.rs @@ -20,10 +20,10 @@ fn main() { // START rustc.main.SimplifyCfg-initial.after.mir // bb0: { // ... -// switchInt(move _4) -> [false: bb7, otherwise: bb8]; +// switchInt(move _4) -> [false: bb6, otherwise: bb7]; // } // bb1: { -// falseEdges -> [real: bb12, imaginary: bb2]; +// falseEdges -> [real: bb10, imaginary: bb2]; // } // bb2: { // falseEdges -> [real: bb13, imaginary: bb3]; @@ -38,33 +38,35 @@ fn main() { // unreachable; // } // bb6: { -// falseEdges -> [real: bb4, imaginary: bb2]; +// _6 = Le(const 10i32, _1); +// switchInt(move _6) -> [false: bb8, otherwise: bb9]; // } // bb7: { -// _6 = Le(const 10i32, _1); -// switchInt(move _6) -> [false: bb9, otherwise: bb10]; +// _5 = Lt(_1, const 10i32); +// switchInt(move _5) -> [false: bb6, otherwise: bb1]; // } // bb8: { -// _5 = Lt(_1, const 10i32); -// switchInt(move _5) -> [false: bb7, otherwise: bb1]; +// switchInt(_1) -> [-1i32: bb3, otherwise: bb4]; // } // bb9: { -// switchInt(_1) -> [-1i32: bb3, otherwise: bb4]; +// _7 = Le(_1, const 20i32); +// switchInt(move _7) -> [false: bb8, otherwise: bb2]; // } // bb10: { -// _7 = Le(_1, const 20i32); -// switchInt(move _7) -> [false: bb9, otherwise: bb2]; +// _8 = &shallow _1; +// StorageLive(_9); +// _9 = _2; +// FakeRead(ForMatchGuard, _8); +// switchInt(move _9) -> [false: bb12, otherwise: bb11]; // } // bb11: { +// StorageDead(_9); // _3 = const 0i32; // goto -> bb16; // } // bb12: { -// _8 = &shallow _1; -// StorageLive(_9); -// _9 = _2; -// FakeRead(ForMatchGuard, _8); -// switchInt(move _9) -> [false: bb6, otherwise: bb11]; +// StorageDead(_9); +// falseEdges -> [real: bb4, imaginary: bb2]; // } // bb13: { // _3 = const 1i32; @@ -79,7 +81,6 @@ fn main() { // goto -> bb16; // } // bb16: { -// StorageDead(_9); // _0 = (); // StorageDead(_2); // StorageDead(_1); diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 144348450a91b..12de1e8a51c4b 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -21,10 +21,10 @@ fn main() { // bb0: { // FakeRead(ForMatchedPlace, _1); // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb5, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb4, otherwise: bb2]; // } // bb1: { -// goto -> bb7; +// goto -> bb5; // } // bb2: { // goto -> bb8; @@ -33,16 +33,9 @@ fn main() { // unreachable; // } // bb4: { -// goto -> bb2; -// } -// bb5: { // switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; // } -// bb6: { -// _0 = const 0i32; -// goto -> bb9; -// } -// bb7: { +// bb5: { // _4 = &shallow _1; // _5 = &shallow ((_1 as Some).0: &' &' i32); // _6 = &shallow (*((_1 as Some).0: &' &' i32)); @@ -53,14 +46,22 @@ fn main() { // FakeRead(ForMatchGuard, _5); // FakeRead(ForMatchGuard, _6); // FakeRead(ForMatchGuard, _7); -// switchInt(move _8) -> [false: bb4, otherwise: bb6]; +// switchInt(move _8) -> [false: bb7, otherwise: bb6]; +// } +// bb6: { +// StorageDead(_8); +// _0 = const 0i32; +// goto -> bb9; +// } +// bb7: { +// StorageDead(_8); +// goto -> bb2; // } // bb8: { // _0 = const 1i32; // goto -> bb9; // } // bb9: { -// StorageDead(_8); // return; // } // bb10 (cleanup): { @@ -72,10 +73,10 @@ fn main() { // bb0: { // nop; // _3 = discriminant(_1); -// switchInt(move _3) -> [1isize: bb5, otherwise: bb2]; +// switchInt(move _3) -> [1isize: bb4, otherwise: bb2]; // } // bb1: { -// goto -> bb7; +// goto -> bb5; // } // bb2: { // goto -> bb8; @@ -84,16 +85,9 @@ fn main() { // unreachable; // } // bb4: { -// goto -> bb2; -// } -// bb5: { // switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb1, otherwise: bb2]; // } -// bb6: { -// _0 = const 0i32; -// goto -> bb9; -// } -// bb7: { +// bb5: { // nop; // nop; // nop; @@ -104,14 +98,22 @@ fn main() { // nop; // nop; // nop; -// switchInt(move _8) -> [false: bb4, otherwise: bb6]; +// switchInt(move _8) -> [false: bb7, otherwise: bb6]; +// } +// bb6: { +// StorageDead(_8); +// _0 = const 0i32; +// goto -> bb9; +// } +// bb7: { +// StorageDead(_8); +// goto -> bb2; // } // bb8: { // _0 = const 1i32; // goto -> bb9; // } // bb9: { -// StorageDead(_8); // return; // } // bb10 (cleanup): { diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs index da0236ac45070..78609a6e24b5e 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.rs +++ b/src/test/ui/lint/lint-unused-mut-variables.rs @@ -105,6 +105,14 @@ fn main() { _ => {} } + // Attribute should be respected on match arms + match 0 { + #[allow(unused_mut)] + mut x => { + let mut y = 1; + }, + } + let x = |mut y: isize| y = 32; fn nothing(mut foo: isize) { foo = 37; } diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr index e41d8f8ac7408..1a175c9683ec7 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.stderr +++ b/src/test/ui/lint/lint-unused-mut-variables.stderr @@ -133,7 +133,7 @@ LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { | help: remove this `mut` error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:130:9 + --> $DIR/lint-unused-mut-variables.rs:138:9 | LL | let mut b = vec![2]; | ----^ @@ -141,7 +141,7 @@ LL | let mut b = vec![2]; | help: remove this `mut` | note: lint level defined here - --> $DIR/lint-unused-mut-variables.rs:126:8 + --> $DIR/lint-unused-mut-variables.rs:134:8 | LL | #[deny(unused_mut)] | ^^^^^^^^^^ From bd8ecc6f5df1e3b54ca3e17da8360de4b07a1905 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Apr 2019 19:30:18 +0100 Subject: [PATCH 35/45] Remove MIR borrowck hack for old match scopes --- src/librustc_mir/dataflow/impls/mod.rs | 39 ++++++-------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 4dcfb3f1a7fc3..03d55b84f32e2 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -11,8 +11,7 @@ use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; -use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex}; -use super::move_paths::{LookupResult, InitKind}; +use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex, InitKind}; use super::{BitDenotation, BlockSets, InitialFlow}; use super::drop_flag_effects_for_function_entry; @@ -470,35 +469,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for EverInitializedPlaces<'a, 'gcx, 'tc sets.gen_all(&init_loc_map[location]); match stmt.kind { - mir::StatementKind::StorageDead(local) | - mir::StatementKind::StorageLive(local) => { - // End inits for StorageDead and StorageLive, so that an immutable - // variable can be reinitialized on the next iteration of the loop. - // - // FIXME(#46525): We *need* to do this for StorageLive as well as - // StorageDead, because lifetimes of match bindings with guards are - // weird - i.e., this code - // - // ``` - // fn main() { - // match 0 { - // a | a - // if { println!("a={}", a); false } => {} - // _ => {} - // } - // } - // ``` - // - // runs the guard twice, using the same binding for `a`, and only - // storagedeads after everything ends, so if we don't regard the - // storagelive as killing storage, we would have a multiple assignment - // to immutable data error. - if let LookupResult::Exact(mpi) = - rev_lookup.find(&mir::Place::Base(mir::PlaceBase::Local(local))) { - debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}", - stmt, location, &init_path_map[mpi]); - sets.kill_all(&init_path_map[mpi]); - } + mir::StatementKind::StorageDead(local) => { + // End inits for StorageDead, so that an immutable variable can + // be reinitialized on the next iteration of the loop. + let move_path_index = rev_lookup.find_local(local); + debug!("stmt {:?} at loc {:?} clears the ever initialized status of {:?}", + stmt, location, &init_path_map[move_path_index]); + sets.kill_all(&init_path_map[move_path_index]); } _ => {} } From decfc9b6f98ffab2cb588f048dda19ea90761f0b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Apr 2019 20:54:23 +0100 Subject: [PATCH 36/45] Emit fake borrows for all tests I was incorrectly under the impression that this would only lead to duplicates. See `mir-opt/match-arm-scope.rs` (upcomming commit) for a case where we didn't emit a fake borrow of `items.1`. --- src/librustc_mir/build/matches/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 091e39630d6cb..58ca35abcb123 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -870,7 +870,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span, untested_candidates, join_block, - &mut None, + fake_borrows, ) } From 4a6ba5109a012c2ed493ff5a9861738e8594a736 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Apr 2019 21:13:51 +0100 Subject: [PATCH 37/45] Schedule storage-dead of temporaries sooner This ensures that we will correctly generate a storage-dead if the initializing expression diverges. --- src/librustc_mir/build/expr/as_temp.rs | 40 +++++++++++++------ src/test/mir-opt/issue-49232.rs | 1 - src/test/mir-opt/match_false_edges.rs | 6 +-- .../mir-opt/storage_live_dead_in_statics.rs | 2 +- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index c60e197010067..ac70bf30e457b 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -1,6 +1,7 @@ //! See docs in build/expr/mod.rs use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use crate::build::scope::{CachedBlock, DropKind}; use crate::hair::*; use rustc::middle::region; use rustc::mir::*; @@ -63,6 +64,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } this.local_decls.push(local_decl) }; + let temp_place = &Place::Base(PlaceBase::Local(temp)); + if !expr_ty.is_never() { this.cfg.push( block, @@ -71,25 +74,38 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { kind: StatementKind::StorageLive(temp), }, ); + + // In constants, temp_lifetime is None for temporaries that live for the + // 'static lifetime. Thus we do not drop these temporaries and simply leak them. + // This is equivalent to what `let x = &foo();` does in functions. The temporary + // is lifted to their surrounding scope. In a function that means the temporary lives + // until just before the function returns. In constants that means it outlives the + // constant's initialization value computation. Anything outliving a constant + // must have the `'static` lifetime and live forever. + // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything + // within a block will keep the regular drops just like runtime code. + if let Some(temp_lifetime) = temp_lifetime { + this.schedule_drop( + expr_span, + temp_lifetime, + temp_place, + expr_ty, + DropKind::Storage, + ); + } } - unpack!(block = this.into(&Place::Base(PlaceBase::Local(temp)), block, expr)); + unpack!(block = this.into(temp_place, block, expr)); - // In constants, temp_lifetime is None for temporaries that live for the - // 'static lifetime. Thus we do not drop these temporaries and simply leak them. - // This is equivalent to what `let x = &foo();` does in functions. The temporary - // is lifted to their surrounding scope. In a function that means the temporary lives - // until just before the function returns. In constants that means it outlives the - // constant's initialization value computation. Anything outliving a constant - // must have the `'static` lifetime and live forever. - // Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything - // within a block will keep the regular drops just like runtime code. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop_storage_and_value( + this.schedule_drop( expr_span, temp_lifetime, - &Place::Base(PlaceBase::Local(temp)), + temp_place, expr_ty, + DropKind::Value { + cached_block: CachedBlock::default(), + }, ); } diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 3910183dee789..bf22f00b50552 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -86,7 +86,6 @@ fn main() { // unreachable; // } // bb17: { -// StorageDead(_4); // goto -> bb18; // } // bb18: { diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 0850c552536c5..6979924c8cd90 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -109,8 +109,8 @@ fn main() { // goto -> bb13; // } // bb13: { -// StorageDead(_1); // StorageDead(_2); +// StorageDead(_1); // _0 = (); // return; // } @@ -186,8 +186,8 @@ fn main() { // goto -> bb13; // } // bb13: { -// StorageDead(_1); // StorageDead(_2); +// StorageDead(_1); // _0 = (); // return; // } @@ -289,8 +289,8 @@ fn main() { // goto -> bb17; // } // bb17: { -// StorageDead(_1); // StorageDead(_2); +// StorageDead(_1); // _0 = (); // return; // } diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs index 10f00cf8b0c32..2ed34ecfad2c6 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.rs +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -182,8 +182,8 @@ fn main() { // _2 = Foo { tup: const "hi", data: move _3 }; // _1 = &_2; // _0 = &(*_1); -// StorageDead(_1); // StorageDead(_5); +// StorageDead(_1); // return; // } //} From 47c4e8c637a72c65b69fa21bf9cfd4ca184065fe Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Apr 2019 21:21:53 +0100 Subject: [PATCH 38/45] Add a test for match scopes --- src/test/mir-opt/match-arm-scopes.rs | 245 +++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 src/test/mir-opt/match-arm-scopes.rs diff --git a/src/test/mir-opt/match-arm-scopes.rs b/src/test/mir-opt/match-arm-scopes.rs new file mode 100644 index 0000000000000..0f026b8a08dfa --- /dev/null +++ b/src/test/mir-opt/match-arm-scopes.rs @@ -0,0 +1,245 @@ +// Test that StorageDead and Drops are generated properly for bindings in +// matches: +// * The MIR should only contain a single drop of `s` and `t`: at the end +// of their respective arms. +// * StorageDead and StorageLive statements are correctly matched up on +// non-unwind paths. +// * The visibility scopes of the match arms should be disjoint, and contain. +// all of the bindings for that scope. +// * No drop flags are used. + +#![feature(nll, bind_by_move_pattern_guards)] + +fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 { + match items { + (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1, + (true, b, t) | (false, b, t) => 2, + } +} + +const CASES: &[(bool, bool, bool, i32)] = &[ + (false, false, false, 2), + (false, false, true, 1), + (false, true, false, 1), + (false, true, true, 2), + (true, false, false, 3), + (true, false, true, 3), + (true, true, false, 3), + (true, true, true, 2), +]; + +fn main() { + for &(cond, items_1, items_2, result) in CASES { + assert_eq!( + complicated_match(cond, (items_1, items_2, String::new())), + result, + ); + } +} + +// END RUST SOURCE +// START rustc.complicated_match.SimplifyCfg-initial.after.mir +// let mut _0: i32; +// let mut _3: &bool; // Temp for fake borrow of `items.0` +// let mut _4: &bool; // Temp for fake borrow of `items.1` +// let _5: bool; // `a` in arm +// let _6: &bool; // `a` in guard +// let _7: std::string::String; // `s` in arm +// let _8: &std::string::String; // `s` in guard +// let mut _9: bool; // `if cond { return 3 } else { a }` +// let mut _10: bool; // `cond` +// let mut _11: !; // `return 3` +// let mut _12: bool; // `if cond { return 3 } else { a }` +// let mut _13: bool; // `cond` +// let mut _14: !; // `return 3` +// let _15: bool; // `b` +// let _16: std::string::String; // `t` +// scope 1 { +// } +// scope 2 { +// } +// bb0: { +// FakeRead(ForMatchedPlace, _2); +// switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb7]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// falseEdges -> [real: bb10, imaginary: bb3]; +// } +// bb3: { +// falseEdges -> [real: bb21, imaginary: bb4]; +// } +// bb4: { +// falseEdges -> [real: bb31, imaginary: bb5]; +// } +// bb5: { +// falseEdges -> [real: bb32, imaginary: bb6]; +// } +// bb6: { +// unreachable; +// } +// bb7: { +// switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb8]; +// } +// bb8: { +// switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb4]; +// } +// bb9: { // arm 1 +// _0 = const 1i32; +// drop(_7) -> [return: bb29, unwind: bb16]; +// } +// bb10: { // guard - first time +// StorageLive(_6); +// _6 = &(_2.1: bool); +// StorageLive(_8); +// _8 = &(_2.2: std::string::String); +// _3 = &shallow (_2.0: bool); +// _4 = &shallow (_2.1: bool); +// StorageLive(_9); +// StorageLive(_10); +// _10 = _1; +// FakeRead(ForMatchedPlace, _10); +// switchInt(_10) -> [false: bb12, otherwise: bb11]; +// } +// bb11: { +// falseEdges -> [real: bb14, imaginary: bb12]; +// } +// bb12: { +// falseEdges -> [real: bb18, imaginary: bb13]; +// } +// bb13: { +// unreachable; +// } +// bb14: { // `return 3` - first time +// _0 = const 3i32; +// StorageDead(_10); +// StorageDead(_9); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb17; +// } +// bb15: { +// return; +// } +// bb16 (cleanup): { +// drop(_2) -> bb1; +// } +// bb17: { +// drop(_2) -> [return: bb15, unwind: bb1]; +// } +// bb18: { // `else` block - first time +// _9 = (*_6); +// StorageDead(_10); +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForGuardBinding, _6); +// FakeRead(ForGuardBinding, _8); +// switchInt(move _9) -> [false: bb20, otherwise: bb19]; +// } +// bb19: { +// StorageDead(_9); +// StorageLive(_5); +// _5 = (_2.1: bool); +// StorageLive(_7); +// _7 = move (_2.2: std::string::String); +// goto -> bb9; +// } +// bb20: { // guard otherwise case - first time +// StorageDead(_9); +// StorageDead(_8); +// StorageDead(_6); +// falseEdges -> [real: bb7, imaginary: bb3]; +// } +// bb21: { // guard - second time +// StorageLive(_6); +// _6 = &(_2.0: bool); +// StorageLive(_8); +// _8 = &(_2.2: std::string::String); +// _3 = &shallow (_2.0: bool); +// _4 = &shallow (_2.1: bool); +// StorageLive(_12); +// StorageLive(_13); +// _13 = _1; +// FakeRead(ForMatchedPlace, _13); +// switchInt(_13) -> [false: bb23, otherwise: bb22]; +// } +// bb22: { +// falseEdges -> [real: bb25, imaginary: bb23]; +// } +// bb23: { +// falseEdges -> [real: bb26, imaginary: bb24]; +// } +// bb24: { +// unreachable; +// } +// bb25: { // `return 3` - second time +// _0 = const 3i32; +// StorageDead(_13); +// StorageDead(_12); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb17; +// } +// bb26: { // `else` block - second time +// _12 = (*_6); +// StorageDead(_13); +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForGuardBinding, _6); +// FakeRead(ForGuardBinding, _8); +// switchInt(move _12) -> [false: bb28, otherwise: bb27]; +// } +// bb27: { // Guard otherwise case - second time +// StorageDead(_12); +// StorageLive(_5); +// _5 = (_2.0: bool); +// StorageLive(_7); +// _7 = move (_2.2: std::string::String); +// goto -> bb9; +// } +// bb28: { // rest of arm 1 +// StorageDead(_12); +// StorageDead(_8); +// StorageDead(_6); +// falseEdges -> [real: bb8, imaginary: bb4]; +// } +// bb29: { +// StorageDead(_7); +// StorageDead(_5); +// StorageDead(_8); +// StorageDead(_6); +// goto -> bb34; +// } +// bb30: { // arm 2 +// _0 = const 2i32; +// drop(_16) -> [return: bb33, unwind: bb16]; +// } +// bb31: { // bindings for arm 2 - first pattern +// StorageLive(_15); +// _15 = (_2.1: bool); +// StorageLive(_16); +// _16 = move (_2.2: std::string::String); +// goto -> bb30; +// } +// bb32: { // bindings for arm 2 - first pattern +// StorageLive(_15); +// _15 = (_2.1: bool); +// StorageLive(_16); +// _16 = move (_2.2: std::string::String); +// goto -> bb30; +// } +// bb33: { // rest of arm 2 +// StorageDead(_16); +// StorageDead(_15); +// goto -> bb34; +// } +// bb34: { // end of match +// drop(_2) -> [return: bb15, unwind: bb1]; +// } +// END rustc.complicated_match.SimplifyCfg-initial.after.mir +// START rustc.complicated_match.ElaborateDrops.after.mir +// let _16: std::string::String; // No drop flags, which would come after this. +// scope 1 { +// END rustc.complicated_match.ElaborateDrops.after.mir From 8094d6e1cfe652c119f34f85e07148a2e65532e0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 22 Apr 2019 20:35:00 +0200 Subject: [PATCH 39/45] Comment style fixes Co-Authored-By: matthewjasper --- src/librustc_mir/build/expr/as_temp.rs | 4 ++-- src/librustc_mir/build/scope.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index ac70bf30e457b..cffd8fb2892f5 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -75,8 +75,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }, ); - // In constants, temp_lifetime is None for temporaries that live for the - // 'static lifetime. Thus we do not drop these temporaries and simply leak them. + // In constants, `temp_lifetime` is `None` for temporaries that live for the + // `'static` lifetime. Thus we do not drop these temporaries and simply leak them. // This is equivalent to what `let x = &foo();` does in functions. The temporary // is lifted to their surrounding scope. In a function that means the temporary lives // until just before the function returns. In constants that means it outlives the diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 0d1d40a8af633..34df40ae180af 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -900,7 +900,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// * The variable must be in that scope. /// * The variable must be at the top of that scope: it's the next thing /// scheduled to drop. - /// * The drop must be of DropKind::Storage. + /// * The drop must be of `DropKind::Storage`. /// /// This is used for the boolean holding the result of the match guard. We /// do this because: From 5b5255da4e7a9a3dd93a814687c53225a55a6e42 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 5 May 2019 17:32:52 +0100 Subject: [PATCH 40/45] Fix match ergonomics suggestion --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 99b350b833274..e4b431e6e68f1 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); } } - hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) | + hir::Node::Arm(_) | hir::Node::Pat(_) => { // rely on match ergonomics or it might be nested `&&pat` if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { From ea93215576ff04cab3bdb78c0d16ea7253488f40 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 13 May 2019 22:15:55 -0400 Subject: [PATCH 41/45] Bump measureme dependency to 0.3 measureme@0.3 adds a version header to the binary file format which will help reduce tool breakage in the future. --- Cargo.lock | 6 +++--- src/librustc/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 982070a243ee5..4417c25abcb4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1481,7 +1481,7 @@ dependencies = [ [[package]] name = "measureme" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2346,7 +2346,7 @@ dependencies = [ "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4174,7 +4174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819" -"checksum measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36bb2b263a6795d352035024d6b30ce465bb79a5e5280d74c3b5f8464c657bcc" +"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 2468de99d60a8..4d50e80d4cf67 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -36,7 +36,7 @@ byteorder = { version = "1.1", features = ["i128"]} chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -measureme = "0.2.1" +measureme = "0.3" # Note that these dependencies are a lie, they're just here to get linkage to # work. From 30317050092cc7a469f0815d40d400a812749564 Mon Sep 17 00:00:00 2001 From: Saleem Jaffer Date: Tue, 14 May 2019 14:14:12 +0530 Subject: [PATCH 42/45] some more refactor of FnType. Things build now --- src/librustc/ty/layout.rs | 186 ++++++++++------- src/librustc_codegen_llvm/abi.rs | 297 ++++++++++++++++++++++++++- src/librustc_codegen_llvm/declare.rs | 6 +- src/librustc_codegen_llvm/type_of.rs | 4 +- 4 files changed, 409 insertions(+), 84 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 58d27d4c5dbe4..6d7b0926c7ae2 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,9 +19,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; pub use rustc_target::abi::*; -use rustc_target::spec::HasTargetSpec; +use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi}; use rustc_target::abi::call::{ - ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode + ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind }; @@ -2266,53 +2266,35 @@ impl<'a, 'gcx> HashStable> for LayoutError<'gcx> } } -pub trait FnTypeExt<'tcx, C> { - fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>; - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>; - fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>; +pub trait FnTypeExt<'tcx, C> +where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, +{ + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self; + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; fn new_internal( cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>], mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>; + ) -> Self; + fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); } - -impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, - { +impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> +where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, +{ + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self { let sig = instance.fn_sig(cx.tcx()); let sig = cx .tcx() @@ -2320,27 +2302,12 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { call::FnType::new(cx, sig, &[]) } - fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, - { + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty))) } - - fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, - { - FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| { let mut layout = cx.layout_of(ty); // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` @@ -2395,19 +2362,11 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { } fn new_internal( - cx: &C, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self - where - C: LayoutOf, TyLayout = TyLayout<'tcx>> - + HasDataLayout - + HasTargetSpec - + HasTargetSpec - + HasTyCtxt<'tcx> - + HasParamEnv<'tcx>, - { + cx: &C, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self { debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); use rustc_target::spec::abi::Abi::*; @@ -2591,7 +2550,7 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { arg }; - let fn_ty = FnType { + let mut fn_ty = FnType { ret: arg_of(sig.output(), None), args: inputs .iter() @@ -2603,8 +2562,83 @@ impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> { c_variadic: sig.c_variadic, conv, }; - // FIXME: uncomment this after figuring out wwhere should adjust_for_abi reside. - //fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty.adjust_for_abi(cx, sig.abi); fn_ty } + + fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) { + if abi == SpecAbi::Unadjusted { + return; + } + + if abi == SpecAbi::Rust + || abi == SpecAbi::RustCall + || abi == SpecAbi::RustIntrinsic + || abi == SpecAbi::PlatformIntrinsic + { + let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { + if arg.is_ignore() { + return; + } + + match arg.layout.abi { + Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the platform intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + Abi::Vector { .. } + if abi != SpecAbi::PlatformIntrinsic + && cx.tcx().sess.target.target.options.simd_types_indirect => + { + arg.make_indirect(); + return; + } + + _ => return, + } + + let size = arg.layout.size; + if arg.layout.is_unsized() || size > Pointer.size(cx) { + arg.make_indirect(); + } else { + // We want to pass small aggregates as immediates, but using + // a LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { + kind: RegKind::Integer, + size, + }); + } + }; + fixup(&mut self.ret); + for arg in &mut self.args { + fixup(arg); + } + if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { + attrs.set(ArgAttribute::StructRet); + } + return; + } + + if let Err(msg) = self.adjust_for_cabi(cx, abi) { + cx.tcx().sess.fatal(&msg); + } + } } diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index cf4a523d9caa5..00e17ff990d95 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -295,6 +295,19 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> { } pub trait FnTypeExt<'tcx> { + fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self; + fn new(cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn new_internal( + cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self; fn adjust_for_abi(&mut self, cx: &CodegenCx<'ll, 'tcx>, abi: Abi); @@ -306,6 +319,284 @@ pub trait FnTypeExt<'tcx> { } impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { + fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { + let sig = instance.fn_sig(cx.tcx); + let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + FnTypeExt::new(cx, sig, &[]) + } + + fn new(cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self { + FnTypeExt::new_internal(cx, sig, extra_args, |ty, _| { + ArgType::new(cx.layout_of(ty)) + }) + } + + fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self { + FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| { + let mut layout = cx.layout_of(ty); + // Don't pass the vtable, it's not an argument of the virtual fn. + // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` + // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen + if arg_idx == Some(0) { + let fat_pointer_ty = if layout.is_unsized() { + // unsized `self` is passed as a pointer to `self` + // FIXME (mikeyhew) change this to use &own if it is ever added to the language + cx.tcx.mk_mut_ptr(layout.ty) + } else { + match layout.abi { + LayoutAbi::ScalarPair(..) => (), + _ => bug!("receiver type has unsupported layout: {:?}", layout) + } + + // In the case of Rc, we need to explicitly pass a *mut RcBox + // with a Scalar (not ScalarPair) ABI. This is a hack that is understood + // elsewhere in the compiler as a method on a `dyn Trait`. + // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we + // get a built-in pointer type + let mut fat_pointer_layout = layout; + 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() + && !fat_pointer_layout.ty.is_region_ptr() + { + 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { + let field_layout = fat_pointer_layout.field(cx, i); + + if !field_layout.is_zst() { + fat_pointer_layout = field_layout; + continue 'descend_newtypes + } + } + + bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); + } + + fat_pointer_layout.ty + }; + + // we now have a type like `*mut RcBox` + // change its layout to that of `*mut ()`, a thin pointer, but keep the same type + // this is understood as a special case elsewhere in the compiler + let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); + layout = cx.layout_of(unit_pointer_ty); + layout.ty = fat_pointer_ty; + } + ArgType::new(layout) + }) + } + + fn new_internal( + cx: &CodegenCx<'ll, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self { + debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); + + use self::Abi::*; + let conv = match cx.sess().target.target.adjust_abi(sig.abi) { + RustIntrinsic | PlatformIntrinsic | + Rust | RustCall => Conv::C, + + // It's the ABI's job to select this, not ours. + System => bug!("system abi should be selected elsewhere"), + + Stdcall => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall => Conv::X86ThisCall, + C => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, + AmdGpuKernel => Conv::AmdGpuKernel, + + // These API constants ought to be more specific... + Cdecl => Conv::C, + }; + + let mut inputs = sig.inputs(); + let extra_args = if sig.abi == RustCall { + assert!(!sig.c_variadic && extra_args.is_empty()); + + match sig.inputs().last().unwrap().sty { + ty::Tuple(tupled_arguments) => { + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; + tupled_arguments.iter().map(|k| k.expect_ty()).collect() + } + _ => { + bug!("argument to function with \"rust-call\" ABI \ + is not a tuple"); + } + } + } else { + assert!(sig.c_variadic || extra_args.is_empty()); + extra_args.to_vec() + }; + + let target = &cx.sess().target.target; + let win_x64_gnu = target.target_os == "windows" + && target.arch == "x86_64" + && target.target_env == "gnu"; + let linux_s390x = target.target_os == "linux" + && target.arch == "s390x" + && target.target_env == "gnu"; + let linux_sparc64 = target.target_os == "linux" + && target.arch == "sparc64" + && target.target_env == "gnu"; + let rust_abi = match sig.abi { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, + _ => false + }; + + // Handle safe Rust thin and fat pointers. + let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, + scalar: &layout::Scalar, + layout: TyLayout<'tcx, Ty<'tcx>>, + offset: Size, + is_return: bool| { + // Booleans are always an i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.set(ArgAttribute::ZExt); + return; + } + + // Only pointer types handled below. + if scalar.value != layout::Pointer { + return; + } + + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { + attrs.set(ArgAttribute::NonNull); + } + } + + if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_size = pointee.size; + attrs.pointee_align = Some(pointee.align); + + // `Box` pointer parameters never alias because ownership is transferred + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + let no_alias = match kind { + PointerKind::Shared => false, + PointerKind::UniqueOwned => true, + PointerKind::Frozen | + PointerKind::UniqueBorrowed => !is_return + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + } + } + }; + + // Store the index of the last argument. This is useful for working with + // C-compatible variadic arguments. + let last_arg_idx = if sig.inputs().is_empty() { + None + } else { + Some(sig.inputs().len() - 1) + }; + + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { + let is_return = arg_idx.is_none(); + let mut arg = mk_arg_type(ty, arg_idx); + if arg.layout.is_zst() { + // For some forsaken reason, x86_64-pc-windows-gnu + // doesn't ignore zero-sized struct arguments. + // The same is true for s390x-unknown-linux-gnu + // and sparc64-unknown-linux-gnu. + if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { + arg.mode = PassMode::Ignore(IgnoreMode::Zst); + } + } + + // If this is a C-variadic function, this is not the return value, + // and there is one or more fixed arguments; ensure that the `VaList` + // is ignored as an argument. + if sig.c_variadic { + match (last_arg_idx, arg_idx) { + (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { + let va_list_did = match cx.tcx.lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), + }; + match ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // This is the "spoofed" `VaList`. Set the arguments mode + // so that it will be ignored. + arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); + }, + _ => (), + } + } + _ => {} + } + } + + // FIXME(eddyb) other ABIs don't have logic for scalar pairs. + if !is_return && rust_abi { + if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { + let mut a_attrs = ArgAttributes::new(); + let mut b_attrs = ArgAttributes::new(); + adjust_for_rust_scalar(&mut a_attrs, + a, + arg.layout, + Size::ZERO, + false); + adjust_for_rust_scalar(&mut b_attrs, + b, + arg.layout, + a.value.size(cx).align_to(b.value.align(cx).abi), + false); + arg.mode = PassMode::Pair(a_attrs, b_attrs); + return arg; + } + } + + if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { + if let PassMode::Direct(ref mut attrs) = arg.mode { + adjust_for_rust_scalar(attrs, + scalar, + arg.layout, + Size::ZERO, + is_return); + } + } + + arg + }; + + let mut fn_ty = FnType { + ret: arg_of(sig.output(), None), + args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| { + arg_of(ty, Some(i)) + }).collect(), + c_variadic: sig.c_variadic, + conv, + }; + FnTypeExt::adjust_for_abi(&mut fn_ty, cx, sig.abi); + fn_ty + } + fn adjust_for_abi(&mut self, cx: &CodegenCx<'ll, 'tcx>, abi: Abi) { @@ -547,17 +838,17 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> { - FnType::new(&self, sig, extra_args) + FnTypeExt::new(&self, sig, extra_args) } fn new_vtable( &self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>] ) -> FnType<'tcx, Ty<'tcx>> { - FnType::new_vtable(&self, sig, extra_args) + FnTypeExt::new_vtable(&self, sig, extra_args) } fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { - FnType::of_instance(&self, instance) + FnTypeExt::of_instance(&self, instance) } } diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 3febcb019ce29..6b8a45da1803f 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -18,8 +18,8 @@ use crate::attributes; use crate::context::CodegenCx; use crate::type_::Type; use crate::value::Value; -use rustc::ty::{self, PolyFnSig}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::{self, PolyFnSig, Ty}; +use rustc::ty::layout::{FnTypeExt as FnTypeExt1, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; @@ -100,7 +100,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { let sig = self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - let fty = FnType::new(self, sig, &[]); + let fty: FnType<'tcx, Ty<'tcx>> = FnTypeExt1::new(self, sig, &[]); let llfn = declare_raw_fn(self, name, fty.llvm_cconv(), fty.llvm_type(self)); if self.layout_of(sig.output()).abi.is_uninhabited() { diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index ff25ed9256613..800bf505125d6 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -1,8 +1,8 @@ -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType}; use crate::common::*; use crate::type_::Type; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout}; use rustc_target::abi::{FloatTy, TyLayoutMethods}; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_codegen_ssa::traits::*; From e1b3c79d5c9ff805a03b478e77b44f9b48d848f0 Mon Sep 17 00:00:00 2001 From: Saleem Jaffer Date: Tue, 14 May 2019 15:20:29 +0530 Subject: [PATCH 43/45] refactor complete --- src/librustc_codegen_llvm/abi.rs | 379 +-------------------------- src/librustc_codegen_llvm/declare.rs | 8 +- src/librustc_codegen_llvm/type_.rs | 2 +- 3 files changed, 12 insertions(+), 377 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 00e17ff990d95..16e5695c83195 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -11,9 +11,9 @@ use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi}; +use rustc_target::abi::{HasDataLayout, LayoutOf}; use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout::{self, PointerKind}; +use rustc::ty::layout::{self, FnTypeExt}; use libc::c_uint; @@ -294,23 +294,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -pub trait FnTypeExt<'tcx> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self; - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self; - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi); +pub trait FnTypeLlvmExt<'tcx> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn llvm_cconv(&self) -> llvm::CallConv; @@ -318,356 +302,7 @@ pub trait FnTypeExt<'tcx> { fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value); } -impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let sig = instance.fn_sig(cx.tcx); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - FnTypeExt::new(cx, sig, &[]) - } - - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnTypeExt::new_internal(cx, sig, extra_args, |ty, _| { - ArgType::new(cx.layout_of(ty)) - }) - } - - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| { - let mut layout = cx.layout_of(ty); - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if arg_idx == Some(0) { - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx.mk_mut_ptr(layout.ty) - } else { - match layout.abi { - LayoutAbi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout) - } - - // In the case of Rc, we need to explicitly pass a *mut RcBox - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - } - ArgType::new(layout) - }) - } - - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self { - debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); - - use self::Abi::*; - let conv = match cx.sess().target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => Conv::C, - - // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), - - Stdcall => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - match sig.inputs().last().unwrap().sty { - ty::Tuple(tupled_arguments) => { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments.iter().map(|k| k.expect_ty()).collect() - } - _ => { - bug!("argument to function with \"rust-call\" ABI \ - is not a tuple"); - } - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args.to_vec() - }; - - let target = &cx.sess().target.target; - let win_x64_gnu = target.target_os == "windows" - && target.arch == "x86_64" - && target.target_env == "gnu"; - let linux_s390x = target.target_os == "linux" - && target.arch == "s390x" - && target.target_env == "gnu"; - let linux_sparc64 = target.target_os == "linux" - && target.arch == "sparc64" - && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &layout::Scalar, - layout: TyLayout<'tcx, Ty<'tcx>>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != layout::Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_size = pointee.size; - attrs.pointee_align = Some(pointee.align); - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | - PointerKind::UniqueBorrowed => !is_return - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - // Store the index of the last argument. This is useful for working with - // C-compatible variadic arguments. - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { - let is_return = arg_idx.is_none(); - let mut arg = mk_arg_type(ty, arg_idx); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore(IgnoreMode::Zst); - } - } - - // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaList` - // is ignored as an argument. - if sig.c_variadic { - match (last_arg_idx, arg_idx) { - (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { - let va_list_did = match cx.tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaList`. Set the arguments mode - // so that it will be ignored. - arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); - }, - _ => (), - } - } - _ => {} - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, - a, - arg.layout, - Size::ZERO, - false); - adjust_for_rust_scalar(&mut b_attrs, - b, - arg.layout, - a.value.size(cx).align_to(b.value.align(cx).abi), - false); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, - scalar, - arg.layout, - Size::ZERO, - is_return); - } - } - - arg - }; - - let mut fn_ty = FnType { - ret: arg_of(sig.output(), None), - args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| { - arg_of(ty, Some(i)) - }).collect(), - c_variadic: sig.c_variadic, - conv, - }; - FnTypeExt::adjust_for_abi(&mut fn_ty, cx, sig.abi); - fn_ty - } - - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi) { - if abi == Abi::Unadjusted { return } - - if abi == Abi::Rust || abi == Abi::RustCall || - abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { return; } - - match arg.layout.abi { - layout::Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - layout::Abi::Vector { .. } - if abi != Abi::PlatformIntrinsic && - cx.sess().target.target.options.simd_types_indirect => - { - arg.make_indirect(); - return - } - - _ => return - } - - let size = arg.layout.size; - if arg.layout.is_unsized() || size > layout::Pointer.size(cx) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { - kind: RegKind::Integer, - size - }); - } - }; - fixup(&mut self.ret); - for arg in &mut self.args { - fixup(arg); - } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - return; - } - - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.sess().fatal(&msg); - } - } - +impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { let args_capacity: usize = self.args.iter().map(|arg| if arg.pad.is_some() { 1 } else { 0 } + @@ -838,17 +473,17 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> { - FnTypeExt::new(&self, sig, extra_args) + FnType::new(self, sig, extra_args) } fn new_vtable( &self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>] ) -> FnType<'tcx, Ty<'tcx>> { - FnTypeExt::new_vtable(&self, sig, extra_args) + FnType::new_vtable(self, sig, extra_args) } fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { - FnTypeExt::of_instance(&self, instance) + FnType::of_instance(self, instance) } } diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 6b8a45da1803f..89fdec076c6d6 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -13,13 +13,13 @@ use crate::llvm; use crate::llvm::AttributePlace::Function; -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType, FnTypeLlvmExt}; use crate::attributes; use crate::context::CodegenCx; use crate::type_::Type; use crate::value::Value; -use rustc::ty::{self, PolyFnSig, Ty}; -use rustc::ty::layout::{FnTypeExt as FnTypeExt1, LayoutOf}; +use rustc::ty::{self, PolyFnSig}; +use rustc::ty::layout::{FnTypeExt, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; @@ -100,7 +100,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { let sig = self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - let fty: FnType<'tcx, Ty<'tcx>> = FnTypeExt1::new(self, sig, &[]); + let fty= FnType::new(self, sig, &[]); let llfn = declare_raw_fn(self, name, fty.llvm_cconv(), fty.llvm_type(self)); if self.layout_of(sig.output()).abi.is_uninhabited() { diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index a5ed64a66a39d..a3d3f0756a5f3 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::*; use crate::common; use crate::type_of::LayoutLlvmExt; -use crate::abi::{LlvmType, FnTypeExt}; +use crate::abi::{LlvmType, FnTypeLlvmExt}; use syntax::ast; use rustc::ty::Ty; use rustc::ty::layout::{self, Align, Size, TyLayout}; From 44eb607d7665f09967403a1999d99f4559be1c21 Mon Sep 17 00:00:00 2001 From: Saleem Jaffer Date: Tue, 14 May 2019 21:23:01 +0530 Subject: [PATCH 44/45] removes `AbiMethods` --- src/librustc_codegen_llvm/abi.rs | 20 ++------------------ src/librustc_codegen_llvm/builder.rs | 7 +++++++ src/librustc_codegen_llvm/declare.rs | 2 +- src/librustc_codegen_ssa/mir/block.rs | 14 +++++++------- src/librustc_codegen_ssa/mir/mod.rs | 4 ++-- src/librustc_codegen_ssa/traits/abi.rs | 8 +------- src/librustc_codegen_ssa/traits/builder.rs | 2 ++ src/librustc_codegen_ssa/traits/mod.rs | 11 +++++++---- 8 files changed, 29 insertions(+), 39 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 16e5695c83195..38d4b7e3f9d85 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -12,8 +12,8 @@ use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; use rustc_target::abi::{HasDataLayout, LayoutOf}; -use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout::{self, FnTypeExt}; +use rustc::ty::{Ty}; +use rustc::ty::layout::{self}; use libc::c_uint; @@ -471,22 +471,6 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } } -impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> { - FnType::new(self, sig, extra_args) - } - fn new_vtable( - &self, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>] - ) -> FnType<'tcx, Ty<'tcx>> { - FnType::new_vtable(self, sig, extra_args) - } - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { - FnType::of_instance(self, instance) - } -} - impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn apply_attrs_callsite( &mut self, diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index bc2bb97a19e54..48808eea3045e 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -18,6 +18,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef}; use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ops::{Deref, Range}; use std::ptr; @@ -72,6 +73,12 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { } } +impl HasTargetSpec for Builder<'_, '_, 'tcx> { + fn target_spec(&self) -> &Target { + &self.cx.target_spec() + } +} + impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> { type Ty = Ty<'tcx>; type TyLayout = TyLayout<'tcx>; diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 89fdec076c6d6..bcb14b8899ec2 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -100,7 +100,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { let sig = self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - let fty= FnType::new(self, sig, &[]); + let fty = FnType::new(self, sig, &[]); let llfn = declare_raw_fn(self, name, fty.llvm_cconv(), fty.llvm_type(self)); if self.layout_of(sig.output()).abi.is_uninhabited() { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index e64c847db651b..96b8558c1d2c4 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1,6 +1,6 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::InterpError; use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; @@ -334,14 +334,14 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), &sig, ); - let fn_ty = bx.new_vtable(sig, &[]); + let fn_ty = FnType::new_vtable(&bx, sig, &[]); let vtable = args[1]; args = &args[..1]; (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty) } _ => { (bx.get_fn(drop_fn), - bx.fn_type_of_instance(&drop_fn)) + FnType::of_instance(&bx, &drop_fn)) } }; helper.do_call(self, &mut bx, fn_ty, drop_fn, args, @@ -439,7 +439,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. @@ -518,7 +518,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_ty = match def { Some(ty::InstanceDef::Virtual(..)) => { - bx.new_vtable(sig, &extra_args) + FnType::new_vtable(&bx, sig, &extra_args) } Some(ty::InstanceDef::DropGlue(_, None)) => { // Empty drop glue; a no-op. @@ -526,7 +526,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.funclet_br(self, &mut bx, target); return; } - _ => bx.new_fn_type(sig, &extra_args) + _ => FnType::new(&bx, sig, &extra_args) }; // Emit a panic or a no-op for `panic_if_uninhabited`. @@ -556,7 +556,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index fcf099235aa14..060d7d18625fc 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; -use rustc::ty::layout::{TyLayout, HasTyCtxt}; +use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Mir}; use rustc::session::config::DebugInfo; use rustc_mir::monomorphize::Instance; @@ -202,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( ) { assert!(!instance.substs.needs_infer()); - let fn_ty = cx.new_fn_type(sig, &[]); + let fn_ty = FnType::new(cx, sig, &[]); debug!("fn_ty: {:?}", fn_ty); let mut debug_context = cx.create_function_debug_context(instance, sig, llfn, mir); diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/src/librustc_codegen_ssa/traits/abi.rs index a8fd4e1d2c7c7..509255c37be70 100644 --- a/src/librustc_codegen_ssa/traits/abi.rs +++ b/src/librustc_codegen_ssa/traits/abi.rs @@ -1,13 +1,7 @@ use super::BackendTypes; -use rustc::ty::{FnSig, Instance, Ty}; +use rustc::ty::{Ty}; use rustc_target::abi::call::FnType; -pub trait AbiMethods<'tcx> { - fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>; -} - pub trait AbiBuilderMethods<'tcx>: BackendTypes { fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value); fn get_param(&self, index: usize) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index a3f99cd869e28..0c4c4547a7955 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -11,6 +11,7 @@ use crate::mir::place::PlaceRef; use crate::MemFlags; use rustc::ty::Ty; use rustc::ty::layout::{Align, Size, HasParamEnv}; +use rustc_target::spec::{HasTargetSpec}; use std::ops::Range; use std::iter::TrustedLen; @@ -30,6 +31,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: + AsmBuilderMethods<'tcx> + StaticBuilderMethods<'tcx> + HasParamEnv<'tcx> + + HasTargetSpec { fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self; diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index c237cd8bd2645..2bb619e79f5e0 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -27,7 +27,7 @@ mod statics; mod type_; mod write; -pub use self::abi::{AbiBuilderMethods, AbiMethods}; +pub use self::abi::{AbiBuilderMethods}; pub use self::asm::{AsmBuilderMethods, AsmMethods}; pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; @@ -41,7 +41,8 @@ pub use self::type_::{ ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc::ty::layout::{HasParamEnv}; +use rustc::ty::layout::{HasParamEnv, HasTyCtxt}; +use rustc_target::spec::{HasTargetSpec}; use std::fmt; @@ -56,11 +57,12 @@ pub trait CodegenMethods<'tcx>: + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } @@ -71,11 +73,12 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } From 3646b3c3d9f60c0632668943ca65beb259d035f9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 14 May 2019 21:33:22 +0300 Subject: [PATCH 45/45] rustbuild/LLVM: Do not print installation messages for up-to-date files --- src/bootstrap/native.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5777331b9bfd5..da2e03a1a0848 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -317,6 +317,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { fn configure_cmake(builder: &Builder<'_>, target: Interned, cfg: &mut cmake::Config) { + // Do not print installation messages for up-to-date files. + // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. + cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); + if builder.config.ninja { cfg.generator("Ninja"); }