From 3e86cf36b5114f201868bf459934fe346a76a2d4 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 19 Apr 2019 21:13:37 -0700 Subject: [PATCH 01/13] Add implementations of last in terms of next_back on a bunch of DoubleEndedIterators. r?Manishearth --- src/liballoc/collections/binary_heap.rs | 15 ++++++++++ src/liballoc/collections/btree/map.rs | 40 +++++++++++++++++++++++++ src/liballoc/collections/btree/set.rs | 15 ++++++++++ src/liballoc/string.rs | 4 +++ src/liballoc/vec.rs | 14 +++++++++ src/libcore/ascii.rs | 2 ++ src/libcore/iter/adapters/mod.rs | 5 ++++ src/libcore/slice/mod.rs | 20 +++++++++++++ src/libcore/str/mod.rs | 20 +++++++++++++ src/libstd/env.rs | 6 ++++ src/libstd/path.rs | 10 +++++++ src/libstd/sys/unix/args.rs | 2 ++ src/libstd/sys/wasm/args.rs | 4 +++ src/libstd/sys/windows/args.rs | 2 ++ 14 files changed, 159 insertions(+) diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 8c142a3d317c6..2b1e52cbf0543 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -968,6 +968,11 @@ impl<'a, T> Iterator for Iter<'a, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1023,6 +1028,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1069,6 +1079,11 @@ impl Iterator for Drain<'_, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 6b079fc87cc78..414abb00ef1fa 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1193,6 +1193,11 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1253,6 +1258,11 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1359,6 +1369,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(K, V)> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1421,6 +1436,11 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a K> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1458,6 +1478,11 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a V> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1495,6 +1520,11 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { unsafe { Some(self.next_unchecked()) } } } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1508,6 +1538,11 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a mut V> { + self.next_back() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1626,6 +1661,11 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { unsafe { Some(self.next_unchecked()) } } } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 16a96ca19b824..6f2467dfd6b51 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1019,6 +1019,11 @@ impl<'a, T> Iterator for Iter<'a, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> DoubleEndedIterator for Iter<'a, T> { @@ -1044,6 +1049,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for IntoIter { @@ -1073,6 +1083,11 @@ impl<'a, T> Iterator for Range<'a, T> { fn next(&mut self) -> Option<&'a T> { self.iter.next().map(|(k, _)| k) } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "btree_range", since = "1.17.0")] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a3e2098695f70..f01610a7c3f3a 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2367,6 +2367,10 @@ impl Iterator for Drain<'_> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index cd62c3e05244c..50bb37b6ed27f 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2385,6 +2385,11 @@ impl Iterator for IntoIter { fn count(self) -> usize { self.len() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2504,6 +2509,11 @@ impl Iterator for Drain<'_, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] @@ -2573,6 +2583,10 @@ impl Iterator for Splice<'_, I> { fn size_hint(&self) -> (usize, Option) { self.drain.size_hint() } + + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "vec_splice", since = "1.21.0")] diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index c0ab364380fbd..ddee02ea232d1 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -117,6 +117,8 @@ impl Iterator for EscapeDefault { type Item = u8; fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for EscapeDefault { diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index 3ab404a48d3d8..d814e8a5958e7 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -73,6 +73,11 @@ impl Iterator for Rev where I: DoubleEndedIterator { { self.iter.position(predicate) } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index bf3dda48dc797..cda4268607f9a 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3539,6 +3539,11 @@ impl<'a, T, P> Iterator for Split<'a, T, P> where P: FnMut(&T) -> bool { (1, Some(self.v.len() + 1)) } } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3637,6 +3642,11 @@ impl<'a, T, P> Iterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { (1, Some(self.v.len() + 1)) } } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3702,6 +3712,11 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -3766,6 +3781,11 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 379c263c04ca6..41399d2194233 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1331,6 +1331,11 @@ impl<'a> Iterator for Lines<'a> { fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1377,6 +1382,11 @@ impl<'a> Iterator for LinesAny<'a> { fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -4215,6 +4225,11 @@ impl<'a> Iterator for SplitWhitespace<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "split_whitespace", since = "1.1.0")] @@ -4241,6 +4256,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 01b301cb43d54..6cb160067f7ec 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -740,6 +740,10 @@ impl Iterator for Args { self.inner.next().map(|s| s.into_string().unwrap()) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "env", since = "1.0.0")] @@ -775,6 +779,8 @@ impl Iterator for ArgsOs { type Item = OsString; fn next(&mut self) -> Option { self.inner.next() } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } #[stable(feature = "env", since = "1.0.0")] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1bbda9b5bcb1a..79ba37b2eb565 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -886,6 +886,11 @@ impl<'a> Iterator for Iter<'a> { fn next(&mut self) -> Option<&'a OsStr> { self.inner.next().map(Component::as_os_str) } + + #[inline] + fn last(mut self) -> Option<&'a OsStr> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -949,6 +954,11 @@ impl<'a> Iterator for Components<'a> { } None } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 18de1096df2a2..f0594bb21bd83 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -35,6 +35,8 @@ impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { self.iter.next() } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } impl ExactSizeIterator for Args { diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index b3c77b8699563..6766099c1ece1 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -37,6 +37,10 @@ impl Iterator for Args { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } impl ExactSizeIterator for Args { diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs index b04bb484eedb9..744d7ec59d3a3 100644 --- a/src/libstd/sys/windows/args.rs +++ b/src/libstd/sys/windows/args.rs @@ -181,6 +181,8 @@ impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { self.parsed_args_list.next() } fn size_hint(&self) -> (usize, Option) { self.parsed_args_list.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } impl DoubleEndedIterator for Args { From 1e47250540bc97f921d1b7e2982f1904fa191dff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 May 2019 17:59:48 +0200 Subject: [PATCH 02/13] as_ptr returns a read-only pointer --- src/libcore/slice/mod.rs | 6 ++++++ src/libcore/str/mod.rs | 5 +++++ src/libstd/ffi/c_str.rs | 9 +++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 8731f48675356..c273153fa5ead 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -359,6 +359,10 @@ impl [T] { /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`). If you need to mutate + /// the contents of the slice, use [`as_mut_ptr`]. + /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. /// @@ -374,6 +378,8 @@ impl [T] { /// } /// } /// ``` + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn as_ptr(&self) -> *const T { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 45421848cec5d..96a5ce61ca0bc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2188,7 +2188,12 @@ impl str { /// [`u8`]. This pointer will be pointing to the first byte of the string /// slice. /// + /// The caller must ensure that the memory the pointer points to + /// is never written to. If you need to mutate + /// the contents of the string slice, use [`as_mut_ptr`]. + /// /// [`u8`]: primitive.u8.html + /// [`as_mut_ptr`]: #method.as_mut_ptr /// /// # Examples /// diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index f93583dff818f..5c6c43017cf64 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -43,7 +43,9 @@ use crate::sys; /// `CString` implements a [`as_ptr`] method through the [`Deref`] /// trait. This method will give you a `*const c_char` which you can /// feed directly to extern functions that expect a nul-terminated -/// string, like C's `strdup()`. +/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a +/// read-only pointer; if the C code writes to it, that causes +/// undefined behavior. /// /// # Extracting a slice of the whole C string /// @@ -61,7 +63,7 @@ use crate::sys; /// /// Once you have the kind of slice you need (with or without a nul /// terminator), you can call the slice's own -/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to +/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// @@ -1043,6 +1045,9 @@ impl CStr { /// /// **WARNING** /// + /// The returned pointer is read-only; writing to it (including passing it + /// to C code that writes to it) causes undefined behavior. + /// /// It is your responsibility to make sure that the underlying memory is not /// freed too early. For example, the following code will cause undefined /// behavior when `ptr` is used inside the `unsafe` block: From bd005a242a3125c432a76f982dab5a8d59e970f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2019 13:10:01 -0400 Subject: [PATCH 03/13] forego caching for all participants in cycles, apart from root node --- src/librustc/traits/select.rs | 50 ++++++++++++- src/test/ui/traits/cycle-cache-err-60010.rs | 71 +++++++++++++++++++ .../ui/traits/cycle-cache-err-60010.stderr | 20 ++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/traits/cycle-cache-err-60010.rs create mode 100644 src/test/ui/traits/cycle-cache-err-60010.stderr diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8beabe058cf4f..3c4d48b17b9f3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -43,6 +43,7 @@ use crate::hir; use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; +use std::cell::Cell; use std::cmp; use std::fmt::{self, Display}; use std::iter; @@ -153,6 +154,31 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// selection-context's freshener. Used to check for recursion. fresh_trait_ref: ty::PolyTraitRef<'tcx>, + /// Starts out as false -- if, during evaluation, we encounter a + /// cycle, then we will set this flag to true for all participants + /// in the cycle (apart from the "head" node). These participants + /// will then forego caching their results. This is not the most + /// efficient solution, but it addresses #60010. The problem we + /// are trying to prevent: + /// + /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` + /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) + /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) + /// + /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` + /// is `EvaluatedToOk`; this is because they were only considered + /// ok on the premise that if `A: AutoTrait` held, but we indeed + /// encountered a problem (later on) with `A: AutoTrait. So we + /// currently set a flag on the stack node for `B: AutoTrait` (as + /// well as the second instance of `A: AutoTrait`) to supress + /// caching. + /// + /// This is a simple, targeted fix. The correct fix requires + /// deeper changes, but would permit more caching: we could + /// basically defer caching until we have fully evaluated the + /// tree, and then cache the entire tree at once. + in_cycle: Cell, + previous: TraitObligationStackList<'prev, 'tcx>, } @@ -840,8 +866,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); let result = result?; - debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); - self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); + if !stack.in_cycle.get() { + debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); + } else { + debug!( + "evaluate_trait_predicate_recursively: skipping cache because {:?} \ + is a cycle participant", + fresh_trait_ref, + ); + } Ok(result) } @@ -948,6 +982,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); + // If we have a stack like `A B C D E A`, where the top of + // the stack is the final `A`, then this will iterate over + // `A, E, D, C, B` -- i.e., all the participants apart + // from the cycle head. We mark them as participating in a + // cycle. This suppresses caching for those nodes. See + // `in_cycle` field for more details. + for item in stack.iter().take(rec_index + 1) { + debug!("evaluate_stack: marking {:?} as cycle participant", item.fresh_trait_ref); + item.in_cycle.set(true); + } + // Subtle: when checking for a coinductive cycle, we do // not compare using the "freshened trait refs" (which // have erased regions) but rather the fully explicit @@ -3692,6 +3737,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { TraitObligationStack { obligation, fresh_trait_ref, + in_cycle: Cell::new(false), previous: previous_stack, } } diff --git a/src/test/ui/traits/cycle-cache-err-60010.rs b/src/test/ui/traits/cycle-cache-err-60010.rs new file mode 100644 index 0000000000000..45aa1b3c52239 --- /dev/null +++ b/src/test/ui/traits/cycle-cache-err-60010.rs @@ -0,0 +1,71 @@ +// Test that we properly detect the cycle amongst the traits +// here and report an error. + +use std::panic::RefUnwindSafe; + +trait Database { + type Storage; +} +trait HasQueryGroup {} +trait Query { + type Data; +} +trait SourceDatabase { + fn parse(&self) { + loop {} + } +} + +struct ParseQuery; +struct RootDatabase { + _runtime: Runtime, +} +struct Runtime { + _storage: Box, +} +struct SalsaStorage { + _parse: >::Data, //~ ERROR overflow +} + +impl Database for RootDatabase { //~ ERROR overflow + type Storage = SalsaStorage; +} +impl HasQueryGroup for RootDatabase {} +impl Query for ParseQuery +where + DB: SourceDatabase, + DB: Database, +{ + type Data = RootDatabase; +} +impl SourceDatabase for T +where + T: RefUnwindSafe, + T: HasQueryGroup, +{ +} + +pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 { + // This is not satisfied: + // + // - `RootDatabase: SourceDatabase` + // - requires `RootDatabase: RefUnwindSafe` + `RootDatabase: HasQueryGroup` + // - `RootDatabase: RefUnwindSafe` + // - requires `Runtime: RefUnwindSafe` + // - `Runtime: RefUnwindSafe` + // - requires `DB::Storage: RefUnwindSafe` (`SalsaStorage: RefUnwindSafe`) + // - `SalsaStorage: RefUnwindSafe` + // - requires `>::Data: RefUnwindSafe`, + // which means `ParseQuery: Query` + // - `ParseQuery: Query` + // - requires `RootDatabase: SourceDatabase`, + // - `RootDatabase: SourceDatabase` is already on the stack, so we have a + // cycle with non-coinductive participants + // + // we used to fail to report an error here because we got the + // caching wrong. + SourceDatabase::parse(db); + 22 +} + +fn main() {} diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr new file mode 100644 index 0000000000000..9192f7ba2e3b0 --- /dev/null +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -0,0 +1,20 @@ +error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` + --> $DIR/cycle-cache-err-60010.rs:27:5 + | +LL | _parse: >::Data, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Query` for `ParseQuery` + +error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` + --> $DIR/cycle-cache-err-60010.rs:30:6 + | +LL | impl Database for RootDatabase { + | ^^^^^^^^ + | + = note: required because of the requirements on the impl of `Query` for `ParseQuery` + = note: required because it appears within the type `SalsaStorage` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. From 30cf0e4251533e67603c755acee5b0bd56197fce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 May 2019 13:36:30 +0200 Subject: [PATCH 04/13] clarify wording --- src/libcore/slice/mod.rs | 4 ++-- src/libcore/str/mod.rs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index c273153fa5ead..50d2ba0d3ef7f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -360,8 +360,8 @@ impl [T] { /// function returns, or else it will end up pointing to garbage. /// /// The caller must also ensure that the memory the pointer (non-transitively) points to - /// is never written to (except inside an `UnsafeCell`). If you need to mutate - /// the contents of the slice, use [`as_mut_ptr`]. + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 96a5ce61ca0bc..ef4bd83cbc5a6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2188,9 +2188,8 @@ impl str { /// [`u8`]. This pointer will be pointing to the first byte of the string /// slice. /// - /// The caller must ensure that the memory the pointer points to - /// is never written to. If you need to mutate - /// the contents of the string slice, use [`as_mut_ptr`]. + /// The caller must ensure that the returned pointer is never written to. + /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`]. /// /// [`u8`]: primitive.u8.html /// [`as_mut_ptr`]: #method.as_mut_ptr From bf3c46cfc9dbe677ae801f0459cea5b8e5e5a178 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 11 May 2019 00:42:29 +0100 Subject: [PATCH 05/13] Allow subdirectories to be tested by x.py test --- src/bootstrap/test.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a3d96836aad54..3847a2a1e4649 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1184,8 +1184,13 @@ impl Step for Compiletest { Err(_) => p, } }) - .filter(|p| p.starts_with(suite_path) && p.is_file()) - .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap()) + .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file())) + .filter_map(|p| { + match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) { + Some(s) if s != "" => Some(s), + _ => None, + } + }) .collect(); test_args.append(&mut builder.config.cmd.test_args()); From 4cf2379f6176b704bb8648107beee9c896d1b133 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:34:11 +0200 Subject: [PATCH 06/13] Revert "use SecRandomCopyBytes on macOS in Miri" This reverts commit 54aefc6a2d076b74921a8d78c5d8c68c13bfa4a7. --- src/libstd/sys/unix/rand.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index e923b9aa29b01..77f1439e17b10 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(all(unix, not(target_os = "ios"), - not(all(target_os = "macos", miri)), not(target_os = "openbsd"), not(target_os = "freebsd"), not(target_os = "fuchsia")))] @@ -107,9 +106,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -// HACK: However, we do use this when running in Miri on macOS; intercepting this is much -// easier than intercepting accesses to /dev/urandom. -#[cfg(any(target_os = "ios", all(target_os = "macos", miri)))] +#[cfg(target_os = "ios")] mod imp { use crate::io; use crate::ptr; From decd6d366018823a8b1116b346bc778eb010accd Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Mon, 13 May 2019 13:29:49 +0200 Subject: [PATCH 07/13] modify comment modify the comment on `in_cycle` to reflect changes requested by ariel and myself. --- src/librustc/traits/select.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3c4d48b17b9f3..b333f4b96514d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -173,10 +173,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// well as the second instance of `A: AutoTrait`) to supress /// caching. /// - /// This is a simple, targeted fix. The correct fix requires + /// This is a simple, targeted fix. A more-performant fix requires /// deeper changes, but would permit more caching: we could /// basically defer caching until we have fully evaluated the - /// tree, and then cache the entire tree at once. + /// tree, and then cache the entire tree at once. In any case, the + /// performance impact here shouldn't be so horrible: every time + /// this is hit, we do cache at least one trait, so we only + /// evaluate each member of a cycle up to N times, where N is the + /// length of the cycle. This means the performance impact is + /// bounded and we shouldn't have any terrible worst-cases. in_cycle: Cell, previous: TraitObligationStackList<'prev, 'tcx>, From 43207cada264796fe9307ded77e63751c1e0646a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:39:30 +0200 Subject: [PATCH 08/13] update miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 053aa694990a2..bc0c76d861a17 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 053aa694990a212ad8942dd72101ede23597c0e9 +Subproject commit bc0c76d861a178911f3f506196a7404eda1e690d From 36fd00e81cd4af2c83839f0c0b96dc20663710c5 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 May 2019 21:57:20 +0100 Subject: [PATCH 09/13] Allow late bound regions in existential types --- src/librustc_typeck/check/writeback.rs | 7 +++-- .../issue-60655-latebound-regions.rs | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/existential_types/issue-60655-latebound-regions.rs diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ecb8e09ec2461..13baf667808f8 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -466,6 +466,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + debug_assert!(!instantiated_ty.has_escaping_bound_vars()); + let generics = self.tcx().generics_of(def_id); let definition_ty = if generics.parent.is_some() { @@ -524,8 +526,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { }, lt_op: |region| { match region { - // ignore static regions - ty::ReStatic => region, + // Skip static and bound regions: they don't + // require substitution. + ty::ReStatic | ty::ReLateBound(..) => region, _ => { trace!("checking {:?}", region); for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) { diff --git a/src/test/ui/existential_types/issue-60655-latebound-regions.rs b/src/test/ui/existential_types/issue-60655-latebound-regions.rs new file mode 100644 index 0000000000000..a4fe86501299f --- /dev/null +++ b/src/test/ui/existential_types/issue-60655-latebound-regions.rs @@ -0,0 +1,30 @@ +// Test that existential types are allowed to contain late-bound regions. + +// compile-pass +// edition:2018 + +#![feature(async_await, existential_type)] + +use std::future::Future; + +pub existential type Func: Sized; + +// Late bound region should be allowed to escape the function, since it's bound +// in the type. +fn null_function_ptr() -> Func { + None:: fn(&'a ())> +} + +async fn async_nop(_: &u8) {} + +pub existential type ServeFut: Future; + +// Late bound regions occur in the generator witness type here. +fn serve() -> ServeFut { + async move { + let x = 5; + async_nop(&x).await + } +} + +fn main() {} From 7e94f9c72ee5eb33f2e373e91ce6dbd36ae30cf8 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 13 May 2019 11:03:48 -0400 Subject: [PATCH 10/13] default to $ARCH-apple-macosx10.7.0 LLVM triple for darwin targets Over in #60378, we made `rustc` switch LLVM target triples dynamically based on the `MACOSX_DEPLOYMENT_TARGET` environment variable. This change was made to align with `clang`'s behavior, and therefore make cross-language LTO feasible on OS X. Otherwise, `rustc` would produce LLVM bitcode files with a target triple of `x86_64-apple-darwin`, `clang` would produce LLVM bitcode files with a target triple of `x86_64-apple-macosx$VERSION`, and the linker would complain. This change worked fine, except for one corner case: if you didn't have `MACOSX_DEPLOYMENT_TARGET` set, and you wanted to do LTO on just Rust code, you'd get warning messages similar to: ``` warning: Linking two modules of different target triples: ' is 'x86_64-apple-macosx10.7.0' whereas 'main.7rcbfp3g-cgu.4' is 'x86_64-apple-darwin' ``` This message occurs because libstd is compiled with `MACOSX_DEPLOYMENT_TARGET` set to 10.7. The LLVM bitcode distributed in libstd's rlibs, then, is tagged with the target triple of `x86_64-apple-macosx10.7.0`, while the bitcode `rustc` produces for "user" code is tagged with the target triple of `x86_64-apple-darwin`. It's not good to have LTO on just Rust code (probably much more common than cross-language LTO) warn by default. These warnings also break Cargo's testsuite. This change defaults to acting as though `MACOSX_DEPLOYMENT_TARGET` was set to 10.7. "user" code will then be given a target triple that is equivalent to the target triple libstd bitcode is already using. The above warning will therefore go away. `rustc` already assumes that compiling without `MACOSX_DEPLOYMENT_TARGET` means that we're compiling for a target compatible with OS X 10.7 (e.g. that things like TLS work properly). So this change is really just making things conform more closely to the status quo. (It's also worth noting that before and after this patch, compiling with `MACOSX_DEPLOYMENT_TARGET` set to, say, 10.9, works just fine: target triples with an "apple" version ignore OS versions when checking compatibility, so bitcode with a `x86_64-apple-macosx10.7.0` triple works just fine with bitcode with a `x86_64-apple-macosx10.9.0` triple.) --- src/librustc_target/spec/apple_base.rs | 17 +++++------------ .../codegen/i686-no-macosx-deployment-target.rs | 2 +- .../x86_64-no-macosx-deployment-target.rs | 2 +- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index 9dd343b6c8de8..53364e72bfe3a 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -14,7 +14,7 @@ pub fn opts() -> TargetOptions { // // Here we detect what version is being requested, defaulting to 10.7. ELF // TLS is flagged as enabled if it looks to be supported. - let version = macos_deployment_target().unwrap_or((10, 7)); + let version = macos_deployment_target(); TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections @@ -35,7 +35,7 @@ pub fn opts() -> TargetOptions { } } -fn macos_deployment_target() -> Option<(u32, u32)> { +fn macos_deployment_target() -> (u32, u32) { let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); let version = deployment_target.as_ref().and_then(|s| { let mut i = s.splitn(2, '.'); @@ -44,17 +44,10 @@ fn macos_deployment_target() -> Option<(u32, u32)> { a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() }); - version + version.unwrap_or((10, 7)) } pub fn macos_llvm_target(arch: &str) -> String { - let version = macos_deployment_target(); - let llvm_target = match version { - Some((major, minor)) => { - format!("{}-apple-macosx{}.{}.0", arch, major, minor) - }, - None => format!("{}-apple-darwin", arch) - }; - - llvm_target + let (major, minor) = macos_deployment_target(); + format!("{}-apple-macosx{}.{}.0", arch, major, minor) } diff --git a/src/test/codegen/i686-no-macosx-deployment-target.rs b/src/test/codegen/i686-no-macosx-deployment-target.rs index eb826590523b7..1cebc49236fee 100644 --- a/src/test/codegen/i686-no-macosx-deployment-target.rs +++ b/src/test/codegen/i686-no-macosx-deployment-target.rs @@ -19,7 +19,7 @@ pub struct Bool { b: bool, } -// CHECK: target triple = "i686-apple-darwin" +// CHECK: target triple = "i686-apple-macosx10.7.0" #[no_mangle] pub extern "C" fn structbool() -> Bool { Bool { b: true } diff --git a/src/test/codegen/x86_64-no-macosx-deployment-target.rs b/src/test/codegen/x86_64-no-macosx-deployment-target.rs index 58a11d1095bbe..c5ac73b54e186 100644 --- a/src/test/codegen/x86_64-no-macosx-deployment-target.rs +++ b/src/test/codegen/x86_64-no-macosx-deployment-target.rs @@ -19,7 +19,7 @@ pub struct Bool { b: bool, } -// CHECK: target triple = "x86_64-apple-darwin" +// CHECK: target triple = "x86_64-apple-macosx10.7.0" #[no_mangle] pub extern "C" fn structbool() -> Bool { Bool { b: true } From 58c6a94f00110a08725182a8519cedee16819c71 Mon Sep 17 00:00:00 2001 From: Benjamin Schultzer Date: Mon, 13 May 2019 15:13:17 -0700 Subject: [PATCH 11/13] Improve the "must use" lint for `Future` Co-Authored-By: Mazdak Farrokhzad --- src/libcore/future/future.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 504330a023b31..3f76ac20192ba 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -23,7 +23,7 @@ use crate::task::{Context, Poll}; /// When using a future, you generally won't call `poll` directly, but instead /// `await!` the value. #[doc(spotlight)] -#[must_use = "futures do nothing unless polled"] +#[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] pub trait Future { /// The type of value produced on completion. From b470d48c8a58a6cd91a14e5ba6387f424da6c5db Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 14 May 2019 09:42:32 +0100 Subject: [PATCH 12/13] Add comment --- src/bootstrap/test.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 3847a2a1e4649..f1bb318651a31 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1186,6 +1186,12 @@ impl Step for Compiletest { }) .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file())) .filter_map(|p| { + // Since test suite paths are themselves directories, if we don't + // specify a directory or file, we'll get an empty string here + // (the result of the test suite directory without its suite prefix). + // Therefore, we need to filter these out, as only the first --test-args + // flag is respected, so providing an empty --test-args conflicts with + // any following it. match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) { Some(s) if s != "" => Some(s), _ => None, From 41184aa545c8ddf3e417dedbc23a6c8198d5de8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Tue, 14 May 2019 11:36:31 +0200 Subject: [PATCH 13/13] submodules: update clippy from 3710ec59 to ad3269c4 Changes: ```` Rustfmt all the things Clippy dogfood Update for compiletest changes Use symbols instead of strings Rustup to rustc 1.36.0-nightly (1764b2972 2019-05-12) Add regression test for identity_conversion FP UI test cleanup: Extract many_single_char_names tests Add tests for empty_loop lint Add in_macro again Rename in_macro to in_macro_or_desugar ```` --- src/tools/clippy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy b/src/tools/clippy index 3710ec5996229..ad3269c4b510b 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 3710ec59962295336ab4aed100267b584dd7df7d +Subproject commit ad3269c4b510b94b7c0082f4bb341bee6ed1eca4