From e753d2105159397eff162aa3f1f7715f96b5772d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 11:23:34 +0100 Subject: [PATCH 01/36] miri: accept extern types in structs if they are the only field --- src/librustc_mir/interpret/eval_context.rs | 15 ++++++++++++-- src/librustc_mir/interpret/place.rs | 3 ++- src/test/ui/consts/const-eval/issue-55541.rs | 21 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/const-eval/issue-55541.rs diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index bc7ad16dc97b..48a8d0bbe56d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -371,8 +371,19 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1)?; - let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)? - .expect("Fields cannot be extern types"); + let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { + Some(size_and_align) => size_and_align, + None => { + // A field with extern type. If this is the only field, + // we treat this struct just the same. Else, this is an error + // (for now). + if layout.fields.count() == 1 { + return Ok(None) + } else { + bug!("Fields cannot be extern types, unless they are the only field") + } + } + }; // FIXME (#26403, #27023): We should be adding padding // to `sized_size` (to accommodate the `unsized_align` diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3b104e2284fe..8bd29aff841c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -354,7 +354,8 @@ where let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout let (_, align) = self.size_and_align_of(base.meta, field_layout)? - .expect("Fields cannot be extern types"); + // If this is an extern type, we fall back to its static size and alignment. + .unwrap_or_else(|| base.layout.size_and_align()); (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs new file mode 100644 index 000000000000..bf8965e83618 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -0,0 +1,21 @@ +// compile-pass + +// Test that we can handle newtypes wrapping extern types + +#![feature(extern_types, const_transmute)] + +extern "C" { + pub type ExternType; +} +unsafe impl Sync for ExternType {} + +#[repr(transparent)] +pub struct Wrapper(ExternType); + +static MAGIC_FFI_STATIC: u8 = 42; + +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +fn main() {} From aca76d42a05c419a539d9b34fa30b88d4cdcadcc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 11:55:39 +0100 Subject: [PATCH 02/36] test for offset and alignment of the sized part, instead of field count --- src/librustc_mir/interpret/eval_context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 48a8d0bbe56d..c1c2efdae751 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -374,13 +374,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { Some(size_and_align) => size_and_align, None => { - // A field with extern type. If this is the only field, - // we treat this struct just the same. Else, this is an error - // (for now). - if layout.fields.count() == 1 { + // A field with extern type. If this field is at offset 0 and the sized + // part makes no alignment constraints, we behave like the underlying + // extern type. + if sized_size == Size::ZERO && sized_align.abi() == 1 { return Ok(None) } else { - bug!("Fields cannot be extern types, unless they are the only field") + bug!("Fields cannot be extern types, unless they are at offset 0") } } }; From bb17f717499132a23e1b54bf3fdd0727c09715ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 14:43:05 +0100 Subject: [PATCH 03/36] also test with PhantomData --- src/test/ui/consts/const-eval/issue-55541.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs index bf8965e83618..611fb89341de 100644 --- a/src/test/ui/consts/const-eval/issue-55541.rs +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -4,18 +4,24 @@ #![feature(extern_types, const_transmute)] +use std::marker::PhantomData; + extern "C" { pub type ExternType; } unsafe impl Sync for ExternType {} +static MAGIC_FFI_STATIC: u8 = 42; #[repr(transparent)] pub struct Wrapper(ExternType); - -static MAGIC_FFI_STATIC: u8 = 42; - pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { std::mem::transmute(&MAGIC_FFI_STATIC) }; +#[repr(transparent)] +pub struct Wrapper2(PhantomData>, ExternType); +pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + fn main() {} From 5ebd077f54c735aeb634d18080c9f127016f1c87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 11:14:21 +0100 Subject: [PATCH 04/36] make it more obvious that the size is not relevant --- src/librustc_mir/interpret/place.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 8bd29aff841c..3dcd081edf9d 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -353,9 +353,10 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let (_, align) = self.size_and_align_of(base.meta, field_layout)? - // If this is an extern type, we fall back to its static size and alignment. - .unwrap_or_else(|| base.layout.size_and_align()); + let align = self.size_and_align_of(base.meta, field_layout)? + .map(|(_, align)| align) + // If this is an extern type, we fall back to its static alignment. + .unwrap_or_else(|| base.layout.align); (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized From a6622c265c9a359c277af576c4849a74d476f597 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 11:20:01 +0100 Subject: [PATCH 05/36] note some FIXMEs --- src/librustc_mir/interpret/eval_context.rs | 3 +++ src/librustc_mir/interpret/place.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c1c2efdae751..797e0458e531 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -377,6 +377,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // A field with extern type. If this field is at offset 0 and the sized // part makes no alignment constraints, we behave like the underlying // extern type. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. if sized_size == Size::ZERO && sized_align.abi() == 1 { return Ok(None) } else { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3dcd081edf9d..c60ae7b4a00c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -356,6 +356,9 @@ where let align = self.size_and_align_of(base.meta, field_layout)? .map(|(_, align)| align) // If this is an extern type, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. .unwrap_or_else(|| base.layout.align); (base.meta, offset.abi_align(align)) } else { From ba0bab39e04a13ad996e41a2ef2ca9b83fbb2cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 08:41:56 +0100 Subject: [PATCH 06/36] make sure we only guess field alignment at offset 0 --- src/librustc_mir/interpret/eval_context.rs | 7 +++---- src/librustc_mir/interpret/place.rs | 18 +++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 797e0458e531..cca4e8a3ce31 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -374,13 +374,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { Some(size_and_align) => size_and_align, None => { - // A field with extern type. If this field is at offset 0 and the sized - // part makes no alignment constraints, we behave like the underlying - // extern type. + // A field with extern type. If this field is at offset 0, we behave + // like the underlying extern type. // FIXME: Once we have made decisions for how to handle size and alignment // of `extern type`, this should be adapted. It is just a temporary hack // to get some code to work that probably ought to work. - if sized_size == Size::ZERO && sized_align.abi() == 1 { + if sized_size == Size::ZERO { return Ok(None) } else { bug!("Fields cannot be extern types, unless they are at offset 0") diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c60ae7b4a00c..a836a199f768 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -353,13 +353,17 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let align = self.size_and_align_of(base.meta, field_layout)? - .map(|(_, align)| align) - // If this is an extern type, we fall back to its static alignment. - // FIXME: Once we have made decisions for how to handle size and alignment - // of `extern type`, this should be adapted. It is just a temporary hack - // to get some code to work that probably ought to work. - .unwrap_or_else(|| base.layout.align); + let align = match self.size_and_align_of(base.meta, field_layout)? { + Some((_, align)) => align, + None if offset == Size::ZERO => + // An extern type at offset 0, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + field_layout.align, + None => + bug!("Cannot compute offset for extern type field at non-0 offset"), + }; (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized From b7c319c56ae8380aa2ab03d2b9b6702ae43d49b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:43:33 +0100 Subject: [PATCH 07/36] do not panic just because cargo failed --- src/bootstrap/compile.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index cef0849937bf..71b204b2de98 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -22,7 +22,7 @@ use std::fs::{self, File}; use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Stdio, exit}; use std::str; use build_helper::{output, mtime, up_to_date}; @@ -1098,7 +1098,7 @@ pub fn run_cargo(builder: &Builder, }); if !ok { - panic!("cargo must succeed"); + exit(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've From 0c085299344d9af4e9bfd892a15d746b116ebe00 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Mon, 5 Nov 2018 15:30:04 +0100 Subject: [PATCH 08/36] A few tweaks to iterations/collecting --- src/librustc/cfg/graphviz.rs | 3 +-- src/librustc/hir/lowering.rs | 3 +-- src/librustc/ty/query/on_disk_cache.rs | 2 +- src/libserialize/hex.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 18 ++++++++---------- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs index cc4f3f95d079..650aa39114fa 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc/cfg/graphviz.rs @@ -106,8 +106,7 @@ impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { type Node = Node<'a>; type Edge = Edge<'a>; fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { - let mut v = Vec::new(); - self.graph.each_node(|i, nd| { v.push((i, nd)); true }); + let v: Vec<_> = self.graph.enumerated_nodes().collect(); v.into() } fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd5d4b8f6aff..4f94b427ec16 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1062,8 +1062,7 @@ impl<'a> LoweringContext<'a> { attrs .iter() .map(|a| self.lower_attr(a)) - .collect::>() - .into() + .collect() } fn lower_attr(&mut self, attr: &Attribute) -> Attribute { diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 54550b8a2055..7d3ae64f4fcd 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -281,7 +281,7 @@ impl<'sess> OnDiskCache<'sess> { // otherwise, abort break; } - interpret_alloc_index.reserve(new_n); + interpret_alloc_index.reserve(new_n - n); for idx in n..new_n { let id = encoder.interpret_allocs_inverse[idx]; let pos = encoder.position() as u32; diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 7f3736e82caa..5604729d2f8d 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -146,7 +146,7 @@ impl FromHex for str { } match modulus { - 0 => Ok(b.into_iter().collect()), + 0 => Ok(b), _ => Err(InvalidHexLength), } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index dd90ef06c392..bfdb53a9d9e1 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1200,16 +1200,14 @@ impl<'a> MethodDef<'a> { let sp = trait_.span; let variants = &enum_def.variants; - let self_arg_names = self_args.iter() - .enumerate() - .map(|(arg_count, _self_arg)| { - if arg_count == 0 { - "__self".to_string() - } else { + let self_arg_names = iter::once("__self".to_string()).chain( + self_args.iter() + .enumerate() + .skip(1) + .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count) - } - }) - .collect::>(); + ) + ).collect::>(); let self_arg_idents = self_arg_names.iter() .map(|name| cx.ident_of(&name[..])) @@ -1218,7 +1216,7 @@ impl<'a> MethodDef<'a> { // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. - let vi_idents: Vec = self_arg_names.iter() + let vi_idents = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); cx.ident_of(&vi_suffix[..]).gensym() From 562be7e1a1955742d61320d0855550794c4b6c22 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 8 Nov 2018 20:12:05 +0100 Subject: [PATCH 09/36] Forward the ABI of the non-zero sized fields of an union if they have the same ABI This is supposed to fix the performence regression of using MaybeUninit in https://github.com/rust-lang/rust/pull/54668 --- src/librustc/ty/layout.rs | 35 ++++++++++++++- src/librustc/ty/mod.rs | 6 +++ src/test/codegen/union-abi.rs | 80 +++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/union-abi.rs diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 877bd5a82e6a..0b00cfc2d7fd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -697,7 +697,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { Align::from_bytes(repr_align, repr_align).unwrap()); } + let optimize = !def.repr.inhibit_union_abi_opt(); let mut size = Size::ZERO; + let mut abi = Abi::Aggregate { sized: true }; let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); @@ -708,13 +710,44 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } else { align = align.max(field.align); } + + // If all non-ZST fields have the same ABI, forward this ABI + if optimize && !field.is_zst() { + // Normalize scalar_unit to the maximal valid range + let field_abi = match &field.abi { + Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), + Abi::ScalarPair(x, y) => { + Abi::ScalarPair( + scalar_unit(x.value), + scalar_unit(y.value), + ) + } + Abi::Vector { element: x, count } => { + Abi::Vector { + element: scalar_unit(x.value), + count: *count, + } + } + Abi::Uninhabited | + Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + }; + + if size == Size::ZERO { + // first non ZST: initialize 'abi' + abi = field_abi; + } else if abi != field_abi { + // different fields have different ABI: reset to Aggregate + abi = Abi::Aggregate { sized: true }; + } + } + size = cmp::max(size, field.size); } return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), - abi: Abi::Aggregate { sized: true }, + abi, align, size: size.abi_align(align) })); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 83feadd50d77..9553d1244837 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1994,6 +1994,12 @@ impl ReprOptions { pub fn inhibit_struct_field_reordering_opt(&self) -> bool { !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) } + + /// Returns true if this `#[repr()]` should inhibit union abi optimisations + pub fn inhibit_union_abi_opt(&self) -> bool { + self.c() + } + } impl<'a, 'gcx, 'tcx> AdtDef { diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs new file mode 100644 index 000000000000..0fa06fa777b2 --- /dev/null +++ b/src/test/codegen/union-abi.rs @@ -0,0 +1,80 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +// This test that using union forward the abi of the inner type, as +// discussed in #54668 + +#![crate_type="lib"] +#![feature(repr_simd)] + +#[derive(Copy, Clone)] +pub enum Unhab {} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i64x4(i64, i64, i64, i64); + +#[derive(Copy, Clone)] +pub union UnionI64x4{ a:(), b: i64x4 } + +// CHECK: define <4 x i64> @test_UnionI64x4(<4 x i64> %arg0) +#[no_mangle] +pub extern fn test_UnionI64x4(_: UnionI64x4) -> UnionI64x4 { loop {} } + +pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } + +// CHECK: define <4 x i64> @test_UnionI64x4_(<4 x i64> %arg0) +#[no_mangle] +pub extern fn test_UnionI64x4_(_: UnionI64x4_) -> UnionI64x4_ { loop {} } + +pub union UnionI64x4I64{ a: i64x4, b: i64 } + +// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} } + +pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) } + +// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} } + + +pub union UnionF32{a:f32} + +// CHECK: define float @test_UnionF32(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } + +pub union UnionF32F32{a:f32, b:f32} + +// CHECK: define float @test_UnionF32F32(float %arg0) +#[no_mangle] +pub extern fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } + +pub union UnionF32U32{a:f32, b:u32} + +// CHECK: define i32 @test_UnionF32U32(i32) +#[no_mangle] +pub extern fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } + +pub union UnionU128{a:u128} +// CHECK: define i128 @test_UnionU128(i128 %arg0) +#[no_mangle] +pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } + +#[repr(C)] +pub union CUnionU128{a:u128} +// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0) +#[no_mangle] +pub fn test_CUnionU128(_: CUnionU128) { loop {} } + From 547ac5ef0a2c34fb62611bddb4c45f57049f8f64 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 14 Nov 2018 10:56:45 +1300 Subject: [PATCH 10/36] save-analysis: be even more aggressive about ignorning macro-generated defs --- src/librustc_save_analysis/dump_visitor.rs | 12 +++++++----- src/librustc_save_analysis/span_utils.rs | 6 +----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9bc3fbe7c245..c65cd6a5ba74 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -658,11 +658,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { impl_items: &'l [ast::ImplItem], ) { if let Some(impl_data) = self.save_ctxt.get_item_data(item) { - if let super::Data::RelationData(rel, imp) = impl_data { - self.dumper.dump_relation(rel); - self.dumper.dump_impl(imp); - } else { - span_bug!(item.span, "unexpected data kind: {:?}", impl_data); + if !self.span.filter_generated(item.span) { + if let super::Data::RelationData(rel, imp) = impl_data { + self.dumper.dump_relation(rel); + self.dumper.dump_impl(imp); + } else { + span_bug!(item.span, "unexpected data kind: {:?}", impl_data); + } } } self.visit_ty(&typ); diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 902353da13f7..06b4f33b5db3 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -124,14 +124,10 @@ impl<'a> SpanUtils<'a> { /// Used to filter out spans of minimal value, /// such as references to macro internal variables. pub fn filter_generated(&self, span: Span) -> bool { - if span.is_dummy() { + if generated_code(span) { return true; } - if !generated_code(span) { - return false; - } - //If the span comes from a fake source_file, filter it. !self.sess .source_map() From ec7d69bef2b67bd9cc8036d29569490a2686a37f Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 2 Nov 2018 15:08:51 +0100 Subject: [PATCH 11/36] Distinguish between placeholder kinds --- src/librustc/infer/canonical/mod.rs | 6 +++--- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/infer/mod.rs | 2 +- src/librustc/infer/nll_relate/mod.rs | 4 ++-- src/librustc/ty/mod.rs | 21 ++++++++++++++++--- src/librustc/ty/sty.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- .../borrow_check/error_reporting.rs | 4 ++-- .../borrow_check/nll/region_infer/mod.rs | 2 +- .../borrow_check/nll/region_infer/values.rs | 18 ++++++++-------- .../borrow_check/nll/type_check/mod.rs | 2 +- .../borrow_check/nll/type_check/relate_tys.rs | 5 ++++- 12 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index f7eb7118f412..41839d61d326 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -142,7 +142,7 @@ pub enum CanonicalVarKind { /// A "placeholder" that represents "any region". Created when you /// are solving a goal like `for<'a> T: Foo<'a>` to represent the /// bound region `'a`. - PlaceholderRegion(ty::Placeholder), + PlaceholderRegion(ty::PlaceholderRegion), } impl CanonicalVarKind { @@ -374,9 +374,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { universe_map(ui), ).into(), - CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, name }) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::Placeholder { + let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name, }; diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 642382bcf0fa..10f4080b37e8 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let next_universe = self.create_next_universe(); let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { - self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, name: br, })) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4ddf47c88ddb..91175b643cd8 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -411,7 +411,7 @@ pub enum NLLRegionVariableOrigin { /// "Universal" instantiation of a higher-ranked region (e.g., /// from a `for<'a> T` binder). Meant to represent "any region". - Placeholder(ty::Placeholder), + Placeholder(ty::PlaceholderRegion), Existential, } diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index e003c1989e09..9bdbf77fee0a 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -95,7 +95,7 @@ pub trait TypeRelatingDelegate<'tcx> { /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then /// we will invoke this method to instantiate `'b` with a /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>; + fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; /// Creates a new existential region in the given universe. This /// is used when handling subtyping and type variables -- if we @@ -176,7 +176,7 @@ where universe }); - let placeholder = ty::Placeholder { universe, name: br }; + let placeholder = ty::PlaceholderRegion { universe, name: br }; delegate.next_placeholder_region(placeholder) } else { delegate.next_existential_region_var() diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8197136d189a..51e094360699 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1544,12 +1544,27 @@ impl UniverseIndex { /// universe are just two regions with an unknown relationship to one /// another. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)] -pub struct Placeholder { +pub struct Placeholder { pub universe: UniverseIndex, - pub name: BoundRegion, + pub name: T, } -impl_stable_hash_for!(struct Placeholder { universe, name }); +impl<'a, 'gcx, T> HashStable> for Placeholder + where T: HashStable> +{ + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher + ) { + self.universe.hash_stable(hcx, hasher); + self.name.hash_stable(hcx, hasher); + } +} + +pub type PlaceholderRegion = Placeholder; + +pub type PlaceholderType = Placeholder; /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bd3a34cae90f..5c01f1cc3e4d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1165,7 +1165,7 @@ pub enum RegionKind { /// A placeholder region - basically the higher-ranked version of ReFree. /// Should not exist after typeck. - RePlaceholder(ty::Placeholder), + RePlaceholder(ty::PlaceholderRegion), /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e44c0c05bb1a..513a353c7503 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -792,7 +792,7 @@ define_print! { } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { write!(f, "{}", br) } ty::ReScope(scope) if cx.identify_regions => { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3c4d8e09fc16..4ccd26bee8b8 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -2193,7 +2193,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { match ty.sty { ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) | ty::TyKind::Ref( - ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }), + ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, ) => with_highlight_region_for_bound_region(*br, counter, || ty.to_string()), @@ -2207,7 +2207,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { match ty.sty { ty::TyKind::Ref(region, _, _) => match region { ty::RegionKind::ReLateBound(_, br) - | ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { with_highlight_region_for_bound_region(*br, counter, || region.to_string()) } _ => region.to_string(), diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 376f44592427..6a1dc50c67a0 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1230,7 +1230,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir: &Mir<'tcx>, _mir_def_id: DefId, longer_fr: RegionVid, - placeholder: ty::Placeholder, + placeholder: ty::PlaceholderRegion, ) { debug!( "check_bound_universal_region(fr={:?}, placeholder={:?})", diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 2b7ef38d3edf..69e2c896d33e 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -150,7 +150,7 @@ crate enum RegionElement { /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` /// type). - PlaceholderRegion(ty::Placeholder), + PlaceholderRegion(ty::PlaceholderRegion), } /// When we initially compute liveness, we use a bit matrix storing @@ -219,17 +219,17 @@ impl LivenessValues { } } -/// Maps from `ty::Placeholder` values that are used in the rest of +/// Maps from `ty::PlaceholderRegion` values that are used in the rest of /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. #[derive(Default)] crate struct PlaceholderIndices { - to_index: FxHashMap, - from_index: IndexVec, + to_index: FxHashMap, + from_index: IndexVec, } impl PlaceholderIndices { - crate fn insert(&mut self, placeholder: ty::Placeholder) -> PlaceholderIndex { + crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { let PlaceholderIndices { to_index, from_index, @@ -239,11 +239,11 @@ impl PlaceholderIndices { .or_insert_with(|| from_index.push(placeholder)) } - crate fn lookup_index(&self, placeholder: ty::Placeholder) -> PlaceholderIndex { + crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { self.to_index[&placeholder] } - crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::Placeholder { + crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion { self.from_index[placeholder] } @@ -375,7 +375,7 @@ impl RegionValues { crate fn placeholders_contained_in<'a>( &'a self, r: N, - ) -> impl Iterator + 'a { + ) -> impl Iterator + 'a { self.placeholders .row(r) .into_iter() @@ -432,7 +432,7 @@ impl ToElementIndex for RegionVid { } } -impl ToElementIndex for ty::Placeholder { +impl ToElementIndex for ty::PlaceholderRegion { fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { let index = values.placeholder_indices.lookup_index(self); values.placeholders.insert(row, index) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 2193dba9fcac..c6b3afba389a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -777,7 +777,7 @@ impl MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, infcx: &InferCtxt<'_, '_, 'tcx>, - placeholder: ty::Placeholder, + placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); match self.placeholder_index_to_region.get(placeholder_index) { diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index b82efb29f6e5..cf4f91308078 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -84,7 +84,10 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { } } - fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx> { + fn next_placeholder_region( + &mut self, + placeholder: ty::PlaceholderRegion + ) -> ty::Region<'tcx> { if let Some(borrowck_context) = &mut self.borrowck_context { borrowck_context.constraints.placeholder_region(self.infcx, placeholder) } else { From 669cf7bdc9ad41851f4db146c3de6ca0a9ea2df8 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 2 Nov 2018 18:48:24 +0100 Subject: [PATCH 12/36] Introduce `TyKind::Placeholder` variant --- src/librustc/ich/impls_ty.rs | 3 +++ src/librustc/infer/canonical/canonicalizer.rs | 1 + src/librustc/infer/freshen.rs | 6 +++--- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/query/dropck_outlives.rs | 1 + src/librustc/traits/select.rs | 3 +++ src/librustc/ty/context.rs | 2 +- src/librustc/ty/error.rs | 1 + src/librustc/ty/fast_reject.rs | 2 +- src/librustc/ty/flags.rs | 1 + src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 4 +++- src/librustc/ty/mod.rs | 1 + src/librustc/ty/outlives.rs | 1 + src/librustc/ty/structural_impls.rs | 2 ++ src/librustc/ty/sty.rs | 5 +++++ src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 2 +- src/librustc/ty/wf.rs | 1 + src/librustc/util/ppaux.rs | 5 ++++- src/librustc_codegen_llvm/debuginfo/type_names.rs | 1 + src/librustc_lint/types.rs | 1 + src/librustc_mir/monomorphize/item.rs | 1 + src/librustc_traits/chalk_context/program_clauses.rs | 1 + src/librustc_traits/dropck_outlives.rs | 2 +- src/librustc_traits/lowering/environment.rs | 1 + src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 1 + src/librustdoc/clean/mod.rs | 1 + 30 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f..4da026b6473a 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -676,6 +676,9 @@ for ty::TyKind<'gcx> Bound(bound_ty) => { bound_ty.hash_stable(hcx, hasher); } + ty::Placeholder(placeholder_ty) => { + placeholder_ty.hash_stable(hcx, hasher); + } Foreign(def_id) => { def_id.hash_stable(hcx, hasher); } diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 61a861a8a1cd..52bbbc73e37c 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -380,6 +380,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> | ty::Never | ty::Tuple(..) | ty::Projection(..) + | ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Foreign(..) | ty::Param(..) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index b53444992fa2..d17cf0c7b47a 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -170,9 +170,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } - ty::Bound(..) => - bug!("encountered bound ty during freshening"), - ty::Generator(..) | ty::Bool | ty::Char | @@ -200,6 +197,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::Opaque(..) => { t.super_fold_with(self) } + + ty::Placeholder(..) | + ty::Bound(..) => bug!("unexpected type {:?}", t), } } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 71b77909b82a..b7a84c99308f 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -455,7 +455,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { false } - ty::Bound(..) | ty::Infer(..) => match in_crate { + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { InCrate::Local => false, // The inference variable might be unified with a local // type in that remote crate. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2761a954cea8..d757cb220c6a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Generator(..) => Some(18), ty::Foreign(..) => Some(19), ty::GeneratorWitness(..) => Some(20), - ty::Bound(..) | ty::Infer(..) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 62317f074764..678c60046e95 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -251,6 +251,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> | ty::Projection(..) | ty::Param(_) | ty::Opaque(..) + | ty::Placeholder(..) | ty::Infer(_) | ty::Bound(..) | ty::Generator(..) => false, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 550c27ca0ab8..6a91ad59d98e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2470,6 +2470,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Infer(ty::TyVar(_)) => Ambiguous, ty::UnnormalizedProjection(..) + | ty::Placeholder(..) | ty::Bound(_) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -2555,6 +2556,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::UnnormalizedProjection(..) + | ty::Placeholder(..) | ty::Bound(_) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -2594,6 +2596,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | ty::Char => Vec::new(), ty::UnnormalizedProjection(..) + | ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index cdfe8f53b854..b1305c36d425 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2250,7 +2250,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, + Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, Placeholder, Generator, GeneratorWitness, Dynamic, Closure, Tuple, Bound, Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 4737c72b1ef0..e78759e3e796 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -212,6 +212,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integral variable".into(), ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(), + ty::Placeholder(..) => "placeholder type".into(), ty::Bound(_) | ty::Infer(ty::FreshTy(_)) => "fresh type".into(), ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 380f95993f8f..8304e3638157 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -122,7 +122,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Foreign(def_id) => { Some(ForeignSimplifiedType(def_id)) } - ty::Bound(..) | ty::Infer(_) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None, } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 0764f363250d..9cdeb300393b 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -74,6 +74,7 @@ impl FlagComputation { &ty::Uint(_) | &ty::Never | &ty::Str | + &ty::Placeholder(..) | &ty::Foreign(..) => { } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index d44ba0308415..f6c90ab0a1ad 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -515,6 +515,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { ty::Str | ty::FnPtr(_) | ty::Projection(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Param(_) | ty::Opaque(..) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 877bd5a82e6a..04bcf60a86af 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1133,6 +1133,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } ty::Bound(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { @@ -1717,7 +1718,8 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } ty::Projection(_) | ty::UnnormalizedProjection(..) | ty::Bound(..) | - ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => { + ty::Placeholder(..) | ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | + ty::Error => { bug!("TyLayout::field_type: unexpected type `{}`", this.ty) } }) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 51e094360699..9354a4d00799 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2396,6 +2396,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + Placeholder(..) | Bound(..) | Infer(..) => { bug!("unexpected type `{:?}` in sized_constraint_for_ty", diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 7fac88a3d78f..0e3fc62e4ca9 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -155,6 +155,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::FnDef(..) | // OutlivesFunction (*) ty::FnPtr(_) | // OutlivesFunction (*) ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::Placeholder(..) | ty::Bound(..) | ty::Error => { // (*) Bare functions and traits are both binders. In the diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e92f92dce63d..d6aeb288b5cd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -746,6 +746,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Infer(_) | ty::Param(..) | ty::Bound(..) | + ty::Placeholder(..) | ty::Never | ty::Foreign(..) => return self }; @@ -792,6 +793,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Error | ty::Infer(_) | ty::Bound(..) | + ty::Placeholder(..) | ty::Param(..) | ty::Never | ty::Foreign(..) => false, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5c01f1cc3e4d..7e6673a3dcdc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -203,6 +203,9 @@ pub enum TyKind<'tcx> { /// Bound type variable, used only when preparing a trait query. Bound(BoundTy), + /// A placeholder type - universally quantified higher-ranked type. + Placeholder(ty::PlaceholderType), + /// A type variable used during type checking. Infer(InferTy), @@ -1890,6 +1893,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { Foreign(..) | Param(_) | Bound(..) | + Placeholder(..) | Infer(_) | Error => {} } @@ -1954,6 +1958,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { ty::Infer(ty::TyVar(_)) => false, ty::Bound(_) | + ty::Placeholder(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 3d0c54d6b0a5..f0885f960516 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -952,7 +952,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Can refer to a type which may drop. // FIXME(eddyb) check this against a ParamEnv. ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) | - ty::Opaque(..) | ty::Infer(_) | ty::Error => true, + ty::Placeholder(..) | ty::Opaque(..) | ty::Infer(_) | ty::Error => true, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 284c595ee2d9..82b95b9df603 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -82,7 +82,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Infer(_) | ty::Param(_) | ty::Never | ty::Error | - ty::Bound(..) | ty::Foreign(..) => { + ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => { } ty::Array(ty, len) => { push_const(stack, len); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 1336eac63f88..6ae0793d9247 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -259,6 +259,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::Never | ty::Param(_) | ty::Bound(..) | + ty::Placeholder(..) | ty::Foreign(..) => { // WfScalar, WfParameter, etc } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 513a353c7503..1b072bec22c0 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -18,7 +18,7 @@ use ty::{Bool, Char, Adt}; use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; use ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; -use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer}; +use ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; @@ -1144,6 +1144,9 @@ define_print! { data.print(f, cx)?; write!(f, ")") } + Placeholder(placeholder) => { + write!(f, "Placeholder({:?})", placeholder) + } Opaque(def_id, substs) => { if cx.is_verbose { return write!(f, "Opaque({:?}, {:?})", def_id, substs); diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index eb5ae81b2184..ceefed739277 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -171,6 +171,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } ty::Error | ty::Infer(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Bound(..) | diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 0e2d041b1ffd..82ace620c8ab 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -727,6 +727,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 9d69a5669b1c..cf754df75019 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::Error | ty::Bound(..) | ty::Infer(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Param(_) | diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index 31f97b72e192..5592d2a583cf 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -418,6 +418,7 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { } ty::GeneratorWitness(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Infer(..) | ty::Bound(..) | diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index af64522f1839..9ab86daf6544 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -274,7 +274,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - ty::Bound(..) | ty::Infer(..) | ty::Error => { + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => { // By the time this code runs, all type variables ought to // be fully resolved. Err(NoSolution) diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 54f0c6e8da78..c3573f47cebf 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -114,6 +114,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::Tuple(..) | ty::Never | ty::Infer(..) | + ty::Placeholder(..) | ty::Bound(..) => (), ty::GeneratorWitness(..) | diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 3f0a35312444..c35aee7883f4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -128,7 +128,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)), ty::Param(ref p) => Some(PointerKind::OfParam(p)), // Insufficient type information. - ty::Bound(..) | ty::Infer(_) => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None, ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) | diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 47d34c909961..ed32e5a8d9b3 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -336,6 +336,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Bound(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 931ba21f6e4b..81c83d3d908d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2744,6 +2744,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton) ty::Bound(..) => panic!("Bound"), + ty::Placeholder(..) => panic!("Placeholder"), ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::Infer(..) => panic!("Infer"), From 4fefd64006579ad0b002b117b831164b43fb3072 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 2 Nov 2018 18:56:30 +0100 Subject: [PATCH 13/36] Rename some occurences of `skol` to `placeholder` --- src/librustc/traits/project.rs | 4 ++-- src/librustc/traits/query/normalize.rs | 2 +- src/librustc/ty/fold.rs | 8 ++++---- src/librustc/ty/mod.rs | 6 +++--- src/librustc/ty/sty.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/writeback.rs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b59bd0e23887..0aabb7ad713f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -424,7 +424,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.selcx.tcx().global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() || substs.has_skol() { + if substs.needs_infer() || substs.has_placeholders() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { @@ -1656,7 +1656,7 @@ impl<'tcx> ProjectionCache<'tcx> { } pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_skol()); + self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); } pub fn commit(&mut self, snapshot: &ProjectionCacheSnapshot) { diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 59b086e35de3..91b2ba301c31 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -202,7 +202,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.infcx.tcx.global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() || substs.has_skol() { + if substs.needs_infer() || substs.has_placeholders() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index a897afa0ca66..429048f0ee3c 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -102,14 +102,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) } - fn has_skol(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_SKOL) + fn has_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } - fn has_re_skol(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_SKOL) + fn has_re_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) } fn has_closure_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9354a4d00799..c0ac4b96bd67 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -433,7 +433,7 @@ bitflags! { const HAS_SELF = 1 << 1; const HAS_TY_INFER = 1 << 2; const HAS_RE_INFER = 1 << 3; - const HAS_RE_SKOL = 1 << 4; + const HAS_RE_PLACEHOLDER = 1 << 4; /// Does this have any `ReEarlyBound` regions? Used to /// determine whether substitition is required, since those @@ -479,7 +479,7 @@ bitflags! { TypeFlags::HAS_SELF.bits | TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_SKOL.bits | + TypeFlags::HAS_RE_PLACEHOLDER.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits | TypeFlags::HAS_FREE_REGIONS.bits | TypeFlags::HAS_TY_ERR.bits | @@ -1646,7 +1646,7 @@ impl<'tcx> ParamEnv<'tcx> { } Reveal::All => { - if value.has_skol() + if value.has_placeholders() || value.needs_infer() || value.has_param_types() || value.has_self_ty() diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7e6673a3dcdc..cd69d31a0045 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1465,7 +1465,7 @@ impl RegionKind { } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_SKOL; + flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } ty::ReLateBound(..) => { flags = flags | TypeFlags::HAS_RE_LATE_BOUND; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 4c06cae1d075..87d65dbfd797 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1494,7 +1494,7 @@ impl<'tcx> Candidate<'tcx> { // `WhereClausePick`. assert!( !trait_ref.skip_binder().substs.needs_infer() - && !trait_ref.skip_binder().substs.has_skol() + && !trait_ref.skip_binder().substs.has_placeholders() ); WhereClausePick(trait_ref.clone()) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d968bf222aa0..e7e9288058c0 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -115,7 +115,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_skol()); + assert!(!ty.needs_infer() && !ty.has_placeholders()); self.tables.node_types_mut().insert(hir_id, ty); } @@ -580,7 +580,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) { let substs = self.resolve(&substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); - assert!(!substs.needs_infer() && !substs.has_skol()); + assert!(!substs.needs_infer() && !substs.has_placeholders()); self.tables.node_substs_mut().insert(hir_id, substs); } From c181d51a5455b839b0421536234b56de5d58c97e Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 2 Nov 2018 19:25:20 +0100 Subject: [PATCH 14/36] Add `HAS_TY_PLACEHOLDER` flag --- src/librustc/infer/canonical/canonicalizer.rs | 8 ++++++-- src/librustc/ty/flags.rs | 5 ++++- src/librustc/ty/fold.rs | 2 +- src/librustc/ty/mod.rs | 5 ++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 52bbbc73e37c..741ba3b7c064 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -409,9 +409,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { V: TypeFoldable<'tcx> + Lift<'gcx>, { let needs_canonical_flags = if canonicalize_region_mode.any() { - TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX + TypeFlags::KEEP_IN_LOCAL_TCX | + TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` + TypeFlags::HAS_TY_PLACEHOLDER } else { - TypeFlags::KEEP_IN_LOCAL_TCX + TypeFlags::KEEP_IN_LOCAL_TCX | + TypeFlags::HAS_RE_PLACEHOLDER | + TypeFlags::HAS_TY_PLACEHOLDER }; let gcx = tcx.global_tcx(); diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 9cdeb300393b..3b84e7b54bdf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -74,7 +74,6 @@ impl FlagComputation { &ty::Uint(_) | &ty::Never | &ty::Str | - &ty::Placeholder(..) | &ty::Foreign(..) => { } @@ -120,6 +119,10 @@ impl FlagComputation { self.add_binder(bound_ty.index); } + &ty::Placeholder(..) => { + self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); + } + &ty::Infer(infer) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right? self.add_flags(TypeFlags::HAS_TY_INFER); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 429048f0ee3c..c3571087efe9 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -103,7 +103,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) } fn has_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) + self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER) } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c0ac4b96bd67..947a9a1f25be 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -468,6 +468,8 @@ bitflags! { /// if a global bound is safe to evaluate. const HAS_RE_LATE_BOUND = 1 << 13; + const HAS_TY_PLACEHOLDER = 1 << 14; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -487,7 +489,8 @@ bitflags! { TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_RE_LATE_BOUND.bits; + TypeFlags::HAS_RE_LATE_BOUND.bits | + TypeFlags::HAS_TY_PLACEHOLDER.bits; } } From df07c9d45c526e2c189c163ded29558341f6e5e0 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 2 Nov 2018 19:46:30 +0100 Subject: [PATCH 15/36] Handle placeholder types in canonicalization --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/infer/canonical/canonicalizer.rs | 43 +++++++++++++++---- src/librustc/infer/canonical/mod.rs | 36 +++++++++++----- src/librustc/infer/mod.rs | 22 ++++++++++ src/librustc/infer/type_variable.rs | 2 +- 5 files changed, 85 insertions(+), 21 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 4da026b6473a..982f23f5c4a0 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1088,12 +1088,13 @@ impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo { impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind { Ty(k), + PlaceholderTy(placeholder), Region(ui), PlaceholderRegion(placeholder), }); impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind { - General, + General(ui), Int, Float }); diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 741ba3b7c064..88c3a4e5061a 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -339,11 +339,35 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { - ty::Infer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), + ty::Infer(ty::TyVar(vid)) => { + match self.infcx.unwrap().probe_ty_var(vid) { + // `t` could be a float / int variable: canonicalize that instead + Ok(t) => self.fold_ty(t), + + // `TyVar(vid)` is unresolved, track its universe index in the canonicalized + // result + Err(ui) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) + }, + t + ) + } + } - ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), + ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + }, + t + ), - ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), + ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) + }, + t + ), ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -351,6 +375,13 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> bug!("encountered a fresh type during canonicalization") } + ty::Placeholder(placeholder) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::PlaceholderTy(placeholder) + }, + t + ), + ty::Bound(bound_ty) => { if bound_ty.index >= self.binder_index { bug!("escaping bound type during canonicalization") @@ -380,7 +411,6 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> | ty::Never | ty::Tuple(..) | ty::Projection(..) - | ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Foreign(..) | ty::Param(..) @@ -579,15 +609,12 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// if `ty_var` is bound to anything; if so, canonicalize /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. - fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { + fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.infcx.expect("encountered ty-var without infcx"); let bound_to = infcx.shallow_resolve(ty_var); if bound_to != ty_var { self.fold_ty(bound_to) } else { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Ty(ty_kind), - }; let var = self.canonical_var(info, ty_var.into()); self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var))) } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 41839d61d326..230f8958b338 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -122,6 +122,7 @@ impl CanonicalVarInfo { pub fn is_existential(&self) -> bool { match self.kind { CanonicalVarKind::Ty(_) => true, + CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, } @@ -136,6 +137,9 @@ pub enum CanonicalVarKind { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), + /// A "placeholder" that represents "any type". + PlaceholderTy(ty::PlaceholderType), + /// Region variable `'?R`. Region(ty::UniverseIndex), @@ -148,12 +152,12 @@ pub enum CanonicalVarKind { impl CanonicalVarKind { pub fn universe(self) -> ty::UniverseIndex { match self { - // At present, we don't support higher-ranked - // quantification over types, so all type variables are in - // the root universe. - CanonicalVarKind::Ty(_) => ty::UniverseIndex::ROOT, + CanonicalVarKind::Ty(kind) => match kind { + CanonicalTyVarKind::General(ui) => ui, + CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, + } - // Region variables can be created in sub-universes. + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, } @@ -168,7 +172,7 @@ impl CanonicalVarKind { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. - General, + General(ty::UniverseIndex), /// Integral type variable `?I` (that can only be unified with integral types). Int, @@ -358,8 +362,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { match cv_info.kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { - CanonicalTyVarKind::General => { - self.next_ty_var(TypeVariableOrigin::MiscVariable(span)) + CanonicalTyVarKind::General(ui) => { + self.next_ty_var_in_universe( + TypeVariableOrigin::MiscVariable(span), + universe_map(ui) + ) } CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), @@ -369,6 +376,15 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ty.into() } + CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped = ty::PlaceholderType { + universe: universe_mapped, + name, + }; + self.tcx.mk_ty(ty::Placeholder(placeholder_mapped)).into() + } + CanonicalVarKind::Region(ui) => self.next_region_var_in_universe( RegionVariableOrigin::MiscVariable(span), universe_map(ui), @@ -380,9 +396,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { universe: universe_mapped, name, }; - self.tcx - .mk_region(ty::RePlaceholder(placeholder_mapped)) - .into() + self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into() } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 91175b643cd8..11082476f45d 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -972,6 +972,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(false, origin)) } + pub fn next_ty_var_in_universe( + &self, + origin: TypeVariableOrigin, + universe: ty::UniverseIndex + ) -> Ty<'tcx> { + let vid = self.type_variables + .borrow_mut() + .new_var(universe, false, origin); + self.tcx.mk_var(vid) + } + pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(true, origin)) } @@ -1227,6 +1238,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// If `TyVar(vid)` resolves to a type, return that type. Else, return the + /// universe index of `TyVar(vid)`. + pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { + use self::type_variable::TypeVariableValue; + + match self.type_variables.borrow_mut().probe(vid) { + TypeVariableValue::Known { value } => Ok(value), + TypeVariableValue::Unknown { universe } => Err(universe), + } + } + pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { self.inlined_shallow_resolve(typ) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 39bf59a7a4ec..6eb2bc9250e5 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -72,7 +72,7 @@ pub type TypeVariableMap = FxHashMap; struct TypeVariableData { origin: TypeVariableOrigin, - diverging: bool + diverging: bool, } #[derive(Copy, Clone, Debug)] From 920feb6bcfb54376465bd68d2a0c5ad77b06daf9 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 3 Nov 2018 14:52:37 +0100 Subject: [PATCH 16/36] Instantiate all bound vars universally --- src/librustc/infer/higher_ranked/mod.rs | 43 ++++++++++++++++--------- src/librustc/infer/mod.rs | 6 ++-- src/librustc/traits/project.rs | 2 +- src/librustc/traits/select.rs | 10 +++--- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 10f4080b37e8..6be811f2aea1 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. let (b_prime, placeholder_map) = - self.infcx.replace_late_bound_regions_with_placeholders(b); + self.infcx.replace_bound_vars_with_placeholders(b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- @@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // First, we instantiate each bound region in the matcher // with a placeholder region. let ((a_match, a_value), placeholder_map) = - self.infcx.replace_late_bound_regions_with_placeholders(a_pair); + self.infcx.replace_bound_vars_with_placeholders(a_pair); debug!("higher_ranked_match: a_match={:?}", a_match); debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map); @@ -314,10 +314,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { region_vars } - /// Replace all regions bound by `binder` with placeholder regions and - /// return a map indicating which bound-region was replaced with what - /// placeholder region. This is the first step of checking subtyping - /// when higher-ranked things are involved. + /// Replace all regions (resp. types) bound by `binder` with placeholder + /// regions (resp. types) and return a map indicating which bound-region + /// was replaced with what placeholder region. This is the first step of + /// checking subtyping when higher-ranked things are involved. /// /// **Important:** you must call this function from within a snapshot. /// Moreover, before committing the snapshot, you must eventually call @@ -330,26 +330,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the [rustc guide]. /// /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html - pub fn replace_late_bound_regions_with_placeholders( + pub fn replace_bound_vars_with_placeholders( &self, - binder: &ty::Binder, + binder: &ty::Binder ) -> (T, PlaceholderMap<'tcx>) where - T : TypeFoldable<'tcx>, + T: TypeFoldable<'tcx> { let next_universe = self.create_next_universe(); - let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { + let fld_r = |br| { self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, name: br, })) - }); + }; + + let fld_t = |bound_ty: ty::BoundTy| { + self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + universe: next_universe, + name: bound_ty.var, + })) + }; + + let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t); - debug!("replace_late_bound_regions_with_placeholders(binder={:?}, result={:?}, map={:?})", - binder, - result, - map); + debug!( + "replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})", + binder, + result, + map + ); (result, map) } @@ -530,7 +541,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Pops the placeholder regions found in `placeholder_map` from the region /// inference context. Whenever you create placeholder regions via - /// `replace_late_bound_regions_with_placeholders`, they must be popped before you + /// `replace_bound_vars_with_placeholders`, they must be popped before you /// commit the enclosing snapshot (if you do not commit, e.g. within a /// probe or as a result of an error, then this is not necessary, as /// popping happens as part of the rollback). diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 11082476f45d..c1bfc1333852 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -227,7 +227,7 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { universe: Cell, } -/// A map returned by `replace_late_bound_regions_with_placeholders()` +/// A map returned by `replace_bound_vars_with_placeholders()` /// indicating the placeholder region that each late-bound region was /// replaced with. pub type PlaceholderMap<'tcx> = BTreeMap>; @@ -935,7 +935,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { b, }, placeholder_map, - ) = self.replace_late_bound_regions_with_placeholders(predicate); + ) = self.replace_bound_vars_with_placeholders(predicate); let cause_span = cause.span; let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -952,7 +952,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = - self.replace_late_bound_regions_with_placeholders(predicate); + self.replace_bound_vars_with_placeholders(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 0aabb7ad713f..e7b5fc3d1ffd 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -204,7 +204,7 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|snapshot| { let (placeholder_predicate, placeholder_map) = - infcx.replace_late_bound_regions_with_placeholders(&obligation.predicate); + infcx.replace_bound_vars_with_placeholders(&obligation.predicate); let skol_obligation = obligation.with(placeholder_predicate); let r = match project_and_unify_type(selcx, &skol_obligation) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6a91ad59d98e..0cb071e3196a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1726,7 +1726,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let poly_trait_predicate = self.infcx() .resolve_type_vars_if_possible(&obligation.predicate); let (skol_trait_predicate, placeholder_map) = self.infcx() - .replace_late_bound_regions_with_placeholders(&poly_trait_predicate); + .replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( "match_projection_obligation_against_definition_bounds: \ skol_trait_predicate={:?} placeholder_map={:?}", @@ -2685,7 +2685,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.in_snapshot(|this, snapshot| { let (skol_ty, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&ty); + .replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, mut obligations, @@ -2919,7 +2919,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let trait_obligations: Vec> = self.in_snapshot(|this, snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&poly_trait_ref); + .replace_bound_vars_with_placeholders(&poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); this.impl_or_trait_obligations( cause, @@ -3122,7 +3122,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.in_snapshot(|this, snapshot| { let (predicate, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&obligation.predicate); + .replace_bound_vars_with_placeholders(&obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; @@ -3585,7 +3585,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } let (skol_obligation, placeholder_map) = self.infcx() - .replace_late_bound_regions_with_placeholders(&obligation.predicate); + .replace_bound_vars_with_placeholders(&obligation.predicate); let skol_obligation_trait_ref = skol_obligation.trait_ref; let impl_substs = self.infcx From 05f1847570a76c0e8554502f804358f48056f8e0 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 3 Nov 2018 15:15:33 +0100 Subject: [PATCH 17/36] Move `BoundTy` debruijn index to the `TyKind` enum variant --- src/librustc/ich/impls_ty.rs | 3 ++- src/librustc/infer/canonical/canonicalizer.rs | 8 ++++---- .../infer/canonical/query_response.rs | 8 ++++---- src/librustc/traits/select.rs | 6 +++--- src/librustc/traits/structural_impls.rs | 2 +- src/librustc/ty/error.rs | 2 +- src/librustc/ty/flags.rs | 4 ++-- src/librustc/ty/fold.rs | 19 ++++++++----------- src/librustc/ty/sty.rs | 12 +++++------- src/librustc/ty/subst.rs | 19 ++++++++++--------- src/librustc/util/ppaux.rs | 6 +++--- .../chalk_context/program_clauses.rs | 19 +++++++++++-------- src/librustc_traits/lowering/environment.rs | 2 +- src/librustc_traits/lowering/mod.rs | 3 ++- 14 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 982f23f5c4a0..633007bb5da3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -673,7 +673,8 @@ for ty::TyKind<'gcx> Param(param_ty) => { param_ty.hash_stable(hcx, hasher); } - Bound(bound_ty) => { + Bound(debruijn, bound_ty) => { + debruijn.hash_stable(hcx, hasher); bound_ty.hash_stable(hcx, hasher); } ty::Placeholder(placeholder_ty) => { diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 88c3a4e5061a..93ef4553f8fc 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -23,7 +23,7 @@ use infer::InferCtxt; use std::sync::atomic::Ordering; use ty::fold::{TypeFoldable, TypeFolder}; use ty::subst::Kind; -use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; +use ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -382,8 +382,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> t ), - ty::Bound(bound_ty) => { - if bound_ty.index >= self.binder_index { + ty::Bound(debruijn, _) => { + if debruijn >= self.binder_index { bug!("escaping bound type during canonicalization") } else { t @@ -616,7 +616,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { self.fold_ty(bound_to) } else { let var = self.canonical_var(info, ty_var.into()); - self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var))) + self.tcx().mk_ty(ty::Bound(self.binder_index, var.into())) } } } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index f4607f7a9092..7a3f79530ffc 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -435,21 +435,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { match result_value.unpack() { UnpackedKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(b) = result_value.sty { + if let ty::Bound(debruijn, b) = result_value.sty { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(b.index, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); } } UnpackedKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let &ty::RegionKind::ReLateBound(index, br) = result_value { + if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(index, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); opt_values[br.assert_bound_var()] = Some(*original_value); } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 0cb071e3196a..0f59f478cb41 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2471,7 +2471,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::UnnormalizedProjection(..) | ty::Placeholder(..) - | ty::Bound(_) + | ty::Bound(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2557,7 +2557,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::UnnormalizedProjection(..) | ty::Placeholder(..) - | ty::Bound(_) + | ty::Bound(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2601,7 +2601,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | ty::Param(..) | ty::Foreign(..) | ty::Projection(..) - | ty::Bound(_) + | ty::Bound(..) | ty::Infer(ty::TyVar(_)) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 3e417f10c449..36538ac0889d 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -324,7 +324,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { use syntax::symbol::Symbol; match t.sty { - ty::Bound(bound_ty) if bound_ty.index == self.binder_index => { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { self.types.insert( bound_ty.var.as_u32(), match bound_ty.kind { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index e78759e3e796..90022a770c11 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::Infer(ty::IntVar(_)) => "integral variable".into(), ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(), ty::Placeholder(..) => "placeholder type".into(), - ty::Bound(_) | + ty::Bound(..) => "bound type".into(), ty::Infer(ty::FreshTy(_)) => "fresh type".into(), ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 3b84e7b54bdf..1ea7e27c0dcd 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -115,8 +115,8 @@ impl FlagComputation { self.add_substs(&substs.substs); } - &ty::Bound(bound_ty) => { - self.add_binder(bound_ty.index); + &ty::Bound(debruijn, _) => { + self.add_binder(debruijn); } &ty::Placeholder(..) => { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index c3571087efe9..6214e5e88ee8 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -460,8 +460,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { - ty::Bound(bound_ty) => { - if bound_ty.index == self.current_index { + ty::Bound(debruijn, bound_ty) => { + if debruijn == self.current_index { let fld_t = &mut self.fld_t; let ty = fld_t(bound_ty); ty::fold::shift_vars( @@ -526,7 +526,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { T: TypeFoldable<'tcx> { // identity for bound types - let fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty)); + let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty)); self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) } @@ -722,16 +722,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { fn fold_ty(&mut self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> { match ty.sty { - ty::Bound(bound_ty) => { - if self.amount == 0 || bound_ty.index < self.current_index { + ty::Bound(debruijn, bound_ty) => { + if self.amount == 0 || debruijn < self.current_index { ty } else { - let shifted = ty::BoundTy { - index: bound_ty.index.shifted_in(self.amount), - var: bound_ty.var, - kind: bound_ty.kind, - }; - self.tcx.mk_ty(ty::Bound(shifted)) + self.tcx.mk_ty( + ty::Bound(debruijn.shifted_in(self.amount), bound_ty) + ) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index cd69d31a0045..3056abba9562 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -201,7 +201,7 @@ pub enum TyKind<'tcx> { Param(ParamTy), /// Bound type variable, used only when preparing a trait query. - Bound(BoundTy), + Bound(ty::DebruijnIndex, BoundTy), /// A placeholder type - universally quantified higher-ranked type. Placeholder(ty::PlaceholderType), @@ -1245,7 +1245,6 @@ newtype_index! { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct BoundTy { - pub index: DebruijnIndex, pub var: BoundVar, pub kind: BoundTyKind, } @@ -1256,13 +1255,12 @@ pub enum BoundTyKind { Param(InternedString), } -impl_stable_hash_for!(struct BoundTy { index, var, kind }); +impl_stable_hash_for!(struct BoundTy { var, kind }); impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) }); -impl BoundTy { - pub fn new(index: DebruijnIndex, var: BoundVar) -> Self { +impl From for BoundTy { + fn from(var: BoundVar) -> Self { BoundTy { - index, var, kind: BoundTyKind::Anon, } @@ -1957,7 +1955,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { ty::Infer(ty::TyVar(_)) => false, - ty::Bound(_) | + ty::Bound(..) | ty::Placeholder(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index b7f1731ba44e..342520398989 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -190,11 +190,12 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { Substs::for_item(tcx, def_id, |param, _| { match param.kind { ty::GenericParamDefKind::Type { .. } => { - tcx.mk_ty(ty::Bound(ty::BoundTy { - index: ty::INNERMOST, - var: ty::BoundVar::from(param.index), - kind: ty::BoundTyKind::Param(param.name), - })).into() + tcx.mk_ty( + ty::Bound(ty::INNERMOST, ty::BoundTy { + var: ty::BoundVar::from(param.index), + kind: ty::BoundTyKind::Param(param.name), + }) + ).into() } ty::GenericParamDefKind::Lifetime => { @@ -584,18 +585,18 @@ impl CanonicalUserSubsts<'tcx> { self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { UnpackedKind::Type(ty) => match ty.sty { - ty::Bound(b) => { + ty::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(b.index, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); cvar == b.var } _ => false, }, UnpackedKind::Lifetime(r) => match r { - ty::ReLateBound(index, br) => { + ty::ReLateBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*index, ty::INNERMOST); + assert_eq!(*debruijn, ty::INNERMOST); cvar == br.assert_bound_var() } _ => false, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1b072bec22c0..e86b93c55bf6 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1110,13 +1110,13 @@ define_print! { Infer(infer_ty) => write!(f, "{}", infer_ty), Error => write!(f, "[type error]"), Param(ref param_ty) => write!(f, "{}", param_ty), - Bound(bound_ty) => { + Bound(debruijn, bound_ty) => { match bound_ty.kind { ty::BoundTyKind::Anon => { - if bound_ty.index == ty::INNERMOST { + if debruijn == ty::INNERMOST { write!(f, "^{}", bound_ty.var.index()) } else { - write!(f, "^{}_{}", bound_ty.index.index(), bound_ty.var.index()) + write!(f, "^{}_{}", debruijn.index(), bound_ty.var.index()) } } diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index 5592d2a583cf..b8670e5e9143 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -59,7 +59,8 @@ fn assemble_clauses_from_assoc_ty_values<'tcx>( fn program_clauses_for_raw_ptr<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -88,9 +89,9 @@ fn program_clauses_for_fn_ptr<'tcx>( ) -> Clauses<'tcx> { let inputs_and_output = tcx.mk_type_list( (0..arity_and_output).into_iter() + .map(|i| ty::BoundVar::from(i)) // DebruijnIndex(1) because we are going to inject these in a `PolyFnSig` - .map(|i| ty::BoundTy::new(ty::DebruijnIndex::from(1usize), ty::BoundVar::from(i))) - .map(|t| tcx.mk_ty(ty::Bound(t))) + .map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into()))) ); let fn_sig = ty::Binder::bind(ty::FnSig { @@ -115,7 +116,8 @@ fn program_clauses_for_fn_ptr<'tcx>( fn program_clauses_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -151,7 +153,8 @@ fn program_clauses_for_array<'tcx>( length: &'tcx ty::Const<'tcx> ) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -188,8 +191,8 @@ fn program_clauses_for_tuple<'tcx>( ) -> Clauses<'tcx> { let type_list = tcx.mk_type_list( (0..arity).into_iter() - .map(|i| ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from(i))) - .map(|t| tcx.mk_ty(ty::Bound(t))) + .map(|i| ty::BoundVar::from(i)) + .map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into()))) ); let tuple_ty = tcx.mk_ty(ty::Tuple(type_list)); @@ -233,7 +236,7 @@ fn program_clauses_for_ref<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) ); let ty = tcx.mk_ty( - ty::Bound(ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(1))) + ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into()) ); let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index c3573f47cebf..519b0ac61058 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -55,7 +55,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) ); let ty = self.tcx.mk_ty( - ty::Bound(ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(1))) + ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into()) ); let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 83b90cf1bf20..6e88ff7bd9a0 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -513,7 +513,8 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>( .unwrap_or(0); // Add a new type param after the existing ones (`U` in the comment above). let ty_var = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(offset + 1)) + ty::INNERMOST, + ty::BoundVar::from_u32(offset + 1).into() ); // `ProjectionEq(>::AssocType = U)` From 3b1f74ccd831d568501aff45c91ddb9bc7a692f5 Mon Sep 17 00:00:00 2001 From: scalexm Date: Sat, 3 Nov 2018 16:08:50 +0100 Subject: [PATCH 18/36] Implement some instantiate / canonical routines --- src/librustc_traits/chalk_context/mod.rs | 165 ++++++++++++++++------- 1 file changed, 113 insertions(+), 52 deletions(-) diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index 0fd9f607a546..14d4be2b1787 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -11,7 +11,7 @@ mod program_clauses; use chalk_engine::fallible::Fallible as ChalkEngineFallible; -use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause}; +use chalk_engine::{context, hh::HhGoal, DelayedLiteral, Literal, ExClause}; use rustc::infer::canonical::{ Canonical, CanonicalVarValues, OriginalQueryValues, QueryRegionConstraint, QueryResponse, }; @@ -28,7 +28,7 @@ use rustc::traits::{ InEnvironment, }; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc::ty::subst::Kind; +use rustc::ty::subst::{Kind, UnpackedKind}; use rustc::ty::{self, TyCtxt}; use std::fmt::{self, Debug}; @@ -44,7 +44,7 @@ crate struct ChalkArenas<'gcx> { #[derive(Copy, Clone)] crate struct ChalkContext<'cx, 'gcx: 'cx> { _arenas: ChalkArenas<'gcx>, - _tcx: TyCtxt<'cx, 'gcx, 'gcx>, + tcx: TyCtxt<'cx, 'gcx, 'gcx>, } #[derive(Copy, Clone)] @@ -68,7 +68,7 @@ BraceStructTypeFoldableImpl! { } impl context::Context for ChalkArenas<'tcx> { - type CanonicalExClause = Canonical<'tcx, ExClause>; + type CanonicalExClause = Canonical<'tcx, ChalkExClause<'tcx>>; type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>; @@ -147,19 +147,29 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { /// - the environment and goal found by substitution `S` into `arg` fn instantiate_ucanonical_goal( &self, - _arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, + arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, + op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, ) -> R { - unimplemented!() + self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| { + let chalk_infcx = &mut ChalkInferenceContext { + infcx, + }; + op.with(chalk_infcx, subst, arg.environment, arg.goal) + }) } fn instantiate_ex_clause( &self, _num_universes: usize, - _canonical_ex_clause: &Canonical<'gcx, ChalkExClause<'gcx>>, - _op: impl context::WithInstantiatedExClause, Output = R>, + arg: &Canonical<'gcx, ChalkExClause<'gcx>>, + op: impl context::WithInstantiatedExClause, Output = R>, ) -> R { - unimplemented!() + self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| { + let chalk_infcx = &mut ChalkInferenceContext { + infcx, + }; + op.with(chalk_infcx,arg) + }) } /// True if this solution has no region constraints. @@ -186,14 +196,33 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } fn is_trivial_substitution( - _u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _canonical_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, + canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, ) -> bool { - unimplemented!() - } - - fn num_universes(_: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize { - 0 // FIXME + let subst = &canonical_subst.value.subst; + assert_eq!(u_canon.variables.len(), subst.var_values.len()); + subst.var_values + .iter_enumerated() + .all(|(cvar, kind)| match kind.unpack() { + UnpackedKind::Lifetime(r) => match r { + &ty::ReLateBound(debruijn, br) => { + debug_assert_eq!(debruijn, ty::INNERMOST); + cvar == br.assert_bound_var() + } + _ => false, + }, + UnpackedKind::Type(ty) => match ty.sty { + ty::Bound(debruijn, bound_ty) => { + debug_assert_eq!(debruijn, ty::INNERMOST); + cvar == bound_ty.var + } + _ => false, + }, + }) + } + + fn num_universes(canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize { + canon.max_universe.index() + 1 } /// Convert a goal G *from* the canonical universes *into* our @@ -214,39 +243,6 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } } -//impl context::UCanonicalGoalInEnvironment> -// for Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> -//{ -// fn canonical(&self) -> &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> { -// self -// } -// -// fn is_trivial_substitution( -// &self, -// canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, -// ) -> bool { -// let subst = &canonical_subst.value.subst; -// assert_eq!(self.canonical.variables.len(), subst.var_values.len()); -// subst -// .var_values -// .iter_enumerated() -// .all(|(cvar, kind)| match kind.unpack() { -// Kind::Lifetime(r) => match r { -// ty::ReCanonical(cvar1) => cvar == cvar1, -// _ => false, -// }, -// Kind::Type(ty) => match ty.sty { -// ty::Infer(ty::InferTy::CanonicalTy(cvar1)) => cvar == cvar1, -// _ => false, -// }, -// }) -// } -// -// fn num_universes(&self) -> usize { -// 0 // FIXME -// } -//} - impl context::InferenceTable, ChalkArenas<'tcx>> for ChalkInferenceContext<'cx, 'gcx, 'tcx> { @@ -338,9 +334,9 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn instantiate_binders_universally( &mut self, - _arg: &ty::Binder>, + arg: &ty::Binder>, ) -> Goal<'tcx> { - panic!("FIXME -- universal instantiation needs sgrif's branch") + self.infcx.replace_bound_vars_with_placeholders(arg).0 } fn instantiate_binders_existentially( @@ -491,3 +487,68 @@ BraceStructLiftImpl! { subst, constraints } } + +trait Upcast<'tcx, 'gcx: 'tcx>: 'gcx { + type Upcasted: 'tcx; + + fn upcast(&self) -> Self::Upcasted; +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for DelayedLiteral> { + type Upcasted = DelayedLiteral>; + + fn upcast(&self) -> Self::Upcasted { + match self { + &DelayedLiteral::CannotProve(..) => DelayedLiteral::CannotProve(()), + &DelayedLiteral::Negative(index) => DelayedLiteral::Negative(index), + DelayedLiteral::Positive(index, subst) => DelayedLiteral::Positive( + *index, + subst.clone() + ), + } + } +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for Literal> { + type Upcasted = Literal>; + + fn upcast(&self) -> Self::Upcasted { + match self { + &Literal::Negative(goal) => Literal::Negative(goal), + &Literal::Positive(goal) => Literal::Positive(goal), + } + } +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for ExClause> { + type Upcasted = ExClause>; + + fn upcast(&self) -> Self::Upcasted { + ExClause { + subst: self.subst.clone(), + delayed_literals: self.delayed_literals + .iter() + .map(|l| l.upcast()) + .collect(), + constraints: self.constraints.clone(), + subgoals: self.subgoals + .iter() + .map(|g| g.upcast()) + .collect(), + } + } +} + +impl<'tcx, 'gcx: 'tcx, T> Upcast<'tcx, 'gcx> for Canonical<'gcx, T> + where T: Upcast<'tcx, 'gcx> +{ + type Upcasted = Canonical<'tcx, T::Upcasted>; + + fn upcast(&self) -> Self::Upcasted { + Canonical { + max_universe: self.max_universe, + value: self.value.upcast(), + variables: self.variables, + } + } +} From f6aa0bdf288c5b04e4c5ebb3ec464676e779e492 Mon Sep 17 00:00:00 2001 From: scalexm Date: Mon, 5 Nov 2018 18:08:47 +0100 Subject: [PATCH 19/36] Fix `ChalkInferenceContext::into_hh_goal` --- src/librustc_traits/chalk_context/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index 14d4be2b1787..25a6af284b57 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -256,7 +256,10 @@ impl context::InferenceTable, ChalkArenas<'tcx>> fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> { match *goal { - GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), + GoalKind::Implies(hypotheses, goal) => HhGoal::Implies( + hypotheses.iter().cloned().collect(), + goal + ), GoalKind::And(left, right) => HhGoal::And(left, right), GoalKind::Not(subgoal) => HhGoal::Not(subgoal), GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d), From 17363914a77c7c953333228fcfa65a956f7de984 Mon Sep 17 00:00:00 2001 From: scalexm Date: Wed, 14 Nov 2018 12:50:26 +0100 Subject: [PATCH 20/36] Fix NLL ui test --- src/test/ui/nll/user-annotations/dump-fn-method.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index 359423d0cfbe..c963625c961e 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -4,7 +4,7 @@ error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubs LL | let x = foo::; //~ ERROR [u32] | ^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } } +error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } } --> $DIR/dump-fn-method.rs:42:13 | LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] @@ -16,7 +16,7 @@ error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubs LL | let x = >::method::; //~ ERROR [u8, u16, u32] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } } +error: user substs: Canonical { max_universe: U1, variables: [CanonicalVarInfo { kind: Ty(General(U1)) }, CanonicalVarInfo { kind: Ty(General(U1)) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } } --> $DIR/dump-fn-method.rs:54:5 | LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32] From 2ec6f340cd29f289fea1c5a672195ceeaf44c475 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Nov 2018 17:41:54 +0100 Subject: [PATCH 21/36] Update CI-clang to 7.0.0 for Linux dists. --- src/ci/docker/dist-i686-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/Dockerfile | 2 +- src/ci/docker/dist-x86_64-linux/build-clang.sh | 2 +- src/ci/docker/scripts/musl.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8df49f364a37..b087ea7899f4 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 0a2dae72f738..a1a778c2b2c6 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh index 4595eacb3106..2762f0bf7ec7 100755 --- a/src/ci/docker/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -13,7 +13,7 @@ set -ex source shared.sh -LLVM=6.0.0 +LLVM=7.0.0 mkdir clang cd clang diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index fcebfb932474..11d85471b7c0 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -51,7 +51,7 @@ hide_output make clean cd .. -LLVM=60 +LLVM=70 # may have been downloaded in a previous run if [ ! -d libunwind-release_$LLVM ]; then From f6b8eb7987fd824d576598c152de1b3144c137bb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Nov 2018 17:42:53 +0100 Subject: [PATCH 22/36] Update CI-clang to 7.0.0 for macOS dists. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b208e760d95c..14fb17aeeddc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -227,9 +227,9 @@ install: chmod +x /usr/local/bin/sccache && travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp && - travis_retry curl -f http://releases.llvm.org/6.0.0/clang+llvm-6.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && - export CC=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang && - export CXX=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang++ && + travis_retry curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && + export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang && + export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++ && export AR=ar ;; esac From 1ca505a30adb1d392d3166a34ec40b0bf584acf9 Mon Sep 17 00:00:00 2001 From: Blitzerr Date: Wed, 14 Nov 2018 08:41:16 -0800 Subject: [PATCH 23/36] capture_disjoint_fields(rust-lang#53488) Just running RustFmt on upvar.rs --- src/librustc_typeck/check/upvar.rs | 144 ++++++++++++++--------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index df994ad9e55c..ef29e13d9fe1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,14 +45,14 @@ use super::FnCtxt; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; +use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc::hir::def_id::LocalDefId; +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::UpvarRegion; +use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; use syntax::ast; use syntax_pos::Span; -use rustc::hir; -use rustc::hir::def_id::LocalDefId; -use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -121,7 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs{ + let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { if self.closure_kind(closure_def_id, closure_substs).is_none() { Some(closure_substs) } else { @@ -213,12 +213,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let final_upvar_tys = self.final_upvar_tys(closure_node_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", - closure_node_id, - substs, - final_upvar_tys + closure_node_id, substs, final_upvar_tys ); - for (upvar_ty, final_upvar_ty) in substs.upvar_tys(closure_def_id, self.tcx) - .zip(final_upvar_tys) + for (upvar_ty, final_upvar_ty) in substs + .upvar_tys(closure_def_id, self.tcx) + .zip(final_upvar_tys) { self.demand_suptype(span, upvar_ty, final_upvar_ty); } @@ -256,9 +255,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!( "var_id={:?} freevar_ty={:?} capture={:?}", - var_node_id, - freevar_ty, - capture + var_node_id, freevar_ty, capture ); match capture { @@ -271,8 +268,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, ), } - }) - .collect() + }).collect() }) } } @@ -301,12 +297,14 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { - fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn adjust_upvar_borrow_kind_for_consume( + &mut self, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!( "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", - cmt, - mode + cmt, mode ); // we only care about moves @@ -381,9 +379,9 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is // mutable, so iterate to the base. self.adjust_upvar_borrow_kind_for_mut(&base); @@ -399,12 +397,12 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => { + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => { return; } } @@ -414,9 +412,9 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is // unique. self.adjust_upvar_borrow_kind_for_unique(&base); @@ -430,18 +428,20 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => {} + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => {} } } - fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::BorrowKind) - -> bool - { + fn try_adjust_upvar_deref( + &mut self, + cmt: &mc::cmt_<'tcx>, + borrow_kind: ty::BorrowKind, + ) -> bool { assert!(match borrow_kind { ty::MutBorrow => true, ty::UniqueImmBorrow => true, @@ -493,15 +493,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { - let upvar_capture = self.adjust_upvar_captures + let upvar_capture = self + .adjust_upvar_captures .get(&upvar_id) .cloned() .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); debug!( "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", - upvar_id, - upvar_capture, - kind + upvar_id, upvar_capture, kind ); match upvar_capture { @@ -511,18 +510,18 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByRef(mut upvar_borrow) => { match (upvar_borrow.kind, kind) { // Take RHS: - (ty::ImmBorrow, ty::UniqueImmBorrow) | - (ty::ImmBorrow, ty::MutBorrow) | - (ty::UniqueImmBorrow, ty::MutBorrow) => { + (ty::ImmBorrow, ty::UniqueImmBorrow) + | (ty::ImmBorrow, ty::MutBorrow) + | (ty::UniqueImmBorrow, ty::MutBorrow) => { upvar_borrow.kind = kind; self.adjust_upvar_captures .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); } // Take LHS: - (ty::ImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::UniqueImmBorrow) | - (ty::MutBorrow, _) => {} + (ty::ImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) + | (ty::MutBorrow, _) => {} } } } @@ -537,10 +536,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { ) { debug!( "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", - closure_id, - new_kind, - upvar_span, - var_name + closure_id, new_kind, upvar_span, var_name ); // Is this the closure whose kind is currently being inferred? @@ -554,22 +550,20 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!( "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", - closure_id, - existing_kind, - new_kind + closure_id, existing_kind, new_kind ); match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) + | (ty::ClosureKind::FnOnce, _) => { // no change needed } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) + | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind self.current_closure_kind = new_kind; self.current_origin = Some((upvar_span, var_name)); @@ -590,12 +584,20 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } - fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: &mc::cmt_<'tcx>, - _mode: euv::MatchMode) { + fn matched_pat( + &mut self, + _matched_pat: &hir::Pat, + _cmt: &mc::cmt_<'tcx>, + _mode: euv::MatchMode, + ) { } - fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn consume_pat( + &mut self, + _consume_pat: &hir::Pat, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } @@ -611,9 +613,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { ) { debug!( "borrow(borrow_id={}, cmt={:?}, bk={:?})", - borrow_id, - cmt, - bk + borrow_id, cmt, bk ); match bk { From c040a483bcb522b60865130ea5e94e2ef2915f94 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 14 Nov 2018 18:09:54 +0100 Subject: [PATCH 24/36] Remove extern and some return value as an attempt to make the test pass on more platforms --- src/test/codegen/union-abi.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs index 0fa06fa777b2..786968128ec1 100644 --- a/src/test/codegen/union-abi.rs +++ b/src/test/codegen/union-abi.rs @@ -26,15 +26,15 @@ pub struct i64x4(i64, i64, i64, i64); #[derive(Copy, Clone)] pub union UnionI64x4{ a:(), b: i64x4 } -// CHECK: define <4 x i64> @test_UnionI64x4(<4 x i64> %arg0) +// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0) #[no_mangle] -pub extern fn test_UnionI64x4(_: UnionI64x4) -> UnionI64x4 { loop {} } +pub fn test_UnionI64x4(_: UnionI64x4) { loop {} } pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } -// CHECK: define <4 x i64> @test_UnionI64x4_(<4 x i64> %arg0) +// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0) #[no_mangle] -pub extern fn test_UnionI64x4_(_: UnionI64x4_) -> UnionI64x4_ { loop {} } +pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} } pub union UnionI64x4I64{ a: i64x4, b: i64 } @@ -53,19 +53,19 @@ pub union UnionF32{a:f32} // CHECK: define float @test_UnionF32(float %arg0) #[no_mangle] -pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } +pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } pub union UnionF32F32{a:f32, b:f32} // CHECK: define float @test_UnionF32F32(float %arg0) #[no_mangle] -pub extern fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } +pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } pub union UnionF32U32{a:f32, b:u32} // CHECK: define i32 @test_UnionF32U32(i32) #[no_mangle] -pub extern fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } +pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } pub union UnionU128{a:u128} // CHECK: define i128 @test_UnionU128(i128 %arg0) From aa3d7a4e6e62aad4f96d7f0b547853641d980eca Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 14 Nov 2018 18:14:31 -0600 Subject: [PATCH 25/36] properly calculate spans for intra-doc link resolution errors --- .../passes/collect_intra_doc_links.rs | 2 +- .../rustdoc-ui/intra-link-span-ice-55723.rs | 24 +++++++++++++++++++ .../intra-link-span-ice-55723.stderr | 13 ++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc-ui/intra-link-span-ice-55723.rs create mode 100644 src/test/rustdoc-ui/intra-link-span-ice-55723.stderr diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a780322e85e8..f25aa000d803 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -527,7 +527,7 @@ fn resolution_failure( doc_comment_padding + // Each subsequent leading whitespace and `///` code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| { - sum + doc_comment_padding + line.len() - line.trim().len() + sum + doc_comment_padding + line.len() - line.trim_start().len() }) }; diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs new file mode 100644 index 000000000000..12e59a4813f8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-end-whitespace + +#![deny(intra_doc_link_resolution_failure)] + +// An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to +// attempt to slice in the middle of a multibyte character. See +// https://github.com/rust-lang/rust/issues/55723 + +/// ## For example: +/// +/// (arr[i]) +pub fn test_ice() { + unimplemented!(); +} diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr new file mode 100644 index 000000000000..7ae6af4a75e8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -0,0 +1,13 @@ +error: `[i]` cannot be resolved, ignoring it... + --> $DIR/intra-link-span-ice-55723.rs:21:10 + | +LL | /// (arr[i]) + | ^ cannot be resolved, ignoring + | +note: lint level defined here + --> $DIR/intra-link-span-ice-55723.rs:13:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + From a1f83e75afefad37b1eed868c0aefba99563969d Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 15 Nov 2018 00:18:19 +0000 Subject: [PATCH 26/36] Stress test for MPSC `concurrent_recv_timeout_and_upgrade` reproduces a problem 100% times on my MacBook with command: ``` ./x.py test --stage 0 ./src/test/run-pass/mpsc_stress.rs ``` Thus it is commented out. Other tests cases were useful for catching another test cases which may arise during the fix. This diff is a part of my previous rewrite attempt: #42883 CC #39364 --- src/test/run-pass/mpsc_stress.rs | 172 +++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/test/run-pass/mpsc_stress.rs diff --git a/src/test/run-pass/mpsc_stress.rs b/src/test/run-pass/mpsc_stress.rs new file mode 100644 index 000000000000..aa369bb17fea --- /dev/null +++ b/src/test/run-pass/mpsc_stress.rs @@ -0,0 +1,172 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test +// ignore-emscripten + +use std::sync::mpsc::channel; +use std::sync::mpsc::TryRecvError; +use std::sync::mpsc::RecvError; +use std::sync::mpsc::RecvTimeoutError; +use std::sync::Arc; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use std::thread; +use std::time::Duration; + + +/// Simple thread synchronization utility +struct Barrier { + // Not using mutex/condvar for precision + shared: Arc, + count: usize, +} + +impl Barrier { + fn new(count: usize) -> Vec { + let shared = Arc::new(AtomicUsize::new(0)); + (0..count).map(|_| Barrier { shared: shared.clone(), count: count }).collect() + } + + fn new2() -> (Barrier, Barrier) { + let mut v = Barrier::new(2); + (v.pop().unwrap(), v.pop().unwrap()) + } + + /// Returns when `count` threads enter `wait` + fn wait(self) { + self.shared.fetch_add(1, Ordering::SeqCst); + while self.shared.load(Ordering::SeqCst) != self.count { + } + } +} + + +fn shared_close_sender_does_not_lose_messages_iter() { + let (tb, rb) = Barrier::new2(); + + let (tx, rx) = channel(); + let _ = tx.clone(); // convert to shared + + thread::spawn(move || { + tb.wait(); + thread::sleep(Duration::from_micros(1)); + tx.send(17).expect("send"); + drop(tx); + }); + + let i = rx.into_iter(); + rb.wait(); + // Make sure it doesn't return disconnected before returning an element + assert_eq!(vec![17], i.collect::>()); +} + +#[test] +fn shared_close_sender_does_not_lose_messages() { + for _ in 0..10000 { + shared_close_sender_does_not_lose_messages_iter(); + } +} + + +// https://github.com/rust-lang/rust/issues/39364 +fn concurrent_recv_timeout_and_upgrade_iter() { + // 1 us + let sleep = Duration::new(0, 1_000); + + let (a, b) = Barrier::new2(); + let (tx, rx) = channel(); + let th = thread::spawn(move || { + a.wait(); + loop { + match rx.recv_timeout(sleep) { + Ok(_) => { + break; + }, + Err(_) => {}, + } + } + }); + b.wait(); + thread::sleep(sleep); + tx.clone().send(()).expect("send"); + th.join().unwrap(); +} + +#[test] +fn concurrent_recv_timeout_and_upgrade() { + // FIXME: fix and enable + if true { return } + + // at the moment of writing this test fails like this: + // thread '' panicked at 'assertion failed: `(left == right)` + // left: `4561387584`, + // right: `0`', libstd/sync/mpsc/shared.rs:253:13 + + for _ in 0..10000 { + concurrent_recv_timeout_and_upgrade_iter(); + } +} + + +fn concurrent_writes_iter() { + const THREADS: usize = 4; + const PER_THR: usize = 100; + + let mut bs = Barrier::new(THREADS + 1); + let (tx, rx) = channel(); + + let mut threads = Vec::new(); + for j in 0..THREADS { + let tx = tx.clone(); + let b = bs.pop().unwrap(); + threads.push(thread::spawn(move || { + b.wait(); + for i in 0..PER_THR { + tx.send(j * 1000 + i).expect("send"); + } + })); + } + + let b = bs.pop().unwrap(); + b.wait(); + + let mut v: Vec<_> = rx.iter().take(THREADS * PER_THR).collect(); + v.sort(); + + for j in 0..THREADS { + for i in 0..PER_THR { + assert_eq!(j * 1000 + i, v[j * PER_THR + i]); + } + } + + for t in threads { + t.join().unwrap(); + } + + let one_us = Duration::new(0, 1000); + + assert_eq!(TryRecvError::Empty, rx.try_recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Timeout, rx.recv_timeout(one_us).unwrap_err()); + + drop(tx); + + assert_eq!(RecvError, rx.recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Disconnected, rx.recv_timeout(one_us).unwrap_err()); + assert_eq!(TryRecvError::Disconnected, rx.try_recv().unwrap_err()); +} + +#[test] +fn concurrent_writes() { + for _ in 0..100 { + concurrent_writes_iter(); + } +} From 166f7d919c9e31875b0492ef90e065eb33336d6c Mon Sep 17 00:00:00 2001 From: Sebastian Geisler Date: Tue, 30 Oct 2018 22:24:33 -0700 Subject: [PATCH 27/36] Implement checked_add_duration for SystemTime Since SystemTime is opaque there is no way to check if the result of an addition will be in bounds. That makes the Add trait completely unusable with untrusted data. This is a big problem because adding a Duration to UNIX_EPOCH is the standard way of constructing a SystemTime from a unix timestamp. This commit implements checked_add_duration(&self, &Duration) -> Option for std::time::SystemTime and as a prerequisite also for all platform specific time structs. This also led to the refactoring of many add_duration(&self, &Duration) -> SystemTime functions to avoid redundancy (they now unwrap the result of checked_add_duration). Some basic unit tests for the newly introduced function were added too. --- src/libstd/sys/cloudabi/time.rs | 19 +++++++++++++------ src/libstd/sys/redox/time.rs | 25 +++++++++++++++++++------ src/libstd/sys/unix/time.rs | 29 +++++++++++++++++++++++------ src/libstd/sys/wasm/time.rs | 4 ++++ src/libstd/sys/windows/time.rs | 16 ++++++++++++---- src/libstd/time.rs | 21 +++++++++++++++++++++ 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs index ee12731619aa..191324e26a40 100644 --- a/src/libstd/sys/cloudabi/time.rs +++ b/src/libstd/sys/cloudabi/time.rs @@ -19,10 +19,14 @@ pub struct Instant { t: abi::timestamp, } -pub fn dur2intervals(dur: &Duration) -> abi::timestamp { +fn checked_dur2intervals(dur: &Duration) -> Option { dur.as_secs() .checked_mul(NSEC_PER_SEC) .and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp)) +} + +pub fn dur2intervals(dur: &Duration) -> abi::timestamp { + checked_dur2intervals(dur) .expect("overflow converting duration to nanoseconds") } @@ -92,11 +96,14 @@ impl SystemTime { } pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { - t: self.t - .checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } + self.checked_add_duration(other) + .expect("overflow when adding duration to instant") + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + checked_dur2intervals(other) + .and_then(|d| self.t.checked_add(d)) + .map(|t| SystemTime {t}) } pub fn sub_duration(&self, other: &Duration) -> SystemTime { diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index 5c491115c551..5f45fd497e2d 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -42,27 +42,36 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + fn checked_add_duration(&self, other: &Duration) -> Option { + let mut secs = match other .as_secs() .try_into() // <- target type would be `i64` .ok() .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); + { + Some(ts) => ts, + None => return None, + }; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; if nsec >= NSEC_PER_SEC as u32 { nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); + secs = match secs.checked_add(1) { + Some(ts) => ts, + None => return None, + } } - Timespec { + Some(Timespec { t: syscall::TimeSpec { tv_sec: secs, tv_nsec: nsec as i32, }, - } + }) } fn sub_duration(&self, other: &Duration) -> Timespec { @@ -180,6 +189,10 @@ impl SystemTime { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 0b1fb726357e..50c3c00382eb 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -43,27 +43,36 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + fn checked_add_duration(&self, other: &Duration) -> Option { + let mut secs = match other .as_secs() .try_into() // <- target type would be `libc::time_t` .ok() .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); + { + Some(ts) => ts, + None => return None, + }; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; if nsec >= NSEC_PER_SEC as u32 { nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); + secs = match secs.checked_add(1) { + Some(ts) => ts, + None => return None, + } } - Timespec { + Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _, }, - } + }) } fn sub_duration(&self, other: &Duration) -> Timespec { @@ -201,6 +210,10 @@ mod inner { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.checked_add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } @@ -325,6 +338,10 @@ mod inner { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.checked_add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index e52435e63398..991e8176edf6 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -51,6 +51,10 @@ impl SystemTime { SystemTime(self.0 + *other) } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.0.checked_add(*other).map(|d| SystemTime(d)) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime(self.0 - *other) } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 07e64d386a1c..8eebe4a85fe1 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -128,9 +128,13 @@ impl SystemTime { } pub fn add_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_add(dur2intervals(other)) - .expect("overflow when adding duration to time"); - SystemTime::from_intervals(intervals) + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + checked_dur2intervals(other) + .and_then(|d| self.intervals().checked_add(d)) + .map(|i| SystemTime::from_intervals(i)) } pub fn sub_duration(&self, other: &Duration) -> SystemTime { @@ -180,11 +184,15 @@ impl Hash for SystemTime { } } -fn dur2intervals(d: &Duration) -> i64 { +fn checked_dur2intervals(d: &Duration) -> Option { d.as_secs() .checked_mul(INTERVALS_PER_SEC) .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) .and_then(|i| i.try_into().ok()) +} + +fn dur2intervals(d: &Duration) -> i64 { + checked_dur2intervals(d) .expect("overflow when converting duration to intervals") } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 90ab34915991..94875d8993d3 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -357,6 +357,14 @@ impl SystemTime { pub fn elapsed(&self) -> Result { SystemTime::now().duration_since(*self) } + + /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as + /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` + /// otherwise. + #[stable(feature = "time_checked_add", since = "1.32.0")] + pub fn checked_add_duration(&self, duration: &Duration) -> Option { + self.0.checked_add_duration(duration).map(|t| SystemTime(t)) + } } #[stable(feature = "time2", since = "1.8.0")] @@ -557,6 +565,19 @@ mod tests { let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); assert_eq!(one_second_from_epoch, one_second_from_epoch2); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(SystemTime::UNIX_EPOCH); + let max_duration = Duration::from_secs(u64::max_value()); + // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add_duration(&max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add_duration(&year).unwrap()); } #[test] From 8231831b3885af2709939147dfe18baa4b5e2bd2 Mon Sep 17 00:00:00 2001 From: Sebastian Geisler Date: Sun, 4 Nov 2018 21:23:20 -0800 Subject: [PATCH 28/36] Rename checked_add_duration to checked_add and make it take the duration by value --- src/libstd/time.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 94875d8993d3..c905af442de1 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -361,9 +361,9 @@ impl SystemTime { /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. - #[stable(feature = "time_checked_add", since = "1.32.0")] - pub fn checked_add_duration(&self, duration: &Duration) -> Option { - self.0.checked_add_duration(duration).map(|t| SystemTime(t)) + #[unstable(feature = "time_checked_add", issue = "55940")] + pub fn checked_add(&self, duration: Duration) -> Option { + self.0.checked_add_duration(&duration).map(|t| SystemTime(t)) } } @@ -571,13 +571,13 @@ mod tests { let max_duration = Duration::from_secs(u64::max_value()); // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. for _ in 0..2 { - maybe_t = maybe_t.and_then(|t| t.checked_add_duration(&max_duration)); + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); } assert_eq!(maybe_t, None); // checked_add_duration calculates the right time and will work for another year let year = Duration::from_secs(60 * 60 * 24 * 365); - assert_eq!(a + year, a.checked_add_duration(&year).unwrap()); + assert_eq!(a + year, a.checked_add(year).unwrap()); } #[test] From 6779bb485c7fb3af47278d7eeefce34eeeb5eaf8 Mon Sep 17 00:00:00 2001 From: Blitzerr Date: Wed, 14 Nov 2018 21:14:46 -0800 Subject: [PATCH 29/36] capture_disjoint_fields(rust-lang#53488) Refactoring out the HirId of the UpvarId in another struct. --- src/librustc/ich/impls_ty.rs | 4 +++- src/librustc/infer/error_reporting/mod.rs | 2 +- src/librustc/infer/error_reporting/note.rs | 4 ++-- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/ty/context.rs | 6 +++--- src/librustc/ty/mod.rs | 7 ++++++- src/librustc/util/ppaux.rs | 4 ++-- .../borrowck/gather_loans/mod.rs | 4 ++-- .../borrowck/gather_loans/move_error.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 10 +++++----- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 ++-- src/librustc_typeck/check/upvar.rs | 16 ++++++++++------ src/librustc_typeck/check/writeback.rs | 2 +- 15 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f..928a6accf2d1 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -216,7 +216,9 @@ impl<'gcx> HashStable> for ty::adjustment::AutoBorrow } } -impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarPath { hir_id }); + +impl_stable_hash_for!(struct ty::UpvarId { var_path, closure_expr_id }); impl_stable_hash_for!(enum ty::BorrowKind { ImmBorrow, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f833ebc7ca76..59a490f4a013 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1315,7 +1315,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { format!(" for lifetime parameter `{}` in coherence check", name) } infer::UpvarRegion(ref upvar_id, _) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); format!(" for capture of `{}` by closure", var_name) } diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 54d01a035a8b..a539c321af3f 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -41,7 +41,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "...so that reference does not outlive borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); err.span_note(span, &format!("...so that closure can access `{}`", var_name)); @@ -174,7 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); let mut err = struct_span_err!(self.tcx.sess, span, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 7e9b26bbf729..5b92bfe6ad3c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -938,7 +938,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let var_hir_id = self.tcx().hir.node_to_hir_id(freevar.var_id()); let closure_def_id = self.tcx().hir.local_def_id(closure_expr.id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 59ef8fa14484..cadf0c42d228 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -818,7 +818,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let closure_expr_def_id = self.tcx.hir.local_def_id(fn_node_id); let var_hir_id = self.tcx.hir.node_to_hir_id(var_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_expr_def_id.to_local(), }; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index cdfe8f53b854..923d362c2345 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -789,7 +789,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { pat_adjustments.hash_stable(hcx, hasher); hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| { let ty::UpvarId { - var_id, + var_path, closure_expr_id } = *up_var_id; @@ -798,14 +798,14 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { let var_owner_def_id = DefId { krate: local_id_root.krate, - index: var_id.owner, + index: var_path.hir_id.owner, }; let closure_def_id = DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index, }; (hcx.def_path_hash(var_owner_def_id), - var_id.local_id, + var_path.hir_id.local_id, hcx.def_path_hash(closure_def_id)) }); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8197136d189a..d1497c42af78 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -731,12 +731,17 @@ impl List { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UpvarPath { + pub hir_id: hir::HirId, +} + /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UpvarId { - pub var_id: hir::HirId, + pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e44c0c05bb1a..d53370d242bd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -678,8 +678,8 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "UpvarId({:?};`{}`;{:?})", - self.var_id, - ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), + self.var_path.hir_id, + ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_path.hir_id))), self.closure_expr_id) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 78a31ed668fc..21fb0cdf90ad 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -453,8 +453,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } None } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { - self.bccx.used_mut_nodes.borrow_mut().insert(var_id); + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { + self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); None } LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index e1a4473539c8..cfd530b7e3d0 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -97,7 +97,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr } } if let NoteClosureEnv(upvar_id) = error.move_from.note { - let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); err.span_label(bccx.tcx.hir.span(var_node_id), "captured outer variable"); } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index d52d78181b77..d189460d0884 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -846,7 +846,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { MutabilityViolation => { let mut db = self.cannot_assign(error_span, &descr, Origin::Ast); if let mc::NoteClosureEnv(upvar_id) = err.cmt.note { - let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let sp = self.tcx.hir.span(node_id); let fn_closure_msg = "`Fn` closures cannot capture their enclosing \ environment for modifications"; @@ -1415,7 +1415,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { loan_path: &LoanPath<'tcx>, out: &mut String) { match loan_path.kind { - LpUpvar(ty::UpvarId { var_id: id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id}, closure_expr_id: _ }) => { out.push_str(&self.tcx.hir.name(self.tcx.hir.hir_to_node_id(id)).as_str()); } LpVar(id) => { @@ -1533,7 +1533,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => { let s = ty::tls::with(|tcx| { let var_node_id = tcx.hir.hir_to_node_id(var_id); tcx.hir.node_to_string(var_node_id) @@ -1568,9 +1568,9 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_user_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { let s = ty::tls::with(|tcx| { - let var_node_id = tcx.hir.hir_to_node_id(var_id); + let var_node_id = tcx.hir.hir_to_node_id(hir_id); tcx.hir.node_to_string(var_node_id) }); write!(f, "$({} captured by closure)", s) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5b4001f0652a..94d1874e9c9e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -612,7 +612,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let var_hir_id = tcx.hir.node_to_hir_id(var_id); let closure_expr_id = tcx.hir.local_def_id(fn_id); let capture = hir.tables().upvar_capture(ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_expr_id), }); let by_ref = match capture { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 656a467fb491..2e9edf20c570 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -1061,7 +1061,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; match cx.tables().upvar_capture(upvar_id) { @@ -1178,7 +1178,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> ExprRef<'tcx> { let var_hir_id = cx.tcx.hir.node_to_hir_id(freevar.var_id()); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).to_local(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index ef29e13d9fe1..312ce402775d 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -134,7 +134,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.with_freevars(closure_node_id, |freevars| { for freevar in freevars { let upvar_id = ty::UpvarId { - var_id: self.tcx.hir.node_to_hir_id(freevar.var_id()), + var_path: ty::UpvarPath { + hir_id : self.tcx.hir.node_to_hir_id(freevar.var_id()), + }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); @@ -248,7 +250,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let var_hir_id = tcx.hir.node_to_hir_id(var_node_id); let freevar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { + hir_id: var_hir_id, + }, closure_expr_id: LocalDefId::from_def_id(closure_def_index), }; let capture = self.tables.borrow().upvar_capture(upvar_id); @@ -347,7 +351,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); self.adjust_upvar_captures @@ -364,7 +368,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); } mc::NoteIndex | mc::NoteNone => {} @@ -465,7 +469,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true @@ -478,7 +482,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d968bf222aa0..4460d5f64ce2 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -306,7 +306,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, &upvar_id.var_id); + let r = self.resolve(&r, &upvar_id.var_path.hir_id); ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, region: r, From c5bc83b60d10492f8e71461b03f5adb8505e53d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 11:14:18 +0100 Subject: [PATCH 30/36] expose MutValueVisitor --- src/librustc_mir/interpret/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 82fe08fa038a..96ea0d509496 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -39,6 +39,6 @@ pub use self::machine::{Machine, AllocMap, MayLeak}; pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy}; -pub use self::visitor::ValueVisitor; +pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; From e4d03f82b582824d2b6c3fb68420883d26598178 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 12:44:40 +0100 Subject: [PATCH 31/36] miri value visitor: provide place when visiting a primitive --- src/librustc_mir/interpret/validity.rs | 5 +++-- src/librustc_mir/interpret/visitor.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c3554512806b..229f48381eaa 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -21,7 +21,7 @@ use rustc::mir::interpret::{ }; use super::{ - OpTy, MPlaceTy, ImmTy, Machine, EvalContext, ValueVisitor + OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor }; macro_rules! validation_failure { @@ -281,8 +281,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } } - fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { + let value = self.ecx.read_immediate(value)?; // Go over all the primitive types let ty = value.layout.ty; match ty.sty { diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 4a4704564325..f0a71242599b 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ use rustc::mir::interpret::{ }; use super::{ - Machine, EvalContext, MPlaceTy, OpTy, ImmTy, + Machine, EvalContext, MPlaceTy, OpTy, }; // A thing that we can project into, and that has a layout. @@ -201,9 +201,11 @@ macro_rules! make_value_visitor { { Ok(()) } /// Called whenever we reach a value of primitive type. There can be no recursion - /// below such a value. This is the leave function. + /// below such a value. This is the leaf function. + /// We do *not* provide an `ImmTy` here because some implementations might want + /// to write to the place this primitive lives in. #[inline(always)] - fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx> { Ok(()) } // Default recursors. Not meant to be overloaded. @@ -279,9 +281,7 @@ macro_rules! make_value_visitor { _ => v.layout().ty.builtin_deref(true).is_some(), }; if primitive { - let op = v.to_op(self.ecx())?; - let val = self.ecx().read_immediate(op)?; - return self.visit_primitive(val); + return self.visit_primitive(v); } // Proceed into the fields. From e6e56357308d1e20b56f1be9af2c2dfc73c49d0d Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 14 Nov 2018 15:00:57 +0100 Subject: [PATCH 32/36] ty: return impl Iterator from Predicate::walk_tys --- src/librustc/ty/mod.rs | 78 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8197136d189a..c801cb99a1e2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -49,7 +49,6 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; -use std::vec::IntoIter; use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; @@ -1343,49 +1342,88 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } +// A custom iterator used by Predicate::walk_tys. +enum WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + None, + One(Ty<'tcx>), + Two(Ty<'tcx>, Ty<'tcx>), + Types(I), + InputTypes(J), + ProjectionTypes(K) +} + +impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + type Item = Ty<'tcx>; + + fn next(&mut self) -> Option> { + match *self { + WalkTysIter::None => None, + WalkTysIter::One(item) => { + *self = WalkTysIter::None; + Some(item) + }, + WalkTysIter::Two(item1, item2) => { + *self = WalkTysIter::One(item2); + Some(item1) + }, + WalkTysIter::Types(ref mut iter) => { + iter.next() + }, + WalkTysIter::InputTypes(ref mut iter) => { + iter.next() + }, + WalkTysIter::ProjectionTypes(ref mut iter) => { + iter.next() + } + } + } +} + impl<'tcx> Predicate<'tcx> { /// Iterates over the types in this predicate. Note that in all /// cases this is skipping over a binder, so late-bound regions /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter> { - let vec: Vec<_> = match *self { + pub fn walk_tys(&'a self) -> impl Iterator> + 'a { + match *self { ty::Predicate::Trait(ref data) => { - data.skip_binder().input_types().collect() + WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - vec![a, b] + WalkTysIter::Two(a, b) } ty::Predicate::TypeOutlives(binder) => { - vec![binder.skip_binder().0] + WalkTysIter::One(binder.skip_binder().0) } ty::Predicate::RegionOutlives(..) => { - vec![] + WalkTysIter::None } ty::Predicate::Projection(ref data) => { let inner = data.skip_binder(); - inner.projection_ty.substs.types().chain(Some(inner.ty)).collect() + WalkTysIter::ProjectionTypes( + inner.projection_ty.substs.types().chain(Some(inner.ty))) } ty::Predicate::WellFormed(data) => { - vec![data] + WalkTysIter::One(data) } ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] + WalkTysIter::None } ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - closure_substs.substs.types().collect() + WalkTysIter::Types(closure_substs.substs.types()) } ty::Predicate::ConstEvaluatable(_, substs) => { - substs.types().collect() + WalkTysIter::Types(substs.types()) } - }; - - // FIXME: The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() + } } pub fn to_opt_poly_trait_ref(&self) -> Option> { From ffb6ba082897db55f7ab4e576175b144597aa38f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 10:32:23 +0100 Subject: [PATCH 33/36] validation: better error when the enum discriminant is Undef --- src/librustc/mir/interpret/error.rs | 4 ++-- src/librustc_mir/interpret/operand.rs | 8 +++++--- src/librustc_mir/interpret/validity.rs | 4 ++-- .../const-pointer-values-in-various-types.stderr | 14 +++++++------- src/test/ui/consts/const-eval/issue-52442.stderr | 2 +- .../ui/consts/const-eval/ref_to_int_match.stderr | 2 +- src/test/ui/consts/const-eval/ub-enum.stderr | 2 +- src/test/ui/consts/const-eval/ub-ref.stderr | 4 ++-- src/test/ui/consts/const-eval/union-ice.stderr | 2 +- 9 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed422..c51a655418c1 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::{Ty, layout}; use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; -use super::{Pointer, Scalar}; +use super::{Pointer, ScalarMaybeUndef}; use backtrace::Backtrace; @@ -240,7 +240,7 @@ pub enum EvalErrorKind<'tcx, O> { InvalidMemoryAccess, InvalidFunctionPointer, InvalidBool, - InvalidDiscriminant(Scalar), + InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, access: bool, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 578bcdc09295..b3b4980beafa 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -601,7 +601,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // read raw discriminant value let discr_op = self.operand_field(rval, 0)?; let discr_val = self.read_immediate(discr_op)?; - let raw_discr = discr_val.to_scalar()?; + let raw_discr = discr_val.to_scalar_or_undef(); trace!("discr value: {:?}", raw_discr); // post-process Ok(match rval.layout.variants { @@ -647,13 +647,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; match raw_discr { - Scalar::Ptr(_) => { + ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) => { // The niche must be just 0 (which a pointer value never is) assert!(niche_start == 0); assert!(variants_start == variants_end); (dataful_variant.as_u32() as u128, dataful_variant) }, - Scalar::Bits { bits: raw_discr, size } => { + ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { assert_eq!(size as u64, discr_val.layout.size.bytes()); let discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); @@ -669,6 +669,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> (dataful_variant.as_u32() as u128, dataful_variant) } }, + ScalarMaybeUndef::Undef => + return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)), } } }) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c3554512806b..10513f2ebba7 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -274,7 +274,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ), EvalErrorKind::ReadPointerAsBytes => validation_failure!( - "a pointer", self.path, "plain bytes" + "a pointer", self.path, "plain (non-pointer) bytes" ), _ => Err(err), } @@ -304,7 +304,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> if self.const_mode { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous try_validation!(value.to_bits(size), - value, self.path, "initialized plain bits"); + value, self.path, "initialized plain (non-pointer) bytes"); } else { // At run-time, for now, we accept *anything* for these types, including // undef. We should fix that, but let's start low. diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index cc1db5db6915..0126743eedec 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:24:5 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:36:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -74,7 +74,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:51:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -96,7 +96,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:60:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -144,7 +144,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:78:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -184,7 +184,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:93:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:102:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 3075be9e28b3..608094b179dd 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52442.rs:12:11 | LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index d55c1c2c70ba..c4bad73eb027 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ref_to_int_match.rs:33:1 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; //~ ERROR it is undefined behavior to use this value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d36e96b08174..b94a57d00a44 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:51:1 | LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at [0], but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index c3f5f4a26f55..fe969d40a2ea 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:22:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:25:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index d5a20640771d..98c2c1472aae 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -13,7 +13,7 @@ LL | / const FIELD_PATH: Struct = Struct { //~ ERROR it is undefined behavior to LL | | a: 42, LL | | b: unsafe { UNION.field3 }, LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain bits + | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior From a3770c2547dd163e0f5bfa07ec23b8b461fbe145 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 11:22:18 +0100 Subject: [PATCH 34/36] do not accept out-of-bounds pointers in enum discriminants, they might be NULL --- src/librustc/ich/impls_ty.rs | 7 ++- src/librustc/mir/interpret/allocation.rs | 8 ++++ src/librustc/mir/interpret/error.rs | 14 ++++-- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/memory.rs | 50 +++++++++++--------- src/librustc_mir/interpret/operand.rs | 23 +++++---- src/librustc_mir/interpret/validity.rs | 5 +- src/test/ui/consts/const-eval/ub-enum.rs | 5 ++ src/test/ui/consts/const-eval/ub-enum.stderr | 20 +++++--- 9 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f..9c1fb99cb73c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -451,7 +451,7 @@ impl_stable_hash_for!( FunctionRetMismatch(a, b), NoMirFor(s), UnterminatedCString(ptr), - PointerOutOfBounds { ptr, access, allocation_size }, + PointerOutOfBounds { ptr, check, allocation_size }, InvalidBoolOp(bop), Unimplemented(s), BoundsCheck { len, index }, @@ -471,6 +471,11 @@ impl_stable_hash_for!( } ); +impl_stable_hash_for!(enum mir::interpret::InboundsCheck { + Live, + MaybeDead +}); + impl_stable_hash_for!(enum mir::interpret::Lock { NoLock, WriteLock(dl), diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index cc92b63256c1..02c0ebcec4fe 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -19,6 +19,14 @@ use mir; use std::ops::{Deref, DerefMut}; use rustc_data_structures::sorted_map::SortedMap; +/// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds +/// or also inbounds of a *live* allocation. +#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum InboundsCheck { + Live, + MaybeDead, +} + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index c51a655418c1..bf678db51c95 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::{Ty, layout}; use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; -use super::{Pointer, ScalarMaybeUndef}; +use super::{Pointer, InboundsCheck, ScalarMaybeUndef}; use backtrace::Backtrace; @@ -243,7 +243,7 @@ pub enum EvalErrorKind<'tcx, O> { InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, - access: bool, + check: InboundsCheck, allocation_size: Size, }, InvalidNullPointerUsage, @@ -457,9 +457,13 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::EvalErrorKind::*; match *self { - PointerOutOfBounds { ptr, access, allocation_size } => { - write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", - if access { "memory access" } else { "pointer computed" }, + PointerOutOfBounds { ptr, check, allocation_size } => { + write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \ + allocation {} which has size {}", + match check { + InboundsCheck::Live => " and live", + InboundsCheck::MaybeDead => "", + }, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, ValidationFailure(ref err) => { diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 40daf78f546f..ec25431bd1ff 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -28,7 +28,7 @@ pub use self::error::{ pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef}; pub use self::allocation::{ - Allocation, AllocationExtra, + InboundsCheck, Allocation, AllocationExtra, Relocations, UndefMask, }; diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index e125927e7d27..c5a242f334c9 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -28,7 +28,7 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::ast::Mutability; use super::{ - Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, + Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, InboundsCheck, EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic, Machine, AllocMap, MayLeak, ScalarMaybeUndef, ErrorHandled, }; @@ -249,17 +249,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Check non-NULL/Undef, extract offset let (offset, alloc_align) = match ptr { Scalar::Ptr(ptr) => { - let (size, align) = self.get_size_and_align(ptr.alloc_id); // check this is not NULL -- which we can ensure only if this is in-bounds // of some (potentially dead) allocation. - if ptr.offset > size { - return err!(PointerOutOfBounds { - ptr: ptr.erase_tag(), - access: true, - allocation_size: size, - }); - }; - // keep data for alignment check + self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?; + // data required for alignment check + let (_, align) = self.get_size_and_align(ptr.alloc_id); (ptr.offset.bytes(), align) } Scalar::Bits { bits, size } => { @@ -293,18 +287,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end /// of an allocation (i.e., at the first *inaccessible* location) *is* considered - /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used - /// for the error message. - /// If you want to check bounds before doing a memory access, be sure to - /// check the pointer one past the end of your access, then everything will - /// work out exactly. - pub fn check_bounds_ptr(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - let allocation_size = alloc.bytes.len() as u64; + /// in-bounds! This follows C's/LLVM's rules. `check` indicates whether we + /// additionally require the pointer to be pointing to a *live* (still allocated) + /// allocation. + /// If you want to check bounds before doing a memory access, better use `check_bounds`. + pub fn check_bounds_ptr( + &self, + ptr: Pointer, + check: InboundsCheck, + ) -> EvalResult<'tcx> { + let allocation_size = match check { + InboundsCheck::Live => { + let alloc = self.get(ptr.alloc_id)?; + alloc.bytes.len() as u64 + } + InboundsCheck::MaybeDead => { + self.get_size_and_align(ptr.alloc_id).0.bytes() + } + }; if ptr.offset.bytes() > allocation_size { return err!(PointerOutOfBounds { ptr: ptr.erase_tag(), - access, + check, allocation_size: Size::from_bytes(allocation_size), }); } @@ -317,10 +321,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &self, ptr: Pointer, size: Size, - access: bool + check: InboundsCheck, ) -> EvalResult<'tcx> { // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - self.check_bounds_ptr(ptr.offset(size, &*self)?, access) + self.check_bounds_ptr(ptr.offset(size, &*self)?, check) } } @@ -626,7 +630,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> EvalResult<'tcx, &[u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; if check_defined_and_ptr { self.check_defined(ptr, size)?; @@ -677,7 +681,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> EvalResult<'tcx, &mut [u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; self.mark_definedness(ptr, size, true)?; self.clear_relocations(ptr, size)?; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index b3b4980beafa..b7910ad3bce9 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -19,7 +19,7 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx use rustc::mir::interpret::{ GlobalId, AllocId, ConstValue, Pointer, Scalar, - EvalResult, EvalErrorKind + EvalResult, EvalErrorKind, InboundsCheck, }; use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind}; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -647,24 +647,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; match raw_discr { - ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) => { - // The niche must be just 0 (which a pointer value never is) - assert!(niche_start == 0); - assert!(variants_start == variants_end); + ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => { + // The niche must be just 0 (which an inbounds pointer value never is) + let ptr_valid = niche_start == 0 && variants_start == variants_end && + self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok(); + if !ptr_valid { + return err!(InvalidDiscriminant(raw_discr.erase_tag())); + } (dataful_variant.as_u32() as u128, dataful_variant) }, ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { assert_eq!(size as u64, discr_val.layout.size.bytes()); - let discr = raw_discr.wrapping_sub(niche_start) + let adjusted_discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); - if variants_start <= discr && discr <= variants_end { - let index = discr as usize; - assert_eq!(index as u128, discr); + if variants_start <= adjusted_discr && adjusted_discr <= variants_end { + let index = adjusted_discr as usize; + assert_eq!(index as u128, adjusted_discr); assert!(index < rval.layout.ty .ty_adt_def() .expect("tagged layout for non adt") .variants.len()); - (discr, VariantIdx::from_usize(index)) + (adjusted_discr, VariantIdx::from_usize(index)) } else { (dataful_variant.as_u32() as u128, dataful_variant) } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 10513f2ebba7..5d5c25e66a2e 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -17,7 +17,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ - Scalar, AllocType, EvalResult, EvalErrorKind, + Scalar, AllocType, EvalResult, EvalErrorKind, InboundsCheck, }; use super::{ @@ -394,7 +394,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } // Maintain the invariant that the place we are checking is // already verified to be in-bounds. - try_validation!(self.ecx.memory.check_bounds(ptr, size, false), + try_validation!( + self.ecx.memory.check_bounds(ptr, size, InboundsCheck::Live), "dangling (not entirely in bounds) reference", self.path); } // Check if we have encountered this pointer+layout combination diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 0aa15c839387..89b449464419 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -39,6 +39,7 @@ union TransmuteEnum2 { in3: (), out1: Enum2, out2: Wrap, // something wrapping the enum so that we test layout first, not enum + out3: Option, } const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; //~^ ERROR is undefined behavior @@ -51,6 +52,10 @@ const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; //~^ ERROR is undefined behavior +// Pointer value in an enum with a niche that is not just 0. +const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; +//~^ ERROR is undefined behavior + // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). union TransmuteChar { diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index b94a57d00a44..5aae3a2f3511 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -15,7 +15,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -23,7 +23,7 @@ LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:47:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2 @@ -31,7 +31,7 @@ LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:51:1 + --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at [0], but expected a valid enum discriminant @@ -39,13 +39,21 @@ LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:61:1 + --> $DIR/ub-enum.rs:56:1 + | +LL | const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:66:1 | LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0080`. From b8915f2ba83d2d7968a1615a086bde0d4bf20706 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 12:19:35 +0100 Subject: [PATCH 35/36] fix other affected tests --- src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index 03de0efd0736..a4c228416147 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52023-array-size-pointer-cast.rs:12:17 | LL | let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior From 8c8ff6a4e14fc8c9ded15b37a910127bbce6cda2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 16 Sep 2018 16:35:41 +0000 Subject: [PATCH 36/36] test/linkage-visibility: Ignore on musl targets DynamicLibrary uses libc's dlsym() function internally to find symbols. Some implementations of dlsym(), like musl's, only look at dynamically- exported symbols, as found in shared libraries. To also export symbols from the main executable, we would need to pass --export-dynamic to the linker. Since this flag isn't available everywhere, ignore the test for now. --- src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs index 4ea3d0d0d0a0..2aaa28341ad9 100644 --- a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs +++ b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-musl - dlsym doesn't see symbols without "-C link-arg=-Wl,--export-dynamic" + #![feature(rustc_private)] // We're testing linkage visibility; the compiler warns us, but we want to