diff --git a/src/Cargo.lock b/src/Cargo.lock index 7620fe8ddb3c..5e7909ff4355 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2585,6 +2585,11 @@ dependencies = [ [[package]] name = "tidy" version = "0.1.0" +dependencies = [ + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "time" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 576e50782474..aa0a7c52246b 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -810,6 +810,7 @@ impl Step for Src { "src/libterm", "src/jemalloc", "src/libprofiler_builtins", + "src/stdsimd", ]; let std_src_dirs_exclude = [ "src/libcompiler_builtins/compiler-rt/test", diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c0998c1e42c9..48490493525f 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -528,6 +528,7 @@ impl Step for Tidy { println!("tidy check ({})", host); let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(build.src.join("src")); + cmd.arg(&build.initial_cargo); if !build.config.vendor { cmd.arg("--no-vendor"); } diff --git a/src/etc/sugarise-doc-comments.py b/src/etc/sugarise-doc-comments.py deleted file mode 100755 index ac2223f4acef..000000000000 --- a/src/etc/sugarise-doc-comments.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2012-2013 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. - -# -# this script attempts to turn doc comment attributes (#[doc = "..."]) -# into sugared-doc-comments (/** ... */ and /// ...) -# -# it sugarises all .rs/.rc files underneath the working directory -# - -import sys -import os -import fnmatch -import re - - -DOC_PATTERN = '^(?P[\\t ]*)#\\[(\\s*)doc(\\s*)=' + \ - '(\\s*)"(?P(\\"|[^"])*?)"(\\s*)\\]' + \ - '(?P;)?' - -ESCAPES = [("\\'", "'"), - ('\\"', '"'), - ("\\n", "\n"), - ("\\r", "\r"), - ("\\t", "\t")] - - -def unescape(s): - for (find, repl) in ESCAPES: - s = s.replace(find, repl) - return s - - -def block_trim(s): - lns = s.splitlines() - - # remove leading/trailing whitespace-lines - while lns and not lns[0].strip(): - lns = lns[1:] - while lns and not lns[-1].strip(): - lns = lns[:-1] - - # remove leading horizontal whitespace - n = sys.maxsize - for ln in lns: - if ln.strip(): - n = min(n, len(re.search('^\s*', ln).group())) - if n != sys.maxsize: - lns = [ln[n:] for ln in lns] - - # strip trailing whitespace - lns = [ln.rstrip() for ln in lns] - - return lns - - -def replace_doc(m): - indent = m.group('indent') - text = block_trim(unescape(m.group('text'))) - - if len(text) > 1: - inner = '!' if m.group('semi') else '*' - starify = lambda s: indent + ' *' + (' ' + s if s else '') - text = '\n'.join(map(starify, text)) - repl = indent + '/*' + inner + '\n' + text + '\n' + indent + ' */' - else: - inner = '!' if m.group('semi') else '/' - repl = indent + '//' + inner + ' ' + text[0] - - return repl - - -def sugarise_file(path): - s = open(path).read() - - r = re.compile(DOC_PATTERN, re.MULTILINE | re.DOTALL) - ns = re.sub(r, replace_doc, s) - - if s != ns: - open(path, 'w').write(ns) - -for (dirpath, dirnames, filenames) in os.walk('.'): - for name in fnmatch.filter(filenames, '*.r[sc]'): - sugarise_file(os.path.join(dirpath, name)) diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 3041f85cd4c3..8aaac5d6e08a 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. @@ -1019,7 +1019,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `BinaryHeap`. @@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 75a59de337ce..b776556d59f1 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -722,7 +722,7 @@ impl ExactSizeIterator for Box { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 618ef81fdd98..ed9c8c18f0d6 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1365,7 +1365,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} @@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 327eaaf46513..2e3157147a08 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -971,7 +971,7 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Range<'a, T> {} /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None @@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d250cfe1880f..3f3067845588 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(i128_type)] #![feature(inclusive_range)] @@ -124,8 +123,9 @@ #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(exact_chunks)] +#![feature(pointer_methods)] -#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] +#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] // Allow testing this library diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index ec579e3fd68d..097d2e414f5c 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} impl<'a, T> IterMut<'a, T> { @@ -1117,7 +1117,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a00e3d17dd00..14d5e96d2e73 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -43,6 +43,7 @@ use core::str as core_str; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; +use core::ptr; use core::iter::FusedIterator; use std_unicode::str::{UnicodeStr, Utf16Encoder}; @@ -171,7 +172,7 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for EncodeUtf16<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2066,9 +2067,59 @@ impl str { /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { - let mut s = String::with_capacity(self.len() * n); - s.extend((0..n).map(|_| self)); - s + if n == 0 { + return String::new(); + } + + // If `n` is larger than zero, it can be split as + // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. + // `2^expn` is the number represented by the leftmost '1' bit of `n`, + // and `rem` is the remaining part of `n`. + + // Using `Vec` to access `set_len()`. + let mut buf = Vec::with_capacity(self.len() * n); + + // `2^expn` repetition is done by doubling `buf` `expn`-times. + buf.extend(self.as_bytes()); + { + let mut m = n >> 1; + // If `m > 0`, there are remaining bits up to the leftmost '1'. + while m > 0 { + // `buf.extend(buf)`: + unsafe { + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut u8).add(buf.len()), + buf.len(), + ); + // `buf` has capacity of `self.len() * n`. + let buf_len = buf.len(); + buf.set_len(buf_len * 2); + } + + m >>= 1; + } + } + + // `rem` (`= n - 2^expn`) repetition is done by copying + // first `rem` repetitions from `buf` itself. + let rem_len = self.len() * n - buf.len(); // `self.len() * rem` + if rem_len > 0 { + // `buf.extend(buf[0 .. rem_len])`: + unsafe { + // This is non-overlapping since `2^expn > rem`. + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut u8).add(buf.len()), + rem_len, + ); + // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). + let buf_cap = buf.capacity(); + buf.set_len(buf_cap); + } + } + + unsafe { String::from_utf8_unchecked(buf) } } /// Checks if all characters in this string are within the ASCII range. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 409d2ab287e7..370fb6b4e890 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index feed7c8699a3..2f57c53a6d83 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2273,7 +2273,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2379,7 +2379,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} /// A place for insertion at the back of a `Vec`. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 8b686365e692..68add3cbd51f 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. @@ -2140,7 +2140,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `VecDeque`. @@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index f409536d1b0e..2c4bccebceb9 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -136,7 +136,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 419ae96b94bd..1372151b7536 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -10,6 +10,24 @@ //! Shareable mutable containers. //! +//! Rust memory safety is based on this rule: Given an object `T`, it is only possible to +//! have one of the following: +//! +//! - Having several immutable references (`&T`) to the object (also known as **aliasing**). +//! - Having one mutable reference (`&mut T`) to the object (also known as **mutability**). +//! +//! This is enforced by the Rust compiler. However, there are situations where this rule is not +//! flexible enough. Sometimes it is required to have multiple references to an object and yet +//! mutate it. +//! +//! Shareable mutable containers exist to permit mutability in a controlled manner, even in the +//! presence of aliasing. Both `Cell` and `RefCell` allows to do this in a single threaded +//! way. However, neither `Cell` nor `RefCell` are thread safe (they do not implement +//! `Sync`). If you need to do aliasing and mutation between multiple threads it is possible to +//! use [`Mutex`](../../std/sync/struct.Mutex.html), +//! [`RwLock`](../../std/sync/struct.RwLock.html) or +//! [`atomic`](../../core/sync/atomic/index.html) types. +//! //! Values of the `Cell` and `RefCell` types may be mutated through shared references (i.e. //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`) //! references. We say that `Cell` and `RefCell` provide 'interior mutability', in contrast diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 7215bd2a4768..1638f9710f59 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -79,7 +79,7 @@ pub const MAX: char = '\u{10ffff}'; /// Converts a `u32` to a `char`. /// -/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with /// [`as`]: /// /// ``` @@ -131,7 +131,7 @@ pub fn from_u32(i: u32) -> Option { /// Converts a `u32` to a `char`, ignoring validity. /// -/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with /// [`as`]: /// /// ``` @@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -790,7 +790,7 @@ impl Iterator for EscapeDebug { #[stable(feature = "char_escape_debug", since = "1.20.0")] impl ExactSizeIterator for EscapeDebug { } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] @@ -904,5 +904,5 @@ impl> Iterator for DecodeUtf8 { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "decode_utf8", issue = "33906")] impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a05d67a304fa..830ebad06542 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1292,6 +1292,10 @@ extern "rust-intrinsic" { /// Reverses the bytes in an integer type `T`. pub fn bswap(x: T) -> T; + /// Reverses the bits in an integer type `T`. + #[cfg(not(stage0))] + pub fn bitreverse(x: T) -> T; + /// Performs checked integer addition. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `overflowing_add` method. For example, diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index b06534c9c1ec..2cfbc0922934 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1180,19 +1180,19 @@ pub trait Iterator { /// /// // this iterator sequence is complex. /// let sum = a.iter() - /// .cloned() - /// .filter(|&x| x % 2 == 0) - /// .fold(0, |sum, i| sum + i); + /// .cloned() + /// .filter(|x| x % 2 == 0) + /// .fold(0, |sum, i| sum + i); /// /// println!("{}", sum); /// /// // let's add some inspect() calls to investigate what's happening /// let sum = a.iter() - /// .cloned() - /// .inspect(|x| println!("about to filter: {}", x)) - /// .filter(|&x| x % 2 == 0) - /// .inspect(|x| println!("made it through filter: {}", x)) - /// .fold(0, |sum, i| sum + i); + /// .cloned() + /// .inspect(|x| println!("about to filter: {}", x)) + /// .filter(|x| x % 2 == 0) + /// .inspect(|x| println!("made it through filter: {}", x)) + /// .fold(0, |sum, i| sum + i); /// /// println!("{}", sum); /// ``` @@ -1200,6 +1200,7 @@ pub trait Iterator { /// This will print: /// /// ```text + /// 6 /// about to filter: 1 /// about to filter: 4 /// made it through filter: 4 @@ -1230,8 +1231,7 @@ pub trait Iterator { /// /// let iter = a.into_iter(); /// - /// let sum: i32 = iter.take(5) - /// .fold(0, |acc, &i| acc + i ); + /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i ); /// /// assert_eq!(sum, 6); /// @@ -1245,9 +1245,7 @@ pub trait Iterator { /// let mut iter = a.into_iter(); /// /// // instead, we add in a .by_ref() - /// let sum: i32 = iter.by_ref() - /// .take(2) - /// .fold(0, |acc, &i| acc + i ); + /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i ); /// /// assert_eq!(sum, 3); /// @@ -1304,9 +1302,7 @@ pub trait Iterator { /// /// let a = [1, 2, 3]; /// - /// let doubled: VecDeque = a.iter() - /// .map(|&x| x * 2) - /// .collect(); + /// let doubled: VecDeque = a.iter().map(|&x| x * 2).collect(); /// /// assert_eq!(2, doubled[0]); /// assert_eq!(4, doubled[1]); @@ -1318,9 +1314,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let doubled = a.iter() - /// .map(|&x| x * 2) - /// .collect::>(); + /// let doubled = a.iter().map(|x| x * 2).collect::>(); /// /// assert_eq!(vec![2, 4, 6], doubled); /// ``` @@ -1331,9 +1325,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let doubled = a.iter() - /// .map(|&x| x * 2) - /// .collect::>(); + /// let doubled = a.iter().map(|x| x * 2).collect::>(); /// /// assert_eq!(vec![2, 4, 6], doubled); /// ``` @@ -1344,9 +1336,9 @@ pub trait Iterator { /// let chars = ['g', 'd', 'k', 'k', 'n']; /// /// let hello: String = chars.iter() - /// .map(|&x| x as u8) - /// .map(|x| (x + 1) as char) - /// .collect(); + /// .map(|&x| x as u8) + /// .map(|x| (x + 1) as char) + /// .collect(); /// /// assert_eq!("hello", hello); /// ``` @@ -1393,8 +1385,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let (even, odd): (Vec, Vec) = a.into_iter() - /// .partition(|&n| n % 2 == 0); + /// let (even, odd): (Vec, Vec) = a + /// .into_iter() + /// .partition(|&n| n % 2 == 0); /// /// assert_eq!(even, vec![2]); /// assert_eq!(odd, vec![1, 3]); @@ -1457,8 +1450,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array - /// let sum = a.iter() - /// .try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = a.iter().try_fold(0i8, |acc, &x| acc.checked_add(x)); /// /// assert_eq!(sum, Some(6)); /// ``` @@ -1556,8 +1548,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the sum of all of the elements of the array - /// let sum = a.iter() - /// .fold(0, |acc, &x| acc + x); + /// let sum = a.iter().fold(0, |acc, x| acc + x); /// /// assert_eq!(sum, 6); /// ``` diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 257d7d6caaaf..a6802d606ca8 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -344,7 +344,7 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; @@ -506,7 +506,7 @@ impl ExactSizeIterator for Rev } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} @@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} @@ -662,7 +662,7 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator for stepping iterators by a custom amount. @@ -1002,7 +1002,7 @@ impl DoubleEndedIterator for Chain where } // Note: *both* must be fused to handle double-ended iterators. -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Chain where A: FusedIterator, B: FusedIterator, @@ -1262,7 +1262,7 @@ unsafe impl TrustedRandomAccess for Zip } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} @@ -1404,7 +1404,7 @@ impl ExactSizeIterator for Map } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} @@ -1553,7 +1553,7 @@ impl DoubleEndedIterator for Filter } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} @@ -1663,7 +1663,7 @@ impl DoubleEndedIterator for FilterMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} @@ -1818,7 +1818,7 @@ unsafe impl TrustedRandomAccess for Enumerate } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1938,7 +1938,7 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Peekable {} impl Peekable { @@ -2072,7 +2072,7 @@ impl Iterator for SkipWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2151,7 +2151,7 @@ impl Iterator for TakeWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2290,7 +2290,7 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -2371,7 +2371,7 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2517,7 +2517,7 @@ impl DoubleEndedIterator for FlatMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} @@ -2765,7 +2765,7 @@ pub struct Fuse { done: bool } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Fuse where I: Iterator {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2896,7 +2896,7 @@ unsafe impl TrustedRandomAccess for Fuse } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl Iterator for Fuse where I: FusedIterator { #[inline] fn next(&mut self) -> Option<::Item> { @@ -2938,7 +2938,7 @@ impl Iterator for Fuse where I: FusedIterator { } } -#[unstable(feature = "fused", reason = "recently added", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator + FusedIterator { @@ -3082,6 +3082,6 @@ impl ExactSizeIterator for Inspect } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 65b38c94dda3..9a3fd215dcfe 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl DoubleEndedIterator for ops::Range { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::Range {} #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl Iterator for ops::RangeFrom { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -463,5 +463,5 @@ impl DoubleEndedIterator for ops::RangeInclusive { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index dfd42f3e7330..0fc1a3aa8ac0 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -41,7 +41,7 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Repeat {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -135,7 +135,7 @@ impl A> DoubleEndedIterator for RepeatWith { fn next_back(&mut self) -> Option { self.next() } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -259,7 +259,7 @@ impl ExactSizeIterator for Empty { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Empty {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Empty {} // not #[derive] because that adds a Clone bound on T, @@ -340,7 +340,7 @@ impl ExactSizeIterator for Once { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Once {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 860742d9eab6..0267fcd37545 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -959,10 +959,10 @@ impl Product> for Result /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] pub trait FusedIterator: Iterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 59a67fff48cf..a46ac2b5f0fe 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -321,6 +321,33 @@ $EndFeature, " (self as $UnsignedT).swap_bytes() as Self } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i16` is used here. + /// + /// Basic usage: + /// + /// ``` + /// #![feature(reverse_bits)] + /// + /// let n: i16 = 0b0000000_01010101; + /// assert_eq!(n, 85); + /// + /// let m = n.reverse_bits(); + /// + /// assert_eq!(m as u16, 0b10101010_00000000); + /// assert_eq!(m, -22016); + /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] + #[cfg(not(stage0))] + #[inline] + pub fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + doc_comment! { concat!("Converts an integer from big endian to the target's endianness. @@ -1773,6 +1800,33 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " unsafe { intrinsics::bswap(self as $ActualT) as Self } } + /// Reverses the bit pattern of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u16` is used here. + /// + /// ``` + /// #![feature(reverse_bits)] + /// + /// let n: u16 = 0b0000000_01010101; + /// assert_eq!(n, 85); + /// + /// let m = n.reverse_bits(); + /// + /// assert_eq!(m, 0b10101010_00000000); + /// assert_eq!(m, 43520); + /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] + #[cfg(not(stage0))] + #[inline] + pub fn reverse_bits(self) -> Self { + unsafe { intrinsics::bitreverse(self as $ActualT) as Self } + } + doc_comment! { concat!("Converts an integer from big endian to the target's endianness. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index b8fe28d0f0d7..25f57d8c0f71 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -233,11 +233,11 @@ impl Option { /// [`usize`]: ../../std/primitive.usize.html /// /// ``` - /// let num_as_str: Option = Some("10".to_string()); + /// let text: Option = Some("Hello, world!".to_string()); /// // First, cast `Option` to `Option<&String>` with `as_ref`, - /// // then consume *that* with `map`, leaving `num_as_str` on the stack. - /// let num_as_int: Option = num_as_str.as_ref().map(|n| n.len()); - /// println!("still can print num_as_str: {:?}", num_as_str); + /// // then consume *that* with `map`, leaving `text` on the stack. + /// let text_length: Option = text.as_ref().map(|s| s.len()); + /// println!("still can print text: {:?}", text); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for Iter<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} @@ -1133,7 +1133,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3801db94e15d..c152d4979b90 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1125,7 +1125,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 64d0d3bb6503..19fe4dd36b68 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1455,7 +1455,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1583,7 +1583,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1731,7 +1731,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1829,7 +1829,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate @@ -1886,7 +1886,6 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -//#[unstable(feature = "fused", issue = "35602")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} @@ -1945,7 +1944,6 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -//#[unstable(feature = "fused", issue = "35602")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} @@ -2082,7 +2080,7 @@ macro_rules! forward_iterator { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} } @@ -2188,7 +2186,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} #[doc(hidden)] @@ -2307,7 +2305,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} #[doc(hidden)] @@ -2423,7 +2421,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} #[doc(hidden)] @@ -2533,7 +2531,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} #[doc(hidden)] @@ -2630,7 +2628,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} #[doc(hidden)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 765b369e4b25..e225c9522bc0 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Chars<'a> {} impl<'a> Chars<'a> { @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for CharIndices<'a> {} impl<'a> CharIndices<'a> { @@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Bytes<'a> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> where P::Searcher: ReverseSearcher<'a> {} @@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Lines<'a> {} /// Created with the method [`lines_any`]. @@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 939afdcb982a..971991dce3d1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(try_trait)] #![feature(exact_chunks)] #![feature(atomic_nand)] +#![feature(reverse_bits)] extern crate core; extern crate test; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index daa1cc3a7f4f..ca6906f73104 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -97,6 +97,17 @@ mod tests { assert_eq!(_1.swap_bytes(), _1); } + #[test] + fn test_reverse_bits() { + assert_eq!(A.reverse_bits().reverse_bits(), A); + assert_eq!(B.reverse_bits().reverse_bits(), B); + assert_eq!(C.reverse_bits().reverse_bits(), C); + + // Swapping these should make no difference + assert_eq!(_0.reverse_bits(), _0); + assert_eq!(_1.reverse_bits(), _1); + } + #[test] fn test_le() { assert_eq!($T::from_le(A.to_le()), A); diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index aa678ba788a5..84fdeba4ab3c 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -436,6 +436,9 @@ impl DepKind { } define_dep_nodes!( <'tcx> + // We use this for most things when incr. comp. is turned off. + [] Null, + // Represents the `Krate` as a whole (the `hir::Krate` value) (as // distinct from the krate module). This is basically a hash of // the entire krate, so if you read from `Krate` (e.g., by calling @@ -553,7 +556,7 @@ define_dep_nodes!( <'tcx> [] RvaluePromotableMap(DefId), [] ImplParent(DefId), [] TraitOfItem(DefId), - [] IsExportedSymbol(DefId), + [] IsReachableNonGeneric(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), [] FnArgNames(DefId), @@ -571,7 +574,7 @@ define_dep_nodes!( <'tcx> [] GetPanicStrategy(CrateNum), [] IsNoBuiltins(CrateNum), [] ImplDefaultness(DefId), - [] ExportedSymbolIds(CrateNum), + [] ReachableNonGenerics(CrateNum), [] NativeLibraries(CrateNum), [] PluginRegistrarFn(CrateNum), [] DeriveRegistrarFn(CrateNum), @@ -605,8 +608,8 @@ define_dep_nodes!( <'tcx> [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - [input] HasCloneClosures(CrateNum), - [input] HasCopyClosures(CrateNum), + [] HasCloneClosures(CrateNum), + [] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a @@ -630,8 +633,6 @@ define_dep_nodes!( <'tcx> [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [anon] NormalizeTy, - // We use this for most things when incr. comp. is turned off. - [] Null, [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -642,6 +643,7 @@ define_dep_nodes!( <'tcx> [] GetSymbolExportLevel(DefId), + [input] Features, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fa745bf16557..877027a21a22 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -550,7 +550,7 @@ impl<'a> LoweringContext<'a> { { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); - self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes; + self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes; assert!(self.in_band_ty_params.is_empty()); @@ -964,7 +964,7 @@ impl<'a> LoweringContext<'a> { let span = t.span; match itctx { ImplTraitContext::Existential => { - let has_feature = self.sess.features.borrow().conservative_impl_trait; + let has_feature = self.sess.features_untracked().conservative_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait", t.span, GateIssue::Language, @@ -988,7 +988,7 @@ impl<'a> LoweringContext<'a> { }, lifetimes) }, ImplTraitContext::Universal(def_id) => { - let has_feature = self.sess.features.borrow().universal_impl_trait; + let has_feature = self.sess.features_untracked().universal_impl_trait; if !t.span.allows_unstable() && !has_feature { emit_feature_err(&self.sess.parse_sess, "universal_impl_trait", t.span, GateIssue::Language, @@ -3713,7 +3713,7 @@ impl<'a> LoweringContext<'a> { } fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { - if self.sess.features.borrow().dyn_trait { + if self.sess.features_untracked().dyn_trait { self.sess.buffer_lint_with_diagnostic( builtin::BARE_TRAIT_OBJECT, id, span, "trait objects without an explicit `dyn` are deprecated", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ed8cea3eb656..d91aa3a38519 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2208,13 +2208,8 @@ impl<'a> State<'a> { if self.next_comment().is_none() { self.s.hardbreak()?; } - loop { - match self.next_comment() { - Some(ref cmnt) => { - self.print_comment(cmnt)?; - } - _ => break, - } + while let Some(ref cmnt) = self.next_comment() { + self.print_comment(cmnt)? } Ok(()) } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c31a5c9d86d7..f935cbfcde99 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -17,6 +17,7 @@ use std::hash as std_hash; use std::mem; use syntax::ast; +use syntax::feature_gate; use syntax::parse::token; use syntax::symbol::InternedString; use syntax::tokenstream; @@ -460,3 +461,21 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, (pos.0 - filemap_start.0, width as u32) } + + + +impl<'gcx> HashStable> for feature_gate::Features { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + // Unfortunately we cannot exhaustively list fields here, since the + // struct is macro generated. + self.declared_stable_lang_features.hash_stable(hcx, hasher); + self.declared_lib_features.hash_stable(hcx, hasher); + + self.walk_feature_fields(|feature_name, value| { + feature_name.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + }); + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 700d06acf11a..559b2720076f 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -56,7 +56,7 @@ //! time of error detection. use infer; -use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs}; +use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; use super::region_constraints::GenericKind; use super::lexical_region_resolve::RegionResolutionError; @@ -81,54 +81,22 @@ mod need_type_info; pub mod nice_region_error; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn note_and_explain_region(self, - region_scope_tree: ®ion::ScopeTree, - err: &mut DiagnosticBuilder, - prefix: &str, - region: ty::Region<'tcx>, - suffix: &str) { - fn item_scope_tag(item: &hir::Item) -> &'static str { - match item.node { - hir::ItemImpl(..) => "impl", - hir::ItemStruct(..) => "struct", - hir::ItemUnion(..) => "union", - hir::ItemEnum(..) => "enum", - hir::ItemTrait(..) => "trait", - hir::ItemFn(..) => "function body", - _ => "item" - } - } - - fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { - match item.node { - hir::TraitItemKind::Method(..) => "method body", - hir::TraitItemKind::Const(..) | - hir::TraitItemKind::Type(..) => "associated item" - } - } - - fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { - match item.node { - hir::ImplItemKind::Method(..) => "method body", - hir::ImplItemKind::Const(..) | - hir::ImplItemKind::Type(_) => "associated item" - } - } - - fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - heading: &str, span: Span) - -> (String, Option) { - let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo()); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), - Some(span)) - } - + pub fn note_and_explain_region( + self, + region_scope_tree: ®ion::ScopeTree, + err: &mut DiagnosticBuilder, + prefix: &str, + region: ty::Region<'tcx>, + suffix: &str, + ) { let (description, span) = match *region { ty::ReScope(scope) => { let new_string; let unknown_scope = || { - format!("{}unknown scope: {:?}{}. Please report a bug.", - prefix, scope, suffix) + format!( + "{}unknown scope: {:?}{}. Please report a bug.", + prefix, scope, suffix + ) }; let span = scope.span(self, region_scope_tree); let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) { @@ -137,15 +105,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprCall(..) => "call", hir::ExprMethodCall(..) => "method call", hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for", + hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let", + hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for", hir::ExprMatch(..) => "match", _ => "expression", }, Some(hir_map::NodeStmt(_)) => "statement", - Some(hir_map::NodeItem(it)) => item_scope_tag(&it), - Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), - Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), + Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it), + Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it), + Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it), Some(_) | None => { err.span_note(span, &unknown_scope()); return; @@ -153,74 +121,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; let scope_decorated_tag = match scope.data() { region::ScopeData::Node(_) => tag, - region::ScopeData::CallSite(_) => { - "scope of call-site for function" - } - region::ScopeData::Arguments(_) => { - "scope of function body" - } + region::ScopeData::CallSite(_) => "scope of call-site for function", + region::ScopeData::Arguments(_) => "scope of function body", region::ScopeData::Destruction(_) => { new_string = format!("destruction scope surrounding {}", tag); &new_string[..] } region::ScopeData::Remainder(r) => { - new_string = format!("block suffix following statement {}", - r.first_statement_index.index()); + new_string = format!( + "block suffix following statement {}", + r.first_statement_index.index() + ); &new_string[..] } }; - explain_span(self, scope_decorated_tag, span) + self.explain_span(scope_decorated_tag, span) } - ty::ReEarlyBound(_) | - ty::ReFree(_) => { - let scope = region.free_region_binding_scope(self); - let node = self.hir.as_local_node_id(scope) - .unwrap_or(DUMMY_NODE_ID); - let unknown; - let tag = match self.hir.find(node) { - Some(hir_map::NodeBlock(_)) | - Some(hir_map::NodeExpr(_)) => "body", - Some(hir_map::NodeItem(it)) => item_scope_tag(&it), - Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it), - Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it), - - // this really should not happen, but it does: - // FIXME(#27942) - Some(_) => { - unknown = format!("unexpected node ({}) for scope {:?}. \ - Please report a bug.", - self.hir.node_to_string(node), scope); - &unknown - } - None => { - unknown = format!("unknown node for scope {:?}. \ - Please report a bug.", scope); - &unknown - } - }; - let (prefix, span) = match *region { - ty::ReEarlyBound(ref br) => { - (format!("the lifetime {} as defined on", br.name), - self.sess.codemap().def_span(self.hir.span(node))) - } - ty::ReFree(ref fr) => { - match fr.bound_region { - ty::BrAnon(idx) => { - (format!("the anonymous lifetime #{} defined on", idx + 1), - self.hir.span(node)) - } - ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(), - self.hir.span(node)), - _ => (format!("the lifetime {} as defined on", fr.bound_region), - self.sess.codemap().def_span(self.hir.span(node))), - } - } - _ => bug!() - }; - let (msg, opt_span) = explain_span(self, tag, span); - (format!("{} {}", prefix, msg), opt_span) - } + ty::ReEarlyBound(_) | ty::ReFree(_) => self.msg_span_from_free_region(region), ty::ReStatic => ("the static lifetime".to_owned(), None), @@ -231,59 +149,168 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // // We shouldn't really be having unification failures with ReVar // and ReLateBound though. - ty::ReSkolemized(..) | - ty::ReVar(_) | - ty::ReLateBound(..) | - ty::ReErased => { + ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { (format!("lifetime {:?}", region), None) } // We shouldn't encounter an error message with ReClosureBound. ty::ReClosureBound(..) => { - bug!( - "encountered unexpected ReClosureBound: {:?}", - region, - ); + bug!("encountered unexpected ReClosureBound: {:?}", region,); } }; + + TyCtxt::emit_msg_span(err, prefix, description, span, suffix); + } + + pub fn note_and_explain_free_region( + self, + err: &mut DiagnosticBuilder, + prefix: &str, + region: ty::Region<'tcx>, + suffix: &str, + ) { + let (description, span) = self.msg_span_from_free_region(region); + + TyCtxt::emit_msg_span(err, prefix, description, span, suffix); + } + + fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option) { + let scope = region.free_region_binding_scope(self); + let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); + let unknown; + let tag = match self.hir.find(node) { + Some(hir_map::NodeBlock(_)) | Some(hir_map::NodeExpr(_)) => "body", + Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it), + Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it), + Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it), + + // this really should not happen, but it does: + // FIXME(#27942) + Some(_) => { + unknown = format!( + "unexpected node ({}) for scope {:?}. \ + Please report a bug.", + self.hir.node_to_string(node), + scope + ); + &unknown + } + None => { + unknown = format!( + "unknown node for scope {:?}. \ + Please report a bug.", + scope + ); + &unknown + } + }; + let (prefix, span) = match *region { + ty::ReEarlyBound(ref br) => ( + format!("the lifetime {} as defined on", br.name), + self.sess.codemap().def_span(self.hir.span(node)), + ), + ty::ReFree(ref fr) => match fr.bound_region { + ty::BrAnon(idx) => ( + format!("the anonymous lifetime #{} defined on", idx + 1), + self.hir.span(node), + ), + ty::BrFresh(_) => ( + "an anonymous lifetime defined on".to_owned(), + self.hir.span(node), + ), + _ => ( + format!("the lifetime {} as defined on", fr.bound_region), + self.sess.codemap().def_span(self.hir.span(node)), + ), + }, + _ => bug!(), + }; + let (msg, opt_span) = self.explain_span(tag, span); + (format!("{} {}", prefix, msg), opt_span) + } + + fn emit_msg_span( + err: &mut DiagnosticBuilder, + prefix: &str, + description: String, + span: Option, + suffix: &str, + ) { let message = format!("{}{}{}", prefix, description, suffix); + if let Some(span) = span { err.span_note(span, &message); } else { err.note(&message); } } + + fn item_scope_tag(item: &hir::Item) -> &'static str { + match item.node { + hir::ItemImpl(..) => "impl", + hir::ItemStruct(..) => "struct", + hir::ItemUnion(..) => "union", + hir::ItemEnum(..) => "enum", + hir::ItemTrait(..) => "trait", + hir::ItemFn(..) => "function body", + _ => "item", + } + } + + fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str { + match item.node { + hir::TraitItemKind::Method(..) => "method body", + hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", + } + } + + fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { + match item.node { + hir::ImplItemKind::Method(..) => "method body", + hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item", + } + } + + fn explain_span(self, heading: &str, span: Span) -> (String, Option) { + let lo = self.sess.codemap().lookup_char_pos_adj(span.lo()); + ( + format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), + Some(span), + ) + } } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - pub fn report_region_errors(&self, - region_scope_tree: ®ion::ScopeTree, - errors: &Vec>, - will_later_be_reported_by_nll: bool) { + pub fn report_region_errors( + &self, + region_scope_tree: ®ion::ScopeTree, + errors: &Vec>, + will_later_be_reported_by_nll: bool, + ) { debug!("report_region_errors(): {} errors to start", errors.len()); - if will_later_be_reported_by_nll && self.tcx.sess.nll() { + if will_later_be_reported_by_nll && self.tcx.nll() { // With `#![feature(nll)]`, we want to present a nice user // experience, so don't even mention the errors from the // AST checker. - if self.tcx.sess.features.borrow().nll { + if self.tcx.features().nll { return; } // But with -Znll, it's nice to have some note for later. for error in errors { match *error { - RegionResolutionError::ConcreteFailure(ref origin, ..) | - RegionResolutionError::GenericBoundFailure(ref origin, ..) => { - self.tcx.sess.span_warn( - origin.span(), - "not reporting region error due to -Znll"); + RegionResolutionError::ConcreteFailure(ref origin, ..) + | RegionResolutionError::GenericBoundFailure(ref origin, ..) => { + self.tcx + .sess + .span_warn(origin.span(), "not reporting region error due to -Znll"); } RegionResolutionError::SubSupConflict(ref rvo, ..) => { - self.tcx.sess.span_warn( - rvo.span(), - "not reporting region error due to -Znll"); + self.tcx + .sess + .span_warn(rvo.span(), "not reporting region error due to -Znll"); } } } @@ -295,7 +322,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // together into a `ProcessedErrors` group: let errors = self.process_errors(errors); - debug!("report_region_errors: {} errors after preprocessing", errors.len()); + debug!( + "report_region_errors: {} errors after preprocessing", + errors.len() + ); for error in errors { debug!("report_region_errors: error = {:?}", error); @@ -310,7 +340,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // the error. If all of these fails, we fall back to a rather // general bit of code that displays the error information RegionResolutionError::ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(region_scope_tree, origin, sub, sup).emit(); + self.report_concrete_failure(region_scope_tree, origin, sub, sup) + .emit(); } RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { @@ -323,17 +354,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ); } - RegionResolutionError::SubSupConflict(var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r) => { - self.report_sub_sup_conflict(region_scope_tree, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r); + RegionResolutionError::SubSupConflict( + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ) => { + self.report_sub_sup_conflict( + region_scope_tree, + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ); } } } @@ -350,8 +385,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // The method also attempts to weed out messages that seem like // duplicates that will be unhelpful to the end-user. But // obviously it never weeds out ALL errors. - fn process_errors(&self, errors: &Vec>) - -> Vec> { + fn process_errors( + &self, + errors: &Vec>, + ) -> Vec> { debug!("process_errors()"); // We want to avoid reporting generic-bound failures if we can @@ -368,15 +405,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { RegionResolutionError::GenericBoundFailure(..) => true, - RegionResolutionError::ConcreteFailure(..) | - RegionResolutionError::SubSupConflict(..) => false, + RegionResolutionError::ConcreteFailure(..) + | RegionResolutionError::SubSupConflict(..) => false, }; - let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { errors.clone() } else { - errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect() + errors + .iter() + .filter(|&e| !is_bound_failure(e)) + .cloned() + .collect() }; // sort the errors by span, for better error message stability. @@ -389,10 +429,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, - err: &mut DiagnosticBuilder, - terr: &TypeError<'tcx>, - sp: Span) { + fn check_and_note_conflicting_crates( + &self, + err: &mut DiagnosticBuilder, + terr: &TypeError<'tcx>, + sp: Span, + ) { let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| { // Only external crates, if either is from a local // module we could have false positives @@ -403,12 +445,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let found_abs_path = self.tcx.absolute_item_path_str(did2); // We compare strings because DefPath can be different // for imported and non-imported crates - if exp_path == found_path - || exp_abs_path == found_abs_path { + if exp_path == found_path || exp_abs_path == found_abs_path { let crate_name = self.tcx.crate_name(did1.krate); - err.span_note(sp, &format!("Perhaps two different versions \ - of crate `{}` are being used?", - crate_name)); + err.span_note( + sp, + &format!( + "Perhaps two different versions \ + of crate `{}` are being used?", + crate_name + ), + ); } } }; @@ -419,24 +465,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (&exp_found.expected.sty, &exp_found.found.sty) { (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { report_path_match(err, exp_adt.did, found_adt.did); - }, - _ => () + } + _ => (), } - }, + } TypeError::Traits(ref exp_found) => { report_path_match(err, exp_found.expected, exp_found.found); - }, - _ => () // FIXME(#22750) handle traits and stuff + } + _ => (), // FIXME(#22750) handle traits and stuff } } - fn note_error_origin(&self, - err: &mut DiagnosticBuilder<'tcx>, - cause: &ObligationCause<'tcx>) - { + fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) { match cause.code { ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source { - hir::MatchSource::IfLetDesugar {..} => { + hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arm with an incompatible type"; if self.tcx.sess.codemap().is_multiline(arm_span) { err.span_note(arm_span, msg); @@ -453,7 +496,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } }, - _ => () + _ => (), } } @@ -470,13 +513,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Bar /// -------- this type is the same as a type argument in the other type, not highlighted /// ``` - fn highlight_outer(&self, - value: &mut DiagnosticStyledString, - other_value: &mut DiagnosticStyledString, - name: String, - sub: &ty::subst::Substs<'tcx>, - pos: usize, - other_ty: &Ty<'tcx>) { + fn highlight_outer( + &self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + name: String, + sub: &ty::subst::Substs<'tcx>, + pos: usize, + other_ty: &Ty<'tcx>, + ) { // `value` and `other_value` hold two incomplete type representation for display. // `name` is the path of both types being compared. `sub` value.push_highlighted(name); @@ -486,14 +531,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } // Output the lifetimes fot the first type - let lifetimes = sub.regions().map(|lifetime| { - let s = format!("{}", lifetime); - if s.is_empty() { - "'_".to_string() - } else { - s - } - }).collect::>().join(", "); + let lifetimes = sub.regions() + .map(|lifetime| { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + }) + .collect::>() + .join(", "); if !lifetimes.is_empty() { if sub.regions().count() < len { value.push_normal(lifetimes + &", "); @@ -543,13 +591,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Bar /// -------- this type is the same as a type argument in the other type, not highlighted /// ``` - fn cmp_type_arg(&self, - mut t1_out: &mut DiagnosticStyledString, - mut t2_out: &mut DiagnosticStyledString, - path: String, - sub: &ty::subst::Substs<'tcx>, - other_path: String, - other_ty: &Ty<'tcx>) -> Option<()> { + fn cmp_type_arg( + &self, + mut t1_out: &mut DiagnosticStyledString, + mut t2_out: &mut DiagnosticStyledString, + path: String, + sub: &ty::subst::Substs<'tcx>, + other_path: String, + other_ty: &Ty<'tcx>, + ) -> Option<()> { for (i, ta) in sub.types().enumerate() { if &ta == other_ty { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); @@ -567,11 +617,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Add a `,` to the type representation only if it is appropriate. - fn push_comma(&self, - value: &mut DiagnosticStyledString, - other_value: &mut DiagnosticStyledString, - len: usize, - pos: usize) { + fn push_comma( + &self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + len: usize, + pos: usize, + ) { if len > 0 && pos != len - 1 { value.push_normal(", "); other_value.push_normal(", "); @@ -580,39 +632,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Compare two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. - fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) - -> (DiagnosticStyledString, DiagnosticStyledString) - { + fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { fn equals<'tcx>(a: &Ty<'tcx>, b: &Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { (a, b) if *a == *b => true, - (&ty::TyInt(_), &ty::TyInfer(ty::InferTy::IntVar(_))) | - (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInt(_)) | - (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInfer(ty::InferTy::IntVar(_))) | - (&ty::TyFloat(_), &ty::TyInfer(ty::InferTy::FloatVar(_))) | - (&ty::TyInfer(ty::InferTy::FloatVar(_)), &ty::TyFloat(_)) | - (&ty::TyInfer(ty::InferTy::FloatVar(_)), - &ty::TyInfer(ty::InferTy::FloatVar(_))) => true, + (&ty::TyInt(_), &ty::TyInfer(ty::InferTy::IntVar(_))) + | (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInt(_)) + | (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInfer(ty::InferTy::IntVar(_))) + | (&ty::TyFloat(_), &ty::TyInfer(ty::InferTy::FloatVar(_))) + | (&ty::TyInfer(ty::InferTy::FloatVar(_)), &ty::TyFloat(_)) + | ( + &ty::TyInfer(ty::InferTy::FloatVar(_)), + &ty::TyInfer(ty::InferTy::FloatVar(_)), + ) => true, _ => false, } } - fn push_ty_ref<'tcx>(r: &ty::Region<'tcx>, - tnm: &ty::TypeAndMut<'tcx>, - s: &mut DiagnosticStyledString) { + fn push_ty_ref<'tcx>( + r: &ty::Region<'tcx>, + tnm: &ty::TypeAndMut<'tcx>, + s: &mut DiagnosticStyledString, + ) { let r = &format!("{}", r); - s.push_highlighted(format!("&{}{}{}", - r, - if r == "" { - "" - } else { - " " - }, - if tnm.mutbl == hir::MutMutable { - "mut " - } else { - "" - })); + s.push_highlighted(format!( + "&{}{}{}", + r, + if r == "" { "" } else { " " }, + if tnm.mutbl == hir::MutMutable { + "mut " + } else { + "" + } + )); s.push_normal(format!("{}", tnm.ty)); } @@ -705,12 +757,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Foo // ------- this type argument is exactly the same as the other type // Bar - if self.cmp_type_arg(&mut values.0, - &mut values.1, - path1.clone(), - sub1, - path2.clone(), - &t2).is_some() { + if self.cmp_type_arg( + &mut values.0, + &mut values.1, + path1.clone(), + sub1, + path2.clone(), + &t2, + ).is_some() + { return values; } // Check for case: @@ -718,19 +773,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Bar // Foo> // ------- this type argument is exactly the same as the other type - if self.cmp_type_arg(&mut values.1, - &mut values.0, - path2, - sub2, - path1, - &t1).is_some() { + if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1) + .is_some() + { return values; } // We couldn't find anything in common, highlight everything. // let x: Bar = y::>(); - (DiagnosticStyledString::highlighted(format!("{}", t1)), - DiagnosticStyledString::highlighted(format!("{}", t2))) + ( + DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2)), + ) } } @@ -759,28 +813,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => { if t1 == t2 { // The two types are the same, elide and don't highlight. - (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) + ( + DiagnosticStyledString::normal("_"), + DiagnosticStyledString::normal("_"), + ) } else { // We couldn't find anything in common, highlight everything. - (DiagnosticStyledString::highlighted(format!("{}", t1)), - DiagnosticStyledString::highlighted(format!("{}", t2))) + ( + DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2)), + ) } } } } - pub fn note_type_err(&self, - diag: &mut DiagnosticBuilder<'tcx>, - cause: &ObligationCause<'tcx>, - secondary_span: Option<(Span, String)>, - mut values: Option>, - terr: &TypeError<'tcx>) - { + pub fn note_type_err( + &self, + diag: &mut DiagnosticBuilder<'tcx>, + cause: &ObligationCause<'tcx>, + secondary_span: Option<(Span, String)>, + mut values: Option>, + terr: &TypeError<'tcx>, + ) { // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. match terr { - TypeError::CyclicTy(_) => { values = None; } - _ => { } + TypeError::CyclicTy(_) => { + values = None; + } + _ => {} } let (expected_found, exp_found, is_simple_error) = match values { @@ -788,8 +850,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(values) => { let (is_simple_error, exp_found) = match values { ValuePairs::Types(exp_found) => { - let is_simple_err = exp_found.expected.is_primitive() - && exp_found.found.is_primitive(); + let is_simple_err = + exp_found.expected.is_primitive() && exp_found.found.is_primitive(); (is_simple_err, Some(exp_found)) } @@ -800,7 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { None => { // Derived error. Cancel the emitter. self.tcx.sess.diagnostic().cancel(diag); - return + return; } }; (vals, exp_found, is_simple_error) @@ -818,9 +880,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (terr, is_simple_error, expected == found) { (&TypeError::Sorts(ref values), false, true) => { diag.note_expected_found_extra( - &"type", expected, found, + &"type", + expected, + found, &format!(" ({})", values.expected.sort_string(self.tcx)), - &format!(" ({})", values.found.sort_string(self.tcx))); + &format!(" ({})", values.found.sort_string(self.tcx)), + ); } (_, false, _) => { if let Some(exp_found) = exp_found { @@ -828,12 +893,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TypeVariants::TyFnDef(def, _) => { (Some(def), Some(self.tcx.fn_sig(def).output())) } - _ => (None, None) + _ => (None, None), }; let exp_is_struct = match exp_found.expected.sty { TypeVariants::TyAdt(def, _) => def.is_struct(), - _ => false + _ => false, }; if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { @@ -861,14 +926,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.note_error_origin(diag, &cause); } - pub fn report_and_explain_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> - { - debug!("report_and_explain_type_error(trace={:?}, terr={:?})", - trace, - terr); + pub fn report_and_explain_type_error( + &self, + trace: TypeTrace<'tcx>, + terr: &TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx> { + debug!( + "report_and_explain_type_error(trace={:?}, terr={:?})", + trace, terr + ); let span = trace.cause.span(&self.tcx); let failure_code = trace.cause.as_failure_code(terr); @@ -890,9 +956,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag } - fn values_str(&self, values: &ValuePairs<'tcx>) - -> Option<(DiagnosticStyledString, DiagnosticStyledString)> - { + fn values_str( + &self, + values: &ValuePairs<'tcx>, + ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { match *values { infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), @@ -900,9 +967,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn expected_found_str_ty(&self, - exp_found: &ty::error::ExpectedFound>) - -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { + fn expected_found_str_ty( + &self, + exp_found: &ty::error::ExpectedFound>, + ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -914,25 +982,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, - exp_found: &ty::error::ExpectedFound) - -> Option<(DiagnosticStyledString, DiagnosticStyledString)> - { + exp_found: &ty::error::ExpectedFound, + ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; } - Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), - DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) + Some(( + DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), + DiagnosticStyledString::highlighted(format!("{}", exp_found.found)), + )) } - pub fn report_generic_bound_failure(&self, - region_scope_tree: ®ion::ScopeTree, - span: Span, - origin: Option>, - bound_kind: GenericKind<'tcx>, - sub: Region<'tcx>) - { + pub fn report_generic_bound_failure( + &self, + region_scope_tree: ®ion::ScopeTree, + span: Span, + origin: Option>, + bound_kind: GenericKind<'tcx>, + sub: Region<'tcx>, + ) { // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. let type_param_span = match (self.in_progress_tables, bound_kind) { @@ -958,8 +1028,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // `sp` only covers `T`, change it so that it covers // `T:` when appropriate let sp = if has_lifetimes { - sp.to(self.tcx.sess.codemap().next_point( - self.tcx.sess.codemap().next_point(sp))) + sp.to(self.tcx + .sess + .codemap() + .next_point(self.tcx.sess.codemap().next_point(sp))) } else { sp }; @@ -974,37 +1046,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let labeled_user_string = match bound_kind { - GenericKind::Param(ref p) => - format!("the parameter type `{}`", p), - GenericKind::Projection(ref p) => - format!("the associated type `{}`", p), + GenericKind::Param(ref p) => format!("the parameter type `{}`", p), + GenericKind::Projection(ref p) => format!("the associated type `{}`", p), }; if let Some(SubregionOrigin::CompareImplMethodObligation { - span, item_name, impl_item_def_id, trait_item_def_id, - }) = origin { - self.report_extra_impl_obligation(span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", bound_kind, sub)) - .emit(); + span, + item_name, + impl_item_def_id, + trait_item_def_id, + }) = origin + { + self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", bound_kind, sub), + ).emit(); return; } - fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>, - type_param_span: Option<(Span, bool)>, - bound_kind: GenericKind<'tcx>, - sub: S) { - let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub); + fn binding_suggestion<'tcx, S: fmt::Display>( + err: &mut DiagnosticBuilder<'tcx>, + type_param_span: Option<(Span, bool)>, + bound_kind: GenericKind<'tcx>, + sub: S, + ) { + let consider = &format!( + "consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, sub + ); if let Some((sp, has_lifetimes)) = type_param_span { - let tail = if has_lifetimes { - " + " - } else { - "" - }; + let tail = if has_lifetimes { " + " } else { "" }; let suggestion = format!("{}: {}{}", bound_kind, sub, tail); err.span_suggestion_short(sp, consider, suggestion); } else { @@ -1013,44 +1087,56 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let mut err = match *sub { - ty::ReEarlyBound(_) | - ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { + ty::ReEarlyBound(_) + | ty::ReFree(ty::FreeRegion { + bound_region: ty::BrNamed(..), + .. + }) => { // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!(self.tcx.sess, - span, - E0309, - "{} may not live long enough", - labeled_user_string); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0309, + "{} may not live long enough", + labeled_user_string + ); binding_suggestion(&mut err, type_param_span, bound_kind, sub); err } ty::ReStatic => { // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!(self.tcx.sess, - span, - E0310, - "{} may not live long enough", - labeled_user_string); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0310, + "{} may not live long enough", + labeled_user_string + ); binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); err } _ => { // If not, be less specific. - let mut err = struct_span_err!(self.tcx.sess, - span, - E0311, - "{} may not live long enough", - labeled_user_string); - err.help(&format!("consider adding an explicit lifetime bound for `{}`", - bound_kind)); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0311, + "{} may not live long enough", + labeled_user_string + ); + err.help(&format!( + "consider adding an explicit lifetime bound for `{}`", + bound_kind + )); self.tcx.note_and_explain_region( region_scope_tree, &mut err, &format!("{} must be valid for ", labeled_user_string), sub, - "..."); + "...", + ); err } }; @@ -1061,26 +1147,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.emit(); } - fn report_sub_sup_conflict(&self, - region_scope_tree: ®ion::ScopeTree, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin<'tcx>, - sub_region: Region<'tcx>, - sup_origin: SubregionOrigin<'tcx>, - sup_region: Region<'tcx>) { - + fn report_sub_sup_conflict( + &self, + region_scope_tree: ®ion::ScopeTree, + var_origin: RegionVariableOrigin, + sub_origin: SubregionOrigin<'tcx>, + sub_region: Region<'tcx>, + sup_origin: SubregionOrigin<'tcx>, + sup_region: Region<'tcx>, + ) { let mut err = self.report_inference_failure(var_origin); - self.tcx.note_and_explain_region(region_scope_tree, &mut err, + self.tcx.note_and_explain_region( + region_scope_tree, + &mut err, "first, the lifetime cannot outlive ", sup_region, - "..."); + "...", + ); match (&sup_origin, &sub_origin) { (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => { - if let (Some((sup_expected, sup_found)), - Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values), - self.values_str(&sub_trace.values)) { + if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = ( + self.values_str(&sup_trace.values), + self.values_str(&sub_trace.values), + ) { if sub_expected == sup_expected && sub_found == sup_found { self.tcx.note_and_explain_region( region_scope_tree, @@ -1089,10 +1180,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sub_region, "...", ); - err.note(&format!("...so that the {}:\nexpected {}\n found {}", - sup_trace.cause.as_requirement_str(), - sup_expected.content(), - sup_found.content())); + err.note(&format!( + "...so that the {}:\nexpected {}\n found {}", + sup_trace.cause.as_requirement_str(), + sup_expected.content(), + sup_found.content() + )); err.emit(); return; } @@ -1103,10 +1196,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.note_region_origin(&mut err, &sup_origin); - self.tcx.note_and_explain_region(region_scope_tree, &mut err, + self.tcx.note_and_explain_region( + region_scope_tree, + &mut err, "but, the lifetime must be valid for ", sub_region, - "..."); + "...", + ); self.note_region_origin(&mut err, &sub_origin); err.emit(); @@ -1114,9 +1210,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn report_inference_failure(&self, - var_origin: RegionVariableOrigin) - -> DiagnosticBuilder<'tcx> { + fn report_inference_failure( + &self, + var_origin: RegionVariableOrigin, + ) -> DiagnosticBuilder<'tcx> { let br_string = |br: ty::BoundRegion| { let mut s = br.to_string(); if !s.is_empty() { @@ -1131,23 +1228,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { infer::Autoref(_) => " for autoref".to_string(), infer::Coercion(_) => " for automatic coercion".to_string(), infer::LateBoundRegion(_, br, infer::FnCall) => { - format!(" for lifetime parameter {}in function call", - br_string(br)) + format!(" for lifetime parameter {}in function call", br_string(br)) } infer::LateBoundRegion(_, br, infer::HigherRankedType) => { format!(" for lifetime parameter {}in generic type", br_string(br)) } - infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => { - format!(" for lifetime parameter {}in trait containing associated type `{}`", - br_string(br), self.tcx.associated_item(def_id).name) - } - infer::EarlyBoundRegion(_, name) => { - format!(" for lifetime parameter `{}`", - name) - } + infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( + " for lifetime parameter {}in trait containing associated type `{}`", + br_string(br), + self.tcx.associated_item(def_id).name + ), + infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), infer::BoundRegionInCoherence(name) => { - format!(" for lifetime parameter `{}` in coherence check", - name) + 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); @@ -1157,10 +1250,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { infer::NLL(..) => bug!("NLL variable found in lexical phase"), }; - struct_span_err!(self.tcx.sess, var_origin.span(), E0495, - "cannot infer an appropriate lifetime{} \ - due to conflicting requirements", - var_description) + struct_span_err!( + self.tcx.sess, + var_origin.span(), + E0495, + "cannot infer an appropriate lifetime{} \ + due to conflicting requirements", + var_description + ) } } @@ -1178,7 +1275,7 @@ impl<'tcx> ObligationCause<'tcx> { match self.code { CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), MatchExpressionArm { source, .. } => Error0308(match source { - hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", + hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types", _ => "match arms have incompatible types", }), IfExpression => Error0308("if and else have incompatible types"), @@ -1193,11 +1290,11 @@ impl<'tcx> ObligationCause<'tcx> { // say, also take a look at the error code, maybe we can // tailor to that. _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => - Error0644("closure/generator type that references itself"), - _ => - Error0308("mismatched types"), - } + TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { + Error0644("closure/generator type that references itself") + } + _ => Error0308("mismatched types"), + }, } } @@ -1207,7 +1304,7 @@ impl<'tcx> ObligationCause<'tcx> { CompareImplMethodObligation { .. } => "method type is compatible with trait", ExprAssignable => "expression is assignable", MatchExpressionArm { source, .. } => match source { - hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types", + hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", _ => "match arms have compatible types", }, IfExpression => "if and else have compatible types", diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index bdb5ad525a75..5dbe2ef516cf 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -32,7 +32,6 @@ use ich; use ty::{self, TyCtxt}; use session::{Session, CrateDisambiguator}; use session::search_paths::PathKind; -use util::nodemap::NodeSet; use std::any::Any; use std::collections::BTreeMap; @@ -258,8 +257,7 @@ pub trait CrateStore { // utility functions fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - link_meta: &LinkMeta, - reachable: &NodeSet) + link_meta: &LinkMeta) -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; } @@ -342,8 +340,7 @@ impl CrateStore for DummyCrateStore { fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option { None } fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - link_meta: &LinkMeta, - reachable: &NodeSet) + link_meta: &LinkMeta) -> EncodedMetadata { bug!("encode_metadata") } diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index d650dbe88b5c..b1418792490f 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -8,12 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::{DefId, LOCAL_CRATE}; +use std::cmp; +use ty; + /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any /// kind of crate, including cdylibs which export very few things. /// `Rust` will only be exported if the crate produced is a Rust /// dylib. -#[derive(Eq, PartialEq, Debug, Copy, Clone)] +#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)] pub enum SymbolExportLevel { C, Rust, @@ -34,3 +38,58 @@ impl SymbolExportLevel { } } } + +#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum ExportedSymbol { + NonGeneric(DefId), + NoDefId(ty::SymbolName), +} + +impl ExportedSymbol { + pub fn symbol_name(&self, tcx: ty::TyCtxt) -> ty::SymbolName { + match *self { + ExportedSymbol::NonGeneric(def_id) => { + tcx.symbol_name(ty::Instance::mono(tcx, def_id)) + } + ExportedSymbol::NoDefId(symbol_name) => { + symbol_name + } + } + } + + pub fn compare_stable(&self, tcx: ty::TyCtxt, other: &ExportedSymbol) -> cmp::Ordering { + match *self { + ExportedSymbol::NonGeneric(self_def_id) => { + match *other { + ExportedSymbol::NonGeneric(other_def_id) => { + tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id)) + } + ExportedSymbol::NoDefId(_) => { + cmp::Ordering::Less + } + } + } + ExportedSymbol::NoDefId(self_symbol_name) => { + match *other { + ExportedSymbol::NonGeneric(_) => { + cmp::Ordering::Greater + } + ExportedSymbol::NoDefId(ref other_symbol_name) => { + self_symbol_name.cmp(other_symbol_name) + } + } + } + } + } +} + +impl_stable_hash_for!(enum self::ExportedSymbol { + NonGeneric(def_id), + NoDefId(symbol_name) +}); + +pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String { + format!("rust_metadata_{}_{}", + tcx.original_crate_name(LOCAL_CRATE), + tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()) +} diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 749685182a8f..5658b5b68329 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -206,11 +206,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Step 2: Mark all symbols that the symbols on the worklist touch. fn propagate(&mut self) { let mut scanned = FxHashSet(); - loop { - let search_item = match self.worklist.pop() { - Some(item) => item, - None => break, - }; + while let Some(search_item) = self.worklist.pop() { if !scanned.insert(search_item) { continue } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e80ea16f565a..16c33d6bd837 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { item_sp: Span, kind: AnnotationKind, visit_children: F) where F: FnOnce(&mut Self) { - if self.tcx.sess.features.borrow().staged_api { + if self.tcx.features().staged_api { // This crate explicitly wants staged API. debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { @@ -398,7 +398,7 @@ impl<'a, 'tcx> Index<'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> { let is_staged_api = tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || - tcx.sess.features.borrow().staged_api; + tcx.features().staged_api; let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); let mut index = Index { @@ -408,7 +408,7 @@ impl<'a, 'tcx> Index<'tcx> { active_features: FxHashSet(), }; - let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; + let ref active_lib_features = tcx.features().declared_lib_features; // Put the active features into a map for quick lookup index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); @@ -677,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => { + hir::ItemUnion(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); @@ -721,8 +721,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let sess = &tcx.sess; - let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability().staged_api[&LOCAL_CRATE] { @@ -736,12 +734,12 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { krate.visit_all_item_likes(&mut missing.as_deep_visitor()); } - let ref declared_lib_features = sess.features.borrow().declared_lib_features; + let ref declared_lib_features = tcx.features().declared_lib_features; let mut remaining_lib_features: FxHashMap = declared_lib_features.clone().into_iter().collect(); remaining_lib_features.remove(&Symbol::intern("proc_macro")); - for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features { + for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features { let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str()) .expect("unexpectedly couldn't find version feature was stabilized"); tcx.lint_node(lint::builtin::STABLE_FEATURES, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bd87a8f918ab..5e9eeb973007 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch}; +use session::config::{DebugInfoLevel, OutputType, Epoch}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -93,7 +93,8 @@ pub struct Session { /// multiple crates with the same name to coexist. See the /// trans::back::symbol_names module for more information. pub crate_disambiguator: RefCell>, - pub features: RefCell, + + features: RefCell>, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. @@ -194,6 +195,7 @@ impl Session { None => bug!("accessing disambiguator before initialization"), } } + pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -456,16 +458,22 @@ impl Session { self.opts.debugging_opts.print_llvm_passes } - /// If true, we should use NLL-style region checking instead of - /// lexical style. - pub fn nll(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.nll + /// Get the features enabled for the current compilation session. + /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents + /// dependency tracking. Use tcx.features() instead. + #[inline] + pub fn features_untracked(&self) -> cell::Ref { + let features = self.features.borrow(); + + if features.is_none() { + bug!("Access to Session::features before it is initialized"); + } + + cell::Ref::map(features, |r| r.as_ref().unwrap()) } - /// If true, we should use the MIR-based borrowck (we may *also* use - /// the AST-based borrowck). - pub fn use_mir(&self) -> bool { - self.borrowck_mode().use_mir() + pub fn init_features(&self, features: feature_gate::Features) { + *(self.features.borrow_mut()) = Some(features); } /// If true, we should gather causal information during NLL @@ -475,42 +483,6 @@ impl Session { self.opts.debugging_opts.nll_dump_cause } - /// If true, we should enable two-phase borrows checks. This is - /// done with either `-Ztwo-phase-borrows` or with - /// `#![feature(nll)]`. - pub fn two_phase_borrows(&self) -> bool { - self.features.borrow().nll || self.opts.debugging_opts.two_phase_borrows - } - - /// What mode(s) of borrowck should we run? AST? MIR? both? - /// (Also considers the `#![feature(nll)]` setting.) - pub fn borrowck_mode(&self) -> BorrowckMode { - match self.opts.borrowck_mode { - mode @ BorrowckMode::Mir | - mode @ BorrowckMode::Compare => mode, - - mode @ BorrowckMode::Ast => { - if self.nll() { - BorrowckMode::Mir - } else { - mode - } - } - - } - } - - /// Should we emit EndRegion MIR statements? These are consumed by - /// MIR borrowck, but not when NLL is used. They are also consumed - /// by the validation stuff. - pub fn emit_end_regions(&self) -> bool { - // FIXME(#46875) -- we should not emit end regions when NLL is enabled, - // but for now we can't stop doing so because it causes false positives - self.opts.debugging_opts.emit_end_regions || - self.opts.debugging_opts.mir_emit_validate > 0 || - self.use_mir() - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -1029,7 +1001,7 @@ pub fn build_session_(sopts: config::Options, crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FxHashMap()), crate_disambiguator: RefCell::new(None), - features: RefCell::new(feature_gate::Features::new()), + features: RefCell::new(None), recursion_limit: Cell::new(64), type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 43940d7cea3e..d11565618a68 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -164,7 +164,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.sess.features.borrow().specialization && + if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d04c47710173..47a3580e8676 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::OutputFilenames; +use session::config::{BorrowckMode, OutputFilenames}; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -46,7 +46,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout}; use ty::maps; use ty::steal::Steal; use ty::BindingMode; -use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap}; +use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, @@ -71,6 +71,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; @@ -1255,6 +1256,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.all_crate_nums(LOCAL_CRATE) } + pub fn features(self) -> Lrc { + self.features_query(LOCAL_CRATE) + } + pub fn def_key(self, id: DefId) -> hir_map::DefKey { if id.is_local() { self.hir.def_key(id) @@ -1362,13 +1367,60 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) } + /// If true, we should use NLL-style region checking instead of + /// lexical style. + pub fn nll(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.nll + } + + /// If true, we should use the MIR-based borrowck (we may *also* use + /// the AST-based borrowck). + pub fn use_mir(self) -> bool { + self.borrowck_mode().use_mir() + } + + /// If true, we should enable two-phase borrows checks. This is + /// done with either `-Ztwo-phase-borrows` or with + /// `#![feature(nll)]`. + pub fn two_phase_borrows(self) -> bool { + self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows + } + + /// What mode(s) of borrowck should we run? AST? MIR? both? + /// (Also considers the `#![feature(nll)]` setting.) + pub fn borrowck_mode(&self) -> BorrowckMode { + match self.sess.opts.borrowck_mode { + mode @ BorrowckMode::Mir | + mode @ BorrowckMode::Compare => mode, + + mode @ BorrowckMode::Ast => { + if self.nll() { + BorrowckMode::Mir + } else { + mode + } + } + + } + } + + /// Should we emit EndRegion MIR statements? These are consumed by + /// MIR borrowck, but not when NLL is used. They are also consumed + /// by the validation stuff. + pub fn emit_end_regions(self) -> bool { + // FIXME(#46875) -- we should not emit end regions when NLL is enabled, + // but for now we can't stop doing so because it causes false positives + self.sess.opts.debugging_opts.emit_end_regions || + self.sess.opts.debugging_opts.mir_emit_validate > 0 || + self.use_mir() + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { - pub fn encode_metadata(self, link_meta: &LinkMeta, reachable: &NodeSet) + pub fn encode_metadata(self, link_meta: &LinkMeta) -> EncodedMetadata { - self.cstore.encode_metadata(self, link_meta, reachable) + self.cstore.encode_metadata(self, link_meta) } } @@ -2020,7 +2072,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.sess.features.borrow().never_type { + if self.features().never_type { self.types.never } else { self.intern_tup(&[], true) @@ -2395,13 +2447,25 @@ pub fn provide(providers: &mut ty::maps::Providers) { }; providers.has_copy_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().copy_closures + tcx.features().copy_closures }; providers.has_clone_closures = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.sess.features.borrow().clone_closures + tcx.features().clone_closures }; providers.fully_normalize_monormophic_ty = |tcx, ty| { tcx.fully_normalize_associated_types_in(&ty) }; + providers.features_query = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Lrc::new(tcx.sess.features_untracked().clone()) + }; + providers.is_panic_runtime = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + attr::contains_name(tcx.hir.krate_attrs(), "panic_runtime") + }; + providers.is_compiler_builtins = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + attr::contains_name(tcx.hir.krate_attrs(), "compiler_builtins") + }; } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index eb07876b05f2..cfc552bdc85c 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -212,9 +212,9 @@ impl<'tcx> QueryDescription<'tcx> for queries::item_attrs<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::is_exported_symbol<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::is_reachable_non_generic<'tcx> { fn describe(_: TyCtxt, _: DefId) -> String { - bug!("is_exported_symbol") + bug!("is_reachable_non_generic") } } @@ -383,7 +383,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_sanitizer_runtime<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::exported_symbol_ids<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("looking up the exported symbols of a crate") } @@ -593,6 +593,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'t } } +impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("looking up enabled feature gates") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 6edb1d9be35d..2ef97b2673d6 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -26,7 +26,7 @@ use middle::region; use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; -use middle::exported_symbols::SymbolExportLevel; +use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; use mir::mono::{CodegenUnit, Stats}; use mir; use session::{CompileResult, CrateDisambiguator}; @@ -52,6 +52,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; +use syntax::feature_gate; use syntax::symbol::Symbol; #[macro_use] @@ -237,7 +238,6 @@ define_maps! { <'tcx> [] fn fn_arg_names: FnArgNames(DefId) -> Vec, [] fn impl_parent: ImplParent(DefId) -> Option, [] fn trait_of_item: TraitOfItem(DefId) -> Option, - [] fn is_exported_symbol: IsExportedSymbol(DefId) -> bool, [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies, [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc, @@ -289,7 +289,23 @@ define_maps! { <'tcx> [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc, [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Lrc, + + // The DefIds of all non-generic functions and statics in the given crate + // that can be reached from outside the crate. + // + // We expect this items to be available for being linked to. + // + // This query can also be called for LOCAL_CRATE. In this case it will + // compute which items will be reachable to other crates, taking into account + // the kind of crate that is currently compiled. Crates with only a + // C interface have fewer reachable things. + // + // Does not include external symbols that don't have a corresponding DefId, + // like the compiler-generated `main` function and so on. + [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc, + [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + + [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, @@ -342,7 +358,7 @@ define_maps! { <'tcx> [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc, SymbolExportLevel)>>, + -> Arc>, [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc, Arc>>>), @@ -374,12 +390,19 @@ define_maps! { <'tcx> // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) -> usize, + + [] fn features_query: features_node(CrateNum) -> Lrc, } ////////////////////////////////////////////////////////////////////// // These functions are little shims used to find the dep-node for a // given query when there is not a *direct* mapping: + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { DepConstructor::EraseRegionsTy { ty } } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index b654b6bc42a1..13f286d6a268 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -851,7 +851,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); } DepKind::ImplParent => { force!(impl_parent, def_id!()); } DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } - DepKind::IsExportedSymbol => { force!(is_exported_symbol, def_id!()); } + DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } @@ -868,7 +868,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); } DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); } DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); } - DepKind::ExportedSymbolIds => { force!(exported_symbol_ids, krate!()); } + DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } DepKind::NativeLibraries => { force!(native_libraries, krate!()); } DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); } DepKind::DeriveRegistrarFn => { force!(derive_registrar_fn, krate!()); } @@ -936,6 +936,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } + DepKind::Features => { force!(features_query, LOCAL_CRATE); } } true diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9ba33a57c205..a7c55880e2e1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2335,7 +2335,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { - if !self.sess.features.borrow().overlapping_marker_traits { + if !self.features().overlapping_marker_traits { return false; } let trait1_is_empty = self.impl_trait_ref(def_id1) @@ -2806,7 +2806,7 @@ impl<'tcx> DtorckConstraint<'tcx> { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub struct SymbolName { // FIXME: we don't rely on interning or equality here - better have // this be a `&'tcx str`. @@ -2817,6 +2817,14 @@ impl_stable_hash_for!(struct self::SymbolName { name }); +impl SymbolName { + pub fn new(name: &str) -> SymbolName { + SymbolName { + name: Symbol::intern(name).as_str() + } + } +} + impl Deref for SymbolName { type Target = str; @@ -2828,3 +2836,9 @@ impl fmt::Display for SymbolName { fmt::Display::fmt(&self.name, fmt) } } + +impl fmt::Debug for SymbolName { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, fmt) + } +} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4fe6ee45295a..bb198adea4a6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -276,7 +276,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.tcx.sess.borrowck_mode()) { + if !o.should_emit_errors(self.tcx.borrowck_mode()) { self.tcx.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 54e3418d4f01..8e3b99f2dbfe 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -227,7 +227,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.sess.features.borrow().never_type { + if self.tcx.features().never_type { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index ae53ed0e1140..6f7143c185cb 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().never_type { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 8e4ec93c14ba..2a571fa82643 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -398,7 +398,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }).collect::, _>>()?)))) } hir::ExprIndex(ref arr, ref idx) => { - if !tcx.sess.features.borrow().const_indexing { + if !tcx.features().const_indexing { signal!(e, IndexOpFeatureGated); } let arr = cx.eval(arr)?; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 02cae52166ac..42a17d33fa6f 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -415,13 +415,7 @@ impl ObligationForest { } } - loop { - // non-standard `while let` to bypass #6393 - let i = match error_stack.pop() { - Some(i) => i, - None => break - }; - + while let Some(i) = error_stack.pop() { let node = &self.nodes[i]; match node.state.get() { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 15afea192138..571cc46bc641 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -650,7 +650,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test); // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; + sess.init_features(features); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -699,7 +699,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); time(time_passes, "plugin registration", || { - if sess.features.borrow().rustc_diagnostic_macros { + if sess.features_untracked().rustc_diagnostic_macros { registry.register_macro("__diagnostic_used", diagnostics::plugin::expand_diagnostic_used); registry.register_macro("__register_diagnostic", @@ -749,7 +749,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, crate_loader, &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; - syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -780,7 +780,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, .filter(|p| env::join_paths(iter::once(p)).is_ok())) .unwrap()); } - let features = sess.features.borrow(); + let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), recursion_limit: sess.recursion_limit.get(), @@ -819,7 +819,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.opts.test, krate, sess.diagnostic(), - &sess.features.borrow()) + &sess.features_untracked()) }); // If we're actually rustdoc then there's no need to actually compile @@ -886,7 +886,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, sess.track_errors(|| { syntax::feature_gate::check_crate(&krate, &sess.parse_sess, - &sess.features.borrow(), + &sess.features_untracked(), &attributes, sess.opts.unstable_features); }) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 5976b80d90f8..17a6176b79e9 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -69,7 +69,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c3e283535ec8..e114606a6311 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -219,7 +219,7 @@ impl Assertion { pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // can't add `#[rustc_dirty]` etc without opting in to this feature - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 66f34a72edf2..62ac898337ca 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1356,7 +1356,7 @@ impl UnreachablePub { // visibility is token at start of declaration (can be macro // variable rather than literal `pub`) let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' '); - let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier { + let replacement = if cx.tcx.features().crate_visibility_modifier { "crate" } else { "pub(crate)" diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index ef9b3d38c637..1c4bd0ff4c2e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -150,11 +150,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // Detect literal value out of range [min, max] inclusive // avoiding use of -min to prevent overflow/panic - if (negative && v > max + 1) || - (!negative && v > max) { - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t)); + if (negative && v > max + 1) || (!negative && v > max) { + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + ty::TyInt(t), + repr_str, + v, + negative, + ); + return; + } + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for {:?}", t), + ); return; } } @@ -182,7 +194,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { let mut err = cx.struct_span_lint( OVERFLOWING_LITERALS, parent_expr.span, - "only u8 can be casted into char"); + "only u8 can be cast into char"); err.span_suggestion(parent_expr.span, &"use a char literal instead", format!("'\\u{{{:X}}}'", lit_val)); @@ -191,9 +203,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } } - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for {:?}", t)); + if let Some(repr_str) = get_bin_hex_repr(cx, lit) { + report_bin_hex_error( + cx, + e, + ty::TyUint(t), + repr_str, + lit_val, + false, + ); + return; + } + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for {:?}", t), + ); } } ty::TyFloat(t) => { @@ -338,6 +363,120 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { _ => false, } } + + fn get_bin_hex_repr(cx: &LateContext, lit: &ast::Lit) -> Option { + let src = cx.sess().codemap().span_to_snippet(lit.span).ok()?; + let firstch = src.chars().next()?; + + if firstch == '0' { + match src.chars().nth(1) { + Some('x') | Some('b') => return Some(src), + _ => return None, + } + } + + None + } + + // This function finds the next fitting type and generates a suggestion string. + // It searches for fitting types in the following way (`X < Y`): + // - `iX`: if literal fits in `uX` => `uX`, else => `iY` + // - `-iX` => `iY` + // - `uX` => `uY` + // + // No suggestion for: `isize`, `usize`. + fn get_type_suggestion<'a>( + t: &ty::TypeVariants, + val: u128, + negative: bool, + ) -> Option { + use syntax::ast::IntTy::*; + use syntax::ast::UintTy::*; + macro_rules! find_fit { + ($ty:expr, $val:expr, $negative:expr, + $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { + { + let _neg = if negative { 1 } else { 0 }; + match $ty { + $($type => { + $(if !negative && val <= uint_ty_range($utypes).1 { + return Some(format!("{:?}", $utypes)) + })* + $(if val <= int_ty_range($itypes).1 as u128 + _neg { + return Some(format!("{:?}", $itypes)) + })* + None + },)* + _ => None + } + } + } + } + match t { + &ty::TyInt(i) => find_fit!(i, val, negative, + I8 => [U8] => [I16, I32, I64, I128], + I16 => [U16] => [I32, I64, I128], + I32 => [U32] => [I64, I128], + I64 => [U64] => [I128], + I128 => [U128] => []), + &ty::TyUint(u) => find_fit!(u, val, negative, + U8 => [U8, U16, U32, U64, U128] => [], + U16 => [U16, U32, U64, U128] => [], + U32 => [U32, U64, U128] => [], + U64 => [U64, U128] => [], + U128 => [U128] => []), + _ => None, + } + } + + fn report_bin_hex_error( + cx: &LateContext, + expr: &hir::Expr, + ty: ty::TypeVariants, + repr_str: String, + val: u128, + negative: bool, + ) { + let (t, actually) = match ty { + ty::TyInt(t) => { + let bits = int_ty_bits(t, cx.sess().target.isize_ty); + let actually = (val << (128 - bits)) as i128 >> (128 - bits); + (format!("{:?}", t), actually.to_string()) + } + ty::TyUint(t) => { + let bits = uint_ty_bits(t, cx.sess().target.usize_ty); + let actually = (val << (128 - bits)) >> (128 - bits); + (format!("{:?}", t), actually.to_string()) + } + _ => bug!(), + }; + let mut err = cx.struct_span_lint( + OVERFLOWING_LITERALS, + expr.span, + &format!("literal out of range for {}", t), + ); + err.note(&format!( + "the literal `{}` (decimal `{}`) does not fit into \ + an `{}` and will become `{}{}`", + repr_str, val, t, actually, t + )); + if let Some(sugg_ty) = + get_type_suggestion(&cx.tables.node_id_to_type(expr.hir_id).sty, val, negative) + { + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + let (sans_suffix, _) = repr_str.split_at(pos); + err.span_suggestion( + expr.span, + &format!("consider using `{}` instead", sugg_ty), + format!("{}{}", sans_suffix, sugg_ty), + ); + } else { + err.help(&format!("consider using `{}` instead", sugg_ty)); + } + } + + err.emit(); + } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 439533fae49d..6ab3172c4fef 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.sess.features.borrow().fn_must_use { + if cx.tcx.features().fn_must_use { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { match callee.node { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 876e7e8dc31a..789ecd0f6136 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -225,9 +225,6 @@ impl<'a> CrateLoader<'a> { crate_root.def_path_table.decode((&metadata, self.sess)) }); - let exported_symbols = crate_root.exported_symbols - .decode((&metadata, self.sess)) - .collect(); let trait_impls = crate_root .impls .decode((&metadata, self.sess)) @@ -238,7 +235,6 @@ impl<'a> CrateLoader<'a> { name, extern_crate: Cell::new(None), def_path_table: Lrc::new(def_path_table), - exported_symbols, trait_impls, proc_macros: crate_root.macro_derive_registrar.map(|_| { self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8b59eec01905..2e95c23b4aed 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -78,8 +78,6 @@ pub struct CrateMetadata { /// compilation support. pub def_path_table: Lrc, - pub exported_symbols: FxHashSet, - pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq>, pub dep_kind: Cell, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7b8194d9eab2..0b50f5c44962 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -18,6 +18,7 @@ use rustc::ty::maps::QueryConfig; use rustc::middle::cstore::{CrateStore, DepKind, MetadataLoader, LinkMeta, LoadedMacro, EncodedMetadata, NativeLibraryKind}; +use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; use rustc::hir::def; use rustc::session::{CrateDisambiguator, Session}; @@ -27,10 +28,11 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::definitions::DefPathTable; -use rustc::util::nodemap::{NodeSet, DefIdMap}; +use rustc::util::nodemap::DefIdMap; use std::any::Any; use rustc_data_structures::sync::Lrc; +use std::sync::Arc; use syntax::ast; use syntax::attr; @@ -160,9 +162,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } - is_exported_symbol => { - cdata.exported_symbols.contains(&def_id.index) - } item_body_nested_bodies => { cdata.item_body_nested_bodies(def_id.index) } const_is_rvalue_promotable_to_static => { cdata.const_is_rvalue_promotable_to_static(def_id.index) @@ -179,7 +178,21 @@ provide! { <'tcx> tcx, def_id, other, cdata, extern_crate => { Lrc::new(cdata.extern_crate.get()) } is_no_builtins => { cdata.is_no_builtins(tcx.sess) } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } - exported_symbol_ids => { Lrc::new(cdata.get_exported_symbols()) } + reachable_non_generics => { + let reachable_non_generics = tcx + .exported_symbols(cdata.cnum) + .iter() + .filter_map(|&(exported_symbol, _)| { + if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { + return Some(def_id) + } else { + None + } + }) + .collect(); + + Lrc::new(reachable_non_generics) + } native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) } plugin_registrar_fn => { cdata.root.plugin_registrar_fn.map(|index| { @@ -238,6 +251,19 @@ provide! { <'tcx> tcx, def_id, other, cdata, has_copy_closures => { cdata.has_copy_closures(tcx.sess) } has_clone_closures => { cdata.has_clone_closures(tcx.sess) } + + exported_symbols => { + let cnum = cdata.cnum; + assert!(cnum != LOCAL_CRATE); + + // If this crate is a custom derive crate, then we're not even going to + // link those in so we skip those crates. + if cdata.root.macro_derive_registrar.is_some() { + return Arc::new(Vec::new()) + } + + Arc::new(cdata.exported_symbols()) + } } pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { @@ -520,11 +546,10 @@ impl CrateStore for cstore::CStore { fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - link_meta: &LinkMeta, - reachable: &NodeSet) + link_meta: &LinkMeta) -> EncodedMetadata { - encoder::encode_metadata(tcx, link_meta, reachable) + encoder::encode_metadata(tcx, link_meta) } fn metadata_encoding_version(&self) -> &[u8] diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0c6a286e2276..60a0d4e03b54 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -18,6 +18,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc::hir; use rustc::middle::cstore::{LinkagePreference, ExternConstBody, ExternBodyNestedBodies}; +use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -27,7 +28,6 @@ use rustc::mir; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; -use rustc::util::nodemap::DefIdSet; use rustc::mir::Mir; use std::cell::Ref; @@ -1006,10 +1006,10 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn get_exported_symbols(&self) -> DefIdSet { - self.exported_symbols - .iter() - .map(|&index| self.local_def_id(index)) + pub fn exported_symbols(&self) -> Vec<(ExportedSymbol, SymbolExportLevel)> { + self.root + .exported_symbols + .decode(self) .collect() } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d3f046c55441..d19ab8945914 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -20,14 +20,16 @@ use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE use rustc::hir::map::definitions::DefPathTable; use rustc::ich::Fingerprint; use rustc::middle::dependency_format::Linkage; +use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel, + metadata_symbol_name}; use rustc::middle::lang_items; use rustc::mir; use rustc::traits::specialization_graph; -use rustc::ty::{self, Ty, TyCtxt, ReprOptions}; +use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName}; use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::session::config::{self, CrateTypeProcMacro}; -use rustc::util::nodemap::{FxHashMap, NodeSet}; +use rustc::util::nodemap::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; @@ -53,7 +55,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { opaque: opaque::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &'a LinkMeta, - exported_symbols: &'a NodeSet, lazy_state: LazyState, type_shorthands: FxHashMap, usize>, @@ -395,9 +396,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode exported symbols info. i = self.position(); + let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE); let exported_symbols = self.tracked( IsolatedEncoder::encode_exported_symbols, - self.exported_symbols); + &exported_symbols); let exported_symbols_bytes = self.position() - i; // Encode and index the items. @@ -1388,9 +1390,25 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // middle::reachable module but filters out items that either don't have a // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). - fn encode_exported_symbols(&mut self, exported_symbols: &NodeSet) -> LazySeq { - let tcx = self.tcx; - self.lazy_seq(exported_symbols.iter().map(|&id| tcx.hir.local_def_id(id).index)) + fn encode_exported_symbols(&mut self, + exported_symbols: &[(ExportedSymbol, SymbolExportLevel)]) + -> LazySeq<(ExportedSymbol, SymbolExportLevel)> { + + // The metadata symbol name is special. It should not show up in + // downstream crates. + let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx)); + + self.lazy_seq(exported_symbols + .iter() + .filter(|&&(ref exported_symbol, _)| { + match *exported_symbol { + ExportedSymbol::NoDefId(symbol_name) => { + symbol_name != metadata_symbol_name + }, + _ => true, + } + }) + .cloned()) } fn encode_dylib_dependency_formats(&mut self, _: ()) -> LazySeq> { @@ -1663,8 +1681,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> { // generated regardless of trailing bytes that end up in it. pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - link_meta: &LinkMeta, - exported_symbols: &NodeSet) + link_meta: &LinkMeta) -> EncodedMetadata { let mut cursor = Cursor::new(vec![]); @@ -1678,7 +1695,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opaque: opaque::Encoder::new(&mut cursor), tcx, link_meta, - exported_symbols, lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index c0ce32cc9706..2504f8dc251f 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { None => self.tcx.sess.err(msg), } } - if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg { + if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "link_cfg", span.unwrap(), @@ -154,7 +154,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { "is feature gated"); } if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.sess.features.borrow().static_nobundle { + !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "static_nobundle", span.unwrap(), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index c542f65dcecf..ce94e4f912f4 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId, CrateNum}; use rustc::ich::StableHashingContext; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; +use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::lang_items; use rustc::mir; use rustc::session::CrateDisambiguator; @@ -202,7 +203,8 @@ pub struct CrateRoot { pub codemap: LazySeq, pub def_path_table: Lazy, pub impls: LazySeq, - pub exported_symbols: LazySeq, + pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>, + pub index: LazySeq, } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 182c9b751968..b77e7cf2ec8b 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -16,7 +16,7 @@ use rustc::ty::{self, RegionKind}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::sync::Lrc; -use super::{MirBorrowckCtxt, Context}; +use super::{Context, MirBorrowckCtxt}; use super::{InitializationRequiringAction, PrefixSet}; use dataflow::{ActiveBorrows, BorrowData, FlowAtLocation, MovingOutStatements}; use dataflow::move_paths::MovePathIndex; @@ -96,7 +96,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } else { true } - }, + } _ => true, }; @@ -106,9 +106,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { None => "value".to_owned(), }; - err.note(&format!("move occurs because {} has type `{}`, \ - which does not implement the `Copy` trait", - note_msg, ty)); + err.note(&format!( + "move occurs because {} has type `{}`, \ + which does not implement the `Copy` trait", + note_msg, ty + )); } } @@ -154,7 +156,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { span, &self.describe_place(place).unwrap_or("_".to_owned()), self.retrieve_borrow_span(borrow), - &self.describe_place(&borrow.borrowed_place).unwrap_or("_".to_owned()), + &self.describe_place(&borrow.borrowed_place) + .unwrap_or("_".to_owned()), Origin::Mir, ); @@ -175,8 +178,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { use rustc::hir::ExprClosure; use rustc::mir::AggregateKind; - let local = match self.mir[location.block].statements.get(location.statement_index) { - Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. }) => local, + let local = match self.mir[location.block] + .statements + .get(location.statement_index) + { + Some(&Statement { + kind: StatementKind::Assign(Place::Local(local), _), + .. + }) => local, _ => return None, }; @@ -202,8 +211,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .with_freevars(node_id, |freevars| { for (v, place) in freevars.iter().zip(places) { match *place { - Operand::Copy(Place::Local(l)) | - Operand::Move(Place::Local(l)) if local == l => + Operand::Copy(Place::Local(l)) + | Operand::Move(Place::Local(l)) if local == l => { debug!( "find_closure_span: found captured local {:?}", @@ -232,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context: Context, (place, span): (&Place<'tcx>, Span), gen_borrow_kind: BorrowKind, - issued_borrow: &BorrowData, + issued_borrow: &BorrowData<'tcx>, end_issued_loan_span: Option, ) { let issued_span = self.retrieve_borrow_span(issued_borrow); @@ -255,8 +264,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "immutable", "mutable", ) { - (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) | - (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx + (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) + | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx .cannot_reborrow_already_borrowed( span, &desc_place, @@ -355,11 +364,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context: Context, borrow: &BorrowData<'tcx>, drop_span: Span, - borrows: &ActiveBorrows<'cx, 'gcx, 'tcx> + borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>, ) { let end_span = borrows.opt_region_end_span(&borrow.region); let scope_tree = borrows.0.scope_tree(); - let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap(); + let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All) + .last() + .unwrap(); let borrow_span = self.mir.source_info(borrow.location).span; let proper_span = match *root_place { @@ -367,13 +378,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _ => drop_span, }; - if self.access_place_error_reported.contains(&(root_place.clone(), borrow_span)) { - debug!("suppressing access_place error when borrow doesn't live long enough for {:?}", - borrow_span); + if self.access_place_error_reported + .contains(&(root_place.clone(), borrow_span)) + { + debug!( + "suppressing access_place error when borrow doesn't live long enough for {:?}", + borrow_span + ); return; } - self.access_place_error_reported.insert((root_place.clone(), borrow_span)); + self.access_place_error_reported + .insert((root_place.clone(), borrow_span)); match (borrow.region, &self.describe_place(&borrow.borrowed_place)) { (RegionKind::ReScope(_), Some(name)) => { @@ -385,9 +401,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { drop_span, borrow_span, proper_span, - end_span + end_span, ); - }, + } (RegionKind::ReScope(_), None) => { self.report_scoped_temporary_value_does_not_live_long_enough( context, @@ -396,14 +412,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { drop_span, borrow_span, proper_span, - end_span + end_span, ); - }, - (RegionKind::ReEarlyBound(_), Some(name)) | - (RegionKind::ReFree(_), Some(name)) | - (RegionKind::ReStatic, Some(name)) | - (RegionKind::ReEmpty, Some(name)) | - (RegionKind::ReVar(_), Some(name)) => { + } + (RegionKind::ReEarlyBound(_), Some(name)) + | (RegionKind::ReFree(_), Some(name)) + | (RegionKind::ReStatic, Some(name)) + | (RegionKind::ReEmpty, Some(name)) + | (RegionKind::ReVar(_), Some(name)) => { self.report_unscoped_local_value_does_not_live_long_enough( context, name, @@ -414,12 +430,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { proper_span, end_span, ); - }, - (RegionKind::ReEarlyBound(_), None) | - (RegionKind::ReFree(_), None) | - (RegionKind::ReStatic, None) | - (RegionKind::ReEmpty, None) | - (RegionKind::ReVar(_), None) => { + } + (RegionKind::ReEarlyBound(_), None) + | (RegionKind::ReFree(_), None) + | (RegionKind::ReStatic, None) + | (RegionKind::ReEmpty, None) + | (RegionKind::ReVar(_), None) => { self.report_unscoped_temporary_value_does_not_live_long_enough( context, &scope_tree, @@ -429,13 +445,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { proper_span, end_span, ); - }, - (RegionKind::ReLateBound(_, _), _) | - (RegionKind::ReSkolemized(_, _), _) | - (RegionKind::ReClosureBound(_), _) | - (RegionKind::ReErased, _) => { + } + (RegionKind::ReLateBound(_, _), _) + | (RegionKind::ReSkolemized(_, _), _) + | (RegionKind::ReClosureBound(_), _) + | (RegionKind::ReErased, _) => { span_bug!(drop_span, "region does not make sense in this context"); - }, + } } } @@ -450,11 +466,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _proper_span: Span, end_span: Option, ) { - let mut err = self.tcx.path_does_not_live_long_enough(borrow_span, - &format!("`{}`", name), - Origin::Mir); + let mut err = self.tcx.path_does_not_live_long_enough( + borrow_span, + &format!("`{}`", name), + Origin::Mir, + ); err.span_label(borrow_span, "borrowed value does not live long enough"); - err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name)); + err.span_label( + drop_span, + format!("`{}` dropped here while still borrowed", name), + ); if let Some(end) = end_span { err.span_label(end, "borrowed value needs to live until here"); } @@ -472,11 +493,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { proper_span: Span, end_span: Option, ) { - let mut err = self.tcx.path_does_not_live_long_enough(proper_span, - "borrowed value", - Origin::Mir); + let mut err = + self.tcx + .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir); err.span_label(proper_span, "temporary value does not live long enough"); - err.span_label(drop_span, "temporary value dropped here while still borrowed"); + err.span_label( + drop_span, + "temporary value dropped here while still borrowed", + ); err.note("consider using a `let` binding to increase its lifetime"); if let Some(end) = end_span { err.span_label(end, "temporary value needs to live until here"); @@ -496,14 +520,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { _proper_span: Span, _end_span: Option, ) { - let mut err = self.tcx.path_does_not_live_long_enough(borrow_span, - &format!("`{}`", name), - Origin::Mir); + debug!( + "report_unscoped_local_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\ + )", + context, name, scope_tree, borrow, drop_span, borrow_span + ); + + let mut err = self.tcx.path_does_not_live_long_enough( + borrow_span, + &format!("`{}`", name), + Origin::Mir, + ); err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(drop_span, "borrowed value only lives until here"); - self.tcx.note_and_explain_region(scope_tree, &mut err, - "borrowed value must be valid for ", - borrow.region, "..."); + + if !self.tcx.nll() { + self.tcx.note_and_explain_region( + scope_tree, + &mut err, + "borrowed value must be valid for ", + borrow.region, + "...", + ); + } + self.explain_why_borrow_contains_point(context, borrow, &mut err); err.emit(); } @@ -516,16 +557,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { drop_span: Span, _borrow_span: Span, proper_span: Span, - _end_span: Option + _end_span: Option, ) { - let mut err = self.tcx.path_does_not_live_long_enough(proper_span, - "borrowed value", - Origin::Mir); + debug!( + "report_unscoped_temporary_value_does_not_live_long_enough(\ + {:?}, {:?}, {:?}, {:?}, {:?}\ + )", + context, scope_tree, borrow, drop_span, proper_span + ); + + let mut err = + self.tcx + .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir); err.span_label(proper_span, "temporary value does not live long enough"); err.span_label(drop_span, "temporary value only lives until here"); - self.tcx.note_and_explain_region(scope_tree, &mut err, - "borrowed value must be valid for ", - borrow.region, "..."); + + if !self.tcx.nll() { + self.tcx.note_and_explain_region( + scope_tree, + &mut err, + "borrowed value must be valid for ", + borrow.region, + "...", + ); + } + self.explain_why_borrow_contains_point(context, borrow, &mut err); err.emit(); } @@ -534,7 +590,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, (place, span): (&Place<'tcx>, Span), - loan: &BorrowData, + loan: &BorrowData<'tcx>, ) { let mut err = self.tcx.cannot_assign_to_borrowed( span, @@ -706,9 +762,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ProjectionElem::Field(_, field_type) => { self.describe_field_from_ty(&field_type, field) } - ProjectionElem::Index(..) | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } => { + ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { format!("{}", self.describe_field(&proj.base, field)) } }, @@ -765,13 +821,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Local(local) => { let local = &self.mir.local_decls[*local]; Some(local.ty) - }, + } Place::Static(ref st) => Some(st.ty), - Place::Projection(ref proj) => { - match proj.elem { - ProjectionElem::Field(_, ty) => Some(ty), - _ => None, - } + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(_, ty) => Some(ty), + _ => None, }, } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c6ed971f767c..1ff0ffaaa68b 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -72,7 +72,7 @@ fn mir_borrowck<'a, 'tcx>( let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); - if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.use_mir() { + if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() { return None; } @@ -101,7 +101,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // contain non-lexical lifetimes. It will have a lifetime tied // to the inference context. let mut mir: Mir<'tcx> = input_mir.clone(); - let free_regions = if !tcx.sess.nll() { + let free_regions = if !tcx.nll() { None } else { let mir = &mut mir; @@ -204,7 +204,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( ); (Some(Rc::new(regioncx)), opt_closure_req) } else { - assert!(!tcx.sess.nll()); + assert!(!tcx.nll()); (None, None) }; let flow_inits = flow_inits; // remove mut @@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// allowed to be split into separate Reservation and /// Activation phases. fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool { - self.tcx.sess.two_phase_borrows() && + self.tcx.two_phase_borrows() && (kind.allows_two_phase_borrow() || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) } @@ -1253,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { span: Span, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { - if !self.tcx.sess.two_phase_borrows() { + if !self.tcx.two_phase_borrows() { return; } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index b6d8e14b7475..19f95aeec709 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -21,7 +21,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(in borrow_check) fn explain_why_borrow_contains_point( &self, context: Context, - borrow: &BorrowData<'_>, + borrow: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>, ) { if let Some(regioncx) = &self.nonlexical_regioncx { @@ -70,9 +70,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } - _ => { - cause.label_diagnostic(mir, err); + Cause::UniversalRegion(region_vid) => { + if let Some(region) = regioncx.to_error_region(region_vid) { + self.tcx.note_and_explain_free_region( + err, + "borrowed value must be valid for ", + region, + "...", + ); + } } + + _ => {} } } } 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 33c012dfad82..3ffb4370359b 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -26,7 +26,6 @@ use rustc::ty::{self, RegionVid, Ty, TypeFoldable}; use rustc::util::common::ErrorReported; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_errors::DiagnosticBuilder; use std::fmt; use std::rc::Rc; use syntax::ast; @@ -435,7 +434,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut()); - self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut()); + self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut()); let outlives_requirements = outlives_requirements.unwrap_or(vec![]); @@ -574,10 +573,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // an error that multiple bounds are required. tcx.sess.span_err( type_test.span, - &format!( - "`{}` does not live long enough", - type_test.generic_kind, - ), + &format!("`{}` does not live long enough", type_test.generic_kind,), ); } } @@ -589,13 +585,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// existentially bound, then we check its inferred value and try /// to find a good name from that. Returns `None` if we can't find /// one (e.g., this is just some random part of the CFG). - fn to_error_region(&self, r: RegionVid) -> Option> { + pub fn to_error_region(&self, r: RegionVid) -> Option> { if self.universal_regions.is_universal_region(r) { return self.definitions[r].external_name; } else { let inferred_values = self.inferred_values - .as_ref() - .expect("region values not yet inferred"); + .as_ref() + .expect("region values not yet inferred"); let upper_bound = self.universal_upper_bound(r); if inferred_values.contains(r, upper_bound) { self.to_error_region(upper_bound) @@ -807,9 +803,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> bool { debug!( "eval_region_test(point={:?}, lower_bound={:?}, test={:?})", - point, - lower_bound, - test + point, lower_bound, test ); match test { @@ -841,9 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> bool { debug!( "eval_outlives({:?}: {:?} @ {:?})", - sup_region, - sub_region, - point + sup_region, sub_region, point ); // Roughly speaking, do a DFS of all region elements reachable @@ -897,7 +889,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_universal_regions<'gcx>( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, ) { @@ -913,7 +904,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { for (fr, _) in universal_definitions { self.check_universal_region( infcx, - mir, mir_def_id, fr, &mut propagated_outlives_requirements, @@ -932,7 +922,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_universal_region<'gcx>( &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, - mir: &Mir<'tcx>, mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, @@ -951,8 +940,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!( "check_universal_region: fr={:?} does not outlive shorter_fr={:?}", - longer_fr, - shorter_fr, + longer_fr, shorter_fr, ); let blame_span = self.blame_span(longer_fr, shorter_fr); @@ -990,7 +978,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Note: in this case, we use the unapproximated regions // to report the error. This gives better error messages // in some cases. - self.report_error(infcx, mir, mir_def_id, longer_fr, shorter_fr, blame_span); + self.report_error(infcx, mir_def_id, longer_fr, shorter_fr, blame_span); } } @@ -1005,7 +993,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_error( &self, infcx: &InferCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, mir_def_id: DefId, fr: RegionVid, outlived_fr: RegionVid, @@ -1039,12 +1026,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { &format!("{} does not outlive {}", fr_string, outlived_fr_string,), ); - // Find out why `fr` had to outlive `outlived_fr`... - let inferred_values = self.inferred_values.as_ref().unwrap(); - if let Some(cause) = inferred_values.cause(fr, outlived_fr) { - cause.label_diagnostic(mir, &mut diag); - } - diag.emit(); } @@ -1134,10 +1115,7 @@ impl fmt::Debug for Constraint { write!( formatter, "({:?}: {:?} @ {:?}) due to {:?}", - self.sup, - self.sub, - self.point, - self.span + self.sup, self.sub, self.point, self.span ) } } @@ -1187,9 +1165,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi debug!( "apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})", - location, - closure_def_id, - closure_substs + location, closure_def_id, closure_substs ); // Get Tu. @@ -1217,9 +1193,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi "apply_requirements: region={:?} \ outlived_region={:?} \ outlives_requirement={:?}", - region, - outlived_region, - outlives_requirement, + region, outlived_region, outlives_requirement, ); infcx.sub_regions(origin, outlived_region, region); } @@ -1230,9 +1204,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi "apply_requirements: ty={:?} \ outlived_region={:?} \ outlives_requirement={:?}", - ty, - outlived_region, - outlives_requirement, + ty, outlived_region, outlives_requirement, ); infcx.register_region_obligation( body_id, @@ -1285,77 +1257,14 @@ impl CauseExt for Rc { } impl Cause { - pub(crate) fn label_diagnostic(&self, mir: &Mir<'_>, diag: &mut DiagnosticBuilder<'_>) { - // The cause information is pretty messy. Only dump it as an - // internal debugging aid if -Znll-dump-cause is given. - let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.nll_dump_cause()); - if !nll_dump_cause { - return; - } - - let mut string = String::new(); - self.push_diagnostic_string(mir, &mut string); - diag.note(&string); - } - - fn push_diagnostic_string(&self, mir: &Mir<'_>, string: &mut String) { - match self { - Cause::LiveVar(local, location) => { - string.push_str(&format!("because `{:?}` is live at {:?}", local, location)); - } - - Cause::DropVar(local, location) => { - string.push_str(&format!( - "because `{:?}` is dropped at {:?}", - local, - location - )); - } - - Cause::LiveOther(location) => { - string.push_str(&format!( - "because of a general liveness constraint at {:?}", - location - )); - } - - Cause::UniversalRegion(region_vid) => { - string.push_str(&format!( - "because `{:?}` is universally quantified", - region_vid - )); - } - - Cause::Outlives { - original_cause, - constraint_location, - constraint_span: _, - } => { - string.push_str(&format!( - "because of an outlives relation created at `{:?}`\n", - constraint_location - )); - - original_cause.push_diagnostic_string(mir, string); - } - } - } - pub(crate) fn root_cause(&self) -> &Cause { match self { - Cause::LiveVar(..) | - Cause::DropVar(..) | - Cause::LiveOther(..) | - Cause::UniversalRegion(..) => { - self - } + Cause::LiveVar(..) + | Cause::DropVar(..) + | Cause::LiveOther(..) + | Cause::UniversalRegion(..) => self, - Cause::Outlives { - original_cause, - .. - } => { - original_cause.root_cause() - } + Cause::Outlives { original_cause, .. } => original_cause.root_cause(), } } } 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 a06d39d225c4..3af10c5c2516 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1587,7 +1587,7 @@ impl MirPass for TypeckMir { // When NLL is enabled, the borrow checker runs the typeck // itself, so we don't need this MIR pass anymore. - if tcx.sess.nll() { + if tcx.nll() { return; } diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 932aad0bb1d8..1ed8289d4418 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, region_scope: region::Scope) { - if tcx.sess.emit_end_regions() { + if tcx.emit_end_regions() { if let region::ScopeData::CallSite(_) = region_scope.data() { // The CallSite scope (aka the root scope) is sort of weird, in that it is // supposed to "separate" the "interior" and "exterior" of a closure. Being diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b16d7ed23650..abea55835466 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().sess.features.borrow().never_type && + self.hir.tcx().features().never_type && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index eb4ba21489c3..10c2f9f758f1 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -736,7 +736,7 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: } Some(_) => true, None => { - if tcx.is_exported_symbol(def_id) || + if tcx.is_reachable_non_generic(def_id) || tcx.is_foreign_item(def_id) { // We can link to the item in question, no instance needed @@ -984,7 +984,7 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { } MonoItemCollectionMode::Lazy => { self.entry_fn == Some(def_id) || - self.tcx.is_exported_symbol(def_id) || + self.tcx.is_reachable_non_generic(def_id) || attr::contains_name(&self.tcx.get_attrs(def_id), "rustc_std_internal_symbol") } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 2b558e71483c..d65c1e03298a 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -363,7 +363,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, can_be_internalized = false; Visibility::Hidden } else if def_id.is_local() { - if tcx.is_exported_symbol(def_id) { + if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; default_visibility(def_id) } else { @@ -385,7 +385,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (Linkage::External, visibility) } MonoItem::Static(def_id) => { - let visibility = if tcx.is_exported_symbol(def_id) { + let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; default_visibility(def_id) } else { @@ -395,7 +395,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); - let visibility = if tcx.is_exported_symbol(def_id) { + let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; default_visibility(def_id) } else { diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs index 7986313aa813..6e8985d99d28 100644 --- a/src/librustc_mir/transform/clean_end_regions.rs +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -42,7 +42,7 @@ impl MirPass for CleanEndRegions { tcx: TyCtxt<'a, 'tcx, 'tcx>, _source: MirSource, mir: &mut Mir<'tcx>) { - if !tcx.sess.emit_end_regions() { return; } + if !tcx.emit_end_regions() { return; } let mut gather = GatherBorrowedRegions { seen_regions: FxHashSet() diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 981b0b854bda..83cd7bf549d5 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -77,19 +77,12 @@ impl Lower128Bit { }; let bin_statement = block.statements.pop().unwrap(); - let (source_info, place, lhs, mut rhs) = match bin_statement { - Statement { - source_info, - kind: StatementKind::Assign( - place, - Rvalue::BinaryOp(_, lhs, rhs)) - } => (source_info, place, lhs, rhs), - Statement { - source_info, - kind: StatementKind::Assign( - place, - Rvalue::CheckedBinaryOp(_, lhs, rhs)) - } => (source_info, place, lhs, rhs), + let source_info = bin_statement.source_info; + let (place, lhs, mut rhs) = match bin_statement.kind { + StatementKind::Assign(place, Rvalue::BinaryOp(_, lhs, rhs)) + | StatementKind::Assign(place, Rvalue::CheckedBinaryOp(_, lhs, rhs)) => { + (place, lhs, rhs) + } _ => bug!("Statement doesn't match pattern any more?"), }; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 0b0ce1fb4d48..8f5831270d6e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -936,7 +936,7 @@ This does not pose a problem by itself because they can't be accessed directly." if self.mode != Mode::Fn && // feature-gate is not enabled, - !self.tcx.sess.features.borrow() + !self.tcx.features() .declared_lib_features .iter() .any(|&(ref sym, _)| sym == feature_name) && diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 4a7ee397aec0..89242ca32bcb 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -514,7 +514,7 @@ impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> { o: Origin) -> DiagnosticBuilder<'a> { - if !o.should_emit_errors(self.sess.borrowck_mode()) { + if !o.should_emit_errors(self.borrowck_mode()) { self.sess.diagnostic().cancel(&mut diag); } diag diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index a46b85d93cbb..bf59165a9c46 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -52,7 +52,7 @@ pub fn load_plugins(sess: &Session, // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without // the feature enabled will result in an error later... - if sess.features.borrow().plugin { + if sess.features_untracked().plugin { for attr in &krate.attrs { if !attr.check_name("plugin") { continue; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index b9899f499148..bf7b81c4d0e4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -590,7 +590,7 @@ impl<'a> Resolver<'a> { }; let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 317bd9217b59..fc1ff2481840 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1524,7 +1524,7 @@ impl<'a> Resolver<'a> { invocations.insert(Mark::root(), arenas.alloc_invocation_data(InvocationData::root(graph_root))); - let features = session.features.borrow(); + let features = session.features_untracked(); let mut macro_defs = FxHashMap(); macro_defs.insert(Mark::root(), root_def_id); @@ -2998,7 +2998,7 @@ impl<'a> Resolver<'a> { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; match prim { TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features.borrow().i128_type { + if !self.session.features_untracked().i128_type { emit_feature_err(&self.session.parse_sess, "i128_type", span, GateIssue::Language, "128-bit type is unstable"); @@ -3089,7 +3089,7 @@ impl<'a> Resolver<'a> { let prev_name = path[0].node.name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && - self.session.features.borrow().extern_absolute_paths { + self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); let crate_root = diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 81cc5e59bbbf..95fa0f3b52fe 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -744,7 +744,7 @@ impl<'a> Resolver<'a> { let def_id = self.definitions.local_def_id(item.id); let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features, + &self.session.features_untracked(), item)); self.macro_map.insert(def_id, ext); @@ -838,7 +838,7 @@ impl<'a> Resolver<'a> { } fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) { - if !self.session.features.borrow().custom_derive { + if !self.session.features_untracked().custom_derive { let sess = &self.session.parse_sess; let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE; emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 438ab3a3513f..01c1ded94578 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -609,7 +609,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() || module_path[0].node.name == keywords::Extern.name()) { let is_extern = module_path[0].node.name == keywords::Extern.name() || - self.session.features.borrow().extern_absolute_paths; + self.session.features_untracked().extern_absolute_paths; match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index a3ff39a47a29..3fe667f15437 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -768,9 +768,9 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for &(ref name, _, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { + for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { if level.is_below_threshold(export_threshold) { - symbols.push(name.clone()); + symbols.push(symbol.symbol_name(tcx).to_string()); } } @@ -782,9 +782,9 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { // ... we add its symbol list to our export list. - for &(ref name, _, level) in tcx.exported_symbols(cnum).iter() { + for &(symbol, level) in tcx.exported_symbols(cnum).iter() { if level.is_below_threshold(export_threshold) { - symbols.push(name.clone()); + symbols.push(symbol.symbol_name(tcx).to_string()); } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 3f9e9191cf03..f79651cef3ec 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -113,7 +113,7 @@ pub(crate) fn run(cgcx: &CodegenContext, Lto::No => panic!("didn't request LTO but we're doing LTO"), }; - let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| { + let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { if level.is_below_threshold(export_threshold) { let mut bytes = Vec::with_capacity(name.len() + 1); bytes.extend(name.bytes()); diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 55ef4e7ed3ae..739ae768ca29 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -11,33 +11,27 @@ use rustc_data_structures::sync::Lrc; use std::sync::Arc; -use base; use monomorphize::Instance; +use rustc::hir; use rustc::hir::def_id::CrateNum; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::middle::exported_symbols::SymbolExportLevel; +use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; -use rustc::ty::TyCtxt; +use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::maps::Providers; -use rustc::util::nodemap::FxHashMap; +use rustc::util::nodemap::{FxHashMap, DefIdSet}; use rustc_allocator::ALLOCATOR_METHODS; use syntax::attr; pub type ExportedSymbols = FxHashMap< CrateNum, - Arc, SymbolExportLevel)>>, + Arc>, >; pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types.borrow()) } -pub fn metadata_symbol_name(tcx: TyCtxt) -> String { - format!("rust_metadata_{}_{}", - tcx.crate_name(LOCAL_CRATE), - tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()) -} - fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { match crate_type { config::CrateTypeExecutable | @@ -60,140 +54,203 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) } } -pub fn provide(providers: &mut Providers) { - providers.exported_symbol_ids = |tcx, cnum| { - let export_threshold = threshold(tcx); - Lrc::new(tcx.exported_symbols(cnum) - .iter() - .filter_map(|&(_, id, level)| { - id.and_then(|id| { - if level.is_below_threshold(export_threshold) { - Some(id) +fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Lrc +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_trans() { + return Lrc::new(DefIdSet()) + } + + let export_threshold = threshold(tcx); + + // We already collect all potentially reachable non-generic items for + // `exported_symbols`. Now we just filter them down to what is actually + // exported for the given crate we are compiling. + let reachable_non_generics = tcx + .exported_symbols(LOCAL_CRATE) + .iter() + .filter_map(|&(exported_symbol, level)| { + if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { + if level.is_below_threshold(export_threshold) { + return Some(def_id) + } + } + + None + }) + .collect(); + + Lrc::new(reachable_non_generics) +} + +fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + tcx.reachable_non_generics(def_id.krate).contains(&def_id) +} + +fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Arc> +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_trans() { + return Arc::new(vec![]) + } + + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || + tcx.is_compiler_builtins(LOCAL_CRATE); + + let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0 + .iter() + .filter_map(|&node_id| { + // We want to ignore some FFI functions that are not exposed from + // this crate. Reachable FFI functions can be lumped into two + // categories: + // + // 1. Those that are included statically via a static library + // 2. Those included otherwise (e.g. dynamically or via a framework) + // + // Although our LLVM module is not literally emitting code for the + // statically included symbols, it's an export of our library which + // needs to be passed on to the linker and encoded in the metadata. + // + // As a result, if this id is an FFI item (foreign item) then we only + // let it through if it's included statically. + match tcx.hir.get(node_id) { + hir::map::NodeForeignItem(..) => { + let def_id = tcx.hir.local_def_id(node_id); + if tcx.is_statically_included_foreign_item(def_id) { + Some(def_id) } else { None } - }) - }) - .collect()) - }; + } - providers.is_exported_symbol = |tcx, id| { - tcx.exported_symbol_ids(id.krate).contains(&id) - }; + // Only consider nodes that actually have exported symbols. + hir::map::NodeItem(&hir::Item { + node: hir::ItemStatic(..), + .. + }) | + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. + }) | + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), + .. + }) => { + let def_id = tcx.hir.local_def_id(node_id); + let generics = tcx.generics_of(def_id); + if (generics.parent_types == 0 && generics.types.is_empty()) && + // Functions marked with #[inline] are only ever translated + // with "internal" linkage and are never exported. + !Instance::mono(tcx, def_id).def.requires_local(tcx) { + Some(def_id) + } else { + None + } + } - providers.exported_symbols = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - let local_exported_symbols = base::find_exported_symbols(tcx); - - let mut local_crate: Vec<_> = local_exported_symbols - .iter() - .map(|&node_id| { - tcx.hir.local_def_id(node_id) - }) - .map(|def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = export_level(tcx, def_id); - debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); - (str::to_owned(&name), Some(def_id), export_level) - }) - .collect(); - - if let Some(_) = *tcx.sess.entry_fn.borrow() { - local_crate.push(("main".to_string(), - None, - SymbolExportLevel::C)); - } - - if tcx.sess.allocator_kind.get().is_some() { - for method in ALLOCATOR_METHODS { - local_crate.push((format!("__rust_{}", method.name), - None, - SymbolExportLevel::Rust)); + _ => None } + }) + .collect(); + + let mut symbols: Vec<_> = reachable_non_generics + .iter() + .map(|&def_id| { + let export_level = if special_runtime_crate { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if &*name == "rust_eh_personality" || + &*name == "rust_eh_register_frames" || + &*name == "rust_eh_unregister_frames" { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } else { + tcx.symbol_export_level(def_id) + }; + debug!("EXPORTED SYMBOL (local): {} ({:?})", + tcx.symbol_name(Instance::mono(tcx, def_id)), + export_level); + (ExportedSymbol::NonGeneric(def_id), export_level) + }) + .collect(); + + if let Some(id) = tcx.sess.derive_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + } + + if let Some(id) = tcx.sess.plugin_registrar_fn.get() { + let def_id = tcx.hir.local_def_id(id); + symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + } + + if let Some(_) = *tcx.sess.entry_fn.borrow() { + let symbol_name = "main".to_string(); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::C)); + } + + if tcx.sess.allocator_kind.get().is_some() { + for method in ALLOCATOR_METHODS { + let symbol_name = format!("__rust_{}", method.name); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + + symbols.push((exported_symbol, SymbolExportLevel::Rust)); } + } - if let Some(id) = tcx.sess.derive_registrar_fn.get() { - let def_id = tcx.hir.local_def_id(id); - let disambiguator = tcx.sess.local_crate_disambiguator(); - let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator); - local_crate.push((registrar, Some(def_id), SymbolExportLevel::C)); - } + if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + let symbol_name = metadata_symbol_name(tcx); + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); - if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - local_crate.push((metadata_symbol_name(tcx), - None, - SymbolExportLevel::Rust)); - } + symbols.push((exported_symbol, SymbolExportLevel::Rust)); + } - // Sort so we get a stable incr. comp. hash. - local_crate.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| { - name1.cmp(name2) - }); + // Sort so we get a stable incr. comp. hash. + symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { + symbol1.compare_stable(tcx, symbol2) + }); - Arc::new(local_crate) - }; + Arc::new(symbols) +} - providers.symbol_export_level = export_level; +pub fn provide(providers: &mut Providers) { + providers.reachable_non_generics = reachable_non_generics_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider; + providers.exported_symbols = exported_symbols_provider_local; + providers.symbol_export_level = symbol_export_level_provider; } pub fn provide_extern(providers: &mut Providers) { - providers.exported_symbols = |tcx, cnum| { - // If this crate is a plugin and/or a custom derive crate, then - // we're not even going to link those in so we skip those crates. - if tcx.plugin_registrar_fn(cnum).is_some() || - tcx.derive_registrar_fn(cnum).is_some() { - return Arc::new(Vec::new()) - } - - // Check to see if this crate is a "special runtime crate". These - // crates, implementation details of the standard library, typically - // have a bunch of `pub extern` and `#[no_mangle]` functions as the - // ABI between them. We don't want their symbols to have a `C` - // export level, however, as they're just implementation details. - // Down below we'll hardwire all of the symbols to the `Rust` export - // level instead. - let special_runtime_crate = - tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - - let mut crate_exports: Vec<_> = tcx - .exported_symbol_ids(cnum) - .iter() - .map(|&def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = if special_runtime_crate { - // We can probably do better here by just ensuring that - // it has hidden visibility rather than public - // visibility, as this is primarily here to ensure it's - // not stripped during LTO. - // - // In general though we won't link right if these - // symbols are stripped, and LTO currently strips them. - if &*name == "rust_eh_personality" || - &*name == "rust_eh_register_frames" || - &*name == "rust_eh_unregister_frames" { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } - } else { - export_level(tcx, def_id) - }; - debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); - (str::to_owned(&name), Some(def_id), export_level) - }) - .collect(); - - // Sort so we get a stable incr. comp. hash. - crate_exports.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| { - name1.cmp(name2) - }); - - Arc::new(crate_exports) - }; - providers.symbol_export_level = export_level; + providers.is_reachable_non_generic = is_reachable_non_generic_provider; + providers.symbol_export_level = symbol_export_level_provider; } -fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { +fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to // special symbols in the standard library for various plumbing between diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 78b26a37485e..c0561ff0c173 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -1332,20 +1332,31 @@ fn start_executing_work(tcx: TyCtxt, let coordinator_send = tcx.tx_to_llvm_workers.clone(); let sess = tcx.sess; - let exported_symbols = match sess.lto() { - Lto::No => None, - Lto::ThinLocal => { - let mut exported_symbols = FxHashMap(); - exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); - Some(Arc::new(exported_symbols)) - } - Lto::Yes | Lto::Fat | Lto::Thin => { - let mut exported_symbols = FxHashMap(); - exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); - for &cnum in tcx.crates().iter() { - exported_symbols.insert(cnum, tcx.exported_symbols(cnum)); + // Compute the set of symbols we need to retain when doing LTO (if we need to) + let exported_symbols = { + let mut exported_symbols = FxHashMap(); + + let copy_symbols = |cnum| { + let symbols = tcx.exported_symbols(cnum) + .iter() + .map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl)) + .collect(); + Arc::new(symbols) + }; + + match sess.lto() { + Lto::No => None, + Lto::ThinLocal => { + exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); + Some(Arc::new(exported_symbols)) + } + Lto::Yes | Lto::Fat | Lto::Thin => { + exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE)); + for &cnum in tcx.crates().iter() { + exported_symbols.insert(cnum, copy_symbols(cnum)); + } + Some(Arc::new(exported_symbols)) } - Some(Arc::new(exported_symbols)) } }; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c0785f539371..beb7a091bdcf 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -30,7 +30,6 @@ use super::ModuleKind; use abi; use back::link; -use back::symbol_export; use back::write::{self, OngoingCrateTranslation, create_target_machine}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; @@ -45,6 +44,7 @@ use rustc::ty::maps::Providers; use rustc::dep_graph::{DepNode, DepConstructor}; use rustc::ty::subst::Kind; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; +use rustc::middle::exported_symbols; use rustc::util::common::{time, print_time_passes_entry}; use rustc::session::config::{self, NoDebugInfo}; use rustc::session::Session; @@ -70,7 +70,7 @@ use time_graph; use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames}; use type_::Type; use type_of::LayoutLlvmExt; -use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet}; +use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use std::any::Any; @@ -89,7 +89,7 @@ use syntax::ast; use mir::operand::OperandValue; -pub use rustc_trans_utils::{find_exported_symbols, check_for_rustc_errors_attr}; +pub use rustc_trans_utils::check_for_rustc_errors_attr; pub use rustc_mir::monomorphize::item::linkage_by_name; pub struct StatRecorder<'a, 'tcx: 'a> { @@ -606,8 +606,7 @@ fn contains_null(s: &str) -> bool { fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, llmod_id: &str, - link_meta: &LinkMeta, - exported_symbols: &NodeSet) + link_meta: &LinkMeta) -> (ContextRef, ModuleRef, EncodedMetadata) { use std::io::Write; use flate2::Compression; @@ -643,7 +642,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, EncodedMetadata::new()); } - let metadata = tcx.encode_metadata(link_meta, exported_symbols); + let metadata = tcx.encode_metadata(link_meta); if kind == MetadataKind::Uncompressed { return (metadata_llcx, metadata_llmod, metadata); } @@ -655,7 +654,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, let llmeta = C_bytes_in_context(metadata_llcx, &compressed); let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false); - let name = symbol_export::metadata_symbol_name(tcx); + let name = exported_symbols::metadata_symbol_name(tcx); let buf = CString::new(name).unwrap(); let llglobal = unsafe { llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr()) @@ -718,13 +717,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let crate_hash = tcx.crate_hash(LOCAL_CRATE); let link_meta = link::build_link_meta(crate_hash); - let exported_symbol_node_ids = find_exported_symbols(tcx); // Translate the metadata. let llmod_id = "metadata"; let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(tcx, llmod_id, &link_meta, &exported_symbol_node_ids) + write_metadata(tcx, llmod_id, &link_meta) }); let metadata_module = ModuleTranslation { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 8c40aa6a2acb..54cc561e8041 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -151,7 +151,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, if cx.tcx.is_translated_item(instance_def_id) { if instance_def_id.is_local() { - if !cx.tcx.is_exported_symbol(instance_def_id) { + if !cx.tcx.is_reachable_non_generic(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 1608c4a87bf5..fd9cb8c5a6be 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -134,7 +134,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { let g = declare::define_global(cx, &sym[..], llty).unwrap(); - if !cx.tcx.is_exported_symbol(def_id) { + if !cx.tcx.is_reachable_non_generic(def_id) { unsafe { llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a285e5f263ab..b93e8c2ad21c 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -597,6 +597,12 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); + ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); + ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); + ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 9559cd4d9ea2..0a3f06b55f1e 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -32,7 +32,7 @@ pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - !cx.tcx.is_exported_symbol(def_id) + !cx.tcx.is_reachable_non_generic(def_id) } #[allow(non_snake_case)] diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index b1f1fb52c907..3f87ce7e0479 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -287,8 +287,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, ], None) }, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | - "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | - "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "bitreverse" | "add_with_overflow" | "sub_with_overflow" | + "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => { let ty = arg_tys[0]; match int_type_width_signed(ty, cx) { @@ -315,6 +315,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, &[args[0].immediate()], None) } } + "bitreverse" => { + bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)), + &[args[0].immediate()], None) + } "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { let intrinsic = format!("llvm.{}{}.with.overflow.i{}", if signed { 's' } else { 'u' }, diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index bfecb2019836..d636a5f2e64b 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -44,11 +44,7 @@ extern crate rustc_data_structures; pub extern crate rustc as __rustc; -use rustc::ty::{TyCtxt, Instance}; -use rustc::hir; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::hir::map as hir_map; -use rustc::util::nodemap::NodeSet; +use rustc::ty::TyCtxt; pub mod diagnostics; pub mod link; @@ -70,53 +66,4 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { } } -/// The context provided lists a set of reachable ids as calculated by -/// middle::reachable, but this contains far more ids and symbols than we're -/// actually exposing from the object file. This function will filter the set in -/// the context to the set of ids which correspond to symbols that are exposed -/// from the object file being generated. -/// -/// This list is later used by linkers to determine the set of symbols needed to -/// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - tcx.reachable_set(LOCAL_CRATE).0.iter().cloned().filter(|&id| { - // Next, we want to ignore some FFI functions that are not exposed from - // this crate. Reachable FFI functions can be lumped into two - // categories: - // - // 1. Those that are included statically via a static library - // 2. Those included otherwise (e.g. dynamically or via a framework) - // - // Although our LLVM module is not literally emitting code for the - // statically included symbols, it's an export of our library which - // needs to be passed on to the linker and encoded in the metadata. - // - // As a result, if this id is an FFI item (foreign item) then we only - // let it through if it's included statically. - match tcx.hir.get(id) { - hir_map::NodeForeignItem(..) => { - let def_id = tcx.hir.local_def_id(id); - tcx.is_statically_included_foreign_item(def_id) - } - - // Only consider nodes that actually have exported symbols. - hir_map::NodeItem(&hir::Item { - node: hir::ItemStatic(..), .. }) | - hir_map::NodeItem(&hir::Item { - node: hir::ItemFn(..), .. }) | - hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Method(..), .. }) => { - let def_id = tcx.hir.local_def_id(id); - let generics = tcx.generics_of(def_id); - (generics.parent_types == 0 && generics.types.is_empty()) && - // Functions marked with #[inline] are only ever translated - // with "internal" linkage and are never exported. - !Instance::mono(tcx, def_id).def.requires_local(tcx) - } - - _ => false - } - }).collect() -} - __build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS } diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs index 5d7d4f3055ba..267c8d2bd03c 100644 --- a/src/librustc_trans_utils/symbol_names_test.rs +++ b/src/librustc_trans_utils/symbol_names_test.rs @@ -28,7 +28,7 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - if !tcx.sess.features.borrow().rustc_attrs { + if !tcx.features().rustc_attrs { return; } diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 419371ba3e33..7b2cbe140aeb 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -247,8 +247,7 @@ impl TransCrate for MetadataOnlyTransCrate { tcx.sess.abort_if_errors(); let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE)); - let exported_symbols = ::find_exported_symbols(tcx); - let metadata = tcx.encode_metadata(&link_meta, &exported_symbols); + let metadata = tcx.encode_metadata(&link_meta); box OngoingCrateTranslation { metadata: metadata, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6a6c49c90483..0df1225cf262 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -415,7 +415,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); - if !self.tcx().sess.features.borrow().unboxed_closures && + if !self.tcx().features().unboxed_closures && trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index da66a2e52e81..a261c12bcdd9 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; if pat_adjustments.len() > 0 { - if tcx.sess.features.borrow().match_default_bindings { + if tcx.features().match_default_bindings { debug!("default binding mode is now {:?}", def_bm); self.inh.tables.borrow_mut() .pat_adjustments_mut() diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index e2d6817697e8..abb0acd699cb 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -586,7 +586,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, "unsized_tuple_coercion", self.cause.span, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 23243c3ad66c..2e00040d99a7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -275,7 +275,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "volatile_store" => (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()), - "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" => + "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | + "bswap" | "bitreverse" => (1, vec![param(0)], param(0)), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c95ead285594..841559013a09 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // possible that there will be multiple applicable methods. if !is_suggestion.0 { if reached_raw_pointer - && !self.tcx.sess.features.borrow().arbitrary_self_types { + && !self.tcx.features().arbitrary_self_types { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 epoch // (see https://github.com/rust-lang/rust/issues/46906) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db5a458bb8ce..0f59973eab25 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1105,7 +1105,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.sess.features.borrow().termination_trait { + if fcx.tcx.features().termination_trait { // If the termination trait language item is activated, check that the main return type // implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { @@ -1616,7 +1616,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let repr_type_ty = def.repr.discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.sess.features.borrow().repr128 { + if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, "repr128", sp, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 39e757c52ff2..d10ee358e072 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -536,7 +536,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); - if !fcx.tcx.sess.features.borrow().arbitrary_self_types { + if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f65d627781f0..d3de31d630a9 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -74,7 +74,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } - if tcx.sess.features.borrow().unboxed_closures { + if tcx.features().unboxed_closures { // the feature gate allows all Fn traits return; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1c8d22e4666a..f7158593f0b6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -711,7 +711,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); - if paren_sugar && !tcx.sess.features.borrow().unboxed_closures { + if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ @@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if !allow_defaults && p.default.is_some() { - if !tcx.sess.features.borrow().default_type_parameter_fallback { + if !tcx.features().default_type_parameter_fallback { tcx.lint_node( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, p.id, @@ -1692,7 +1692,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>( // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic - && !tcx.sess.features.borrow().simd_ffi { + && !tcx.features().simd_ffi { let check = |ast_ty: &hir::Ty, ty: Ty| { if ty.is_simd() { tcx.sess.struct_span_err(ast_ty.span, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index af32738d9d04..d9bd96b0d769 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -207,7 +207,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let actual = tcx.fn_sig(main_def_id); let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.sess.features.borrow().termination_trait { + && tcx.features().termination_trait { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f4c9d556c8ab..e4477bee5c0e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -629,7 +629,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { nested: F) { let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs); if let Some(ref cfg) = attrs.cfg { - if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) { + if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4dfdc23ebee5..6f4528a0e243 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -620,7 +620,7 @@ impl HashMap { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -637,7 +637,7 @@ impl HashMap { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::with_capacity(10); + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -724,7 +724,7 @@ impl HashMap /// use std::collections::hash_map::RandomState; /// /// let hasher = RandomState::new(); - /// let map: HashMap = HashMap::with_hasher(hasher); + /// let map: HashMap = HashMap::with_hasher(hasher); /// let hasher: &RandomState = map.hasher(); /// ``` #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] @@ -741,7 +741,7 @@ impl HashMap /// /// ``` /// use std::collections::HashMap; - /// let map: HashMap = HashMap::with_capacity(100); + /// let map: HashMap = HashMap::with_capacity(100); /// assert!(map.capacity() >= 100); /// ``` #[inline] @@ -770,7 +770,7 @@ impl HashMap /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// map.reserve(10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -849,7 +849,7 @@ impl HashMap /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap = HashMap::with_capacity(100); + /// let mut map: HashMap = HashMap::with_capacity(100); /// map.insert(1, 2); /// map.insert(3, 4); /// assert!(map.capacity() >= 100); @@ -1306,7 +1306,7 @@ impl HashMap /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); /// map.retain(|&k, _| k % 2 == 0); /// assert_eq!(map.len(), 4); /// ``` @@ -1722,7 +1722,7 @@ impl IntoIterator for HashMap /// map.insert("c", 3); /// /// // Not possible with .iter() - /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); + /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` fn into_iter(self) -> IntoIter { IntoIter { inner: self.table.into_iter() } @@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1808,7 +1808,7 @@ impl ExactSizeIterator for IntoIter { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -2786,24 +2786,24 @@ mod test_map { assert_eq!(m2.len(), 2); } - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } #[derive(Hash, PartialEq, Eq)] - struct Dropable { + struct Droppable { k: usize, } - impl Dropable { - fn new(k: usize) -> Dropable { + impl Droppable { + fn new(k: usize) -> Droppable { DROP_VECTOR.with(|slot| { slot.borrow_mut()[k] += 1; }); - Dropable { k: k } + Droppable { k: k } } } - impl Drop for Dropable { + impl Drop for Droppable { fn drop(&mut self) { DROP_VECTOR.with(|slot| { slot.borrow_mut()[self.k] -= 1; @@ -2811,9 +2811,9 @@ mod test_map { } } - impl Clone for Dropable { - fn clone(&self) -> Dropable { - Dropable::new(self.k) + impl Clone for Droppable { + fn clone(&self) -> Droppable { + Droppable::new(self.k) } } @@ -2833,8 +2833,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); m.insert(d1, d2); } @@ -2845,7 +2845,7 @@ mod test_map { }); for i in 0..50 { - let k = Dropable::new(i); + let k = Droppable::new(i); let v = m.remove(&k); assert!(v.is_some()); @@ -2892,8 +2892,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); hm.insert(d1, d2); } @@ -2943,13 +2943,13 @@ mod test_map { #[test] fn test_empty_remove() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); assert_eq!(m.remove(&0), None); } #[test] fn test_empty_entry() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); match m.entry(0) { Occupied(_) => panic!(), Vacant(_) => {} @@ -2960,7 +2960,7 @@ mod test_map { #[test] fn test_empty_iter() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); assert_eq!(m.drain().next(), None); assert_eq!(m.keys().next(), None); assert_eq!(m.values().next(), None); @@ -3461,7 +3461,7 @@ mod test_map { fn test_entry_take_doesnt_corrupt() { #![allow(deprecated)] //rand // Test for #19292 - fn check(m: &HashMap) { + fn check(m: &HashMap) { for k in m.keys() { assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); @@ -3570,7 +3570,7 @@ mod test_map { #[test] fn test_retain() { - let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); + let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); map.retain(|&k, _| k % 2 == 0); assert_eq!(map.len(), 50); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a01..9e63ba2717a6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -724,7 +724,7 @@ impl HashSet /// use std::collections::HashSet; /// /// let xs = [1,2,3,4,5,6]; - /// let mut set: HashSet = xs.iter().cloned().collect(); + /// let mut set: HashSet = xs.iter().cloned().collect(); /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` @@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1124,7 @@ impl ExactSizeIterator for IntoIter { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1745,7 +1745,7 @@ mod test_set { #[test] fn test_retain() { let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet = xs.iter().cloned().collect(); + let mut set: HashSet = xs.iter().cloned().collect(); set.retain(|&k| k % 2 == 0); assert_eq!(set.len(), 3); assert!(set.contains(&2)); diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2519d8304355..c88c2bc91371 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -875,6 +875,8 @@ impl CStr { /// `ptr`. /// * There is no guarantee that the memory pointed to by `ptr` contains a /// valid nul terminator byte at the end of the string. + /// * It is not guaranteed that the memory pointed by `ptr` won't change + /// before the `CStr` has been destroyed. /// /// > **Note**: This operation is intended to be a 0-cost cast but it is /// > currently implemented with an up-front calculation of the length of diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a7e1c0ce732e..da15941374d8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -266,7 +266,6 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(hashmap_hasher)] #![feature(heap_api)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1608a752a463..cd2af99d6ac1 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1076,7 +1076,7 @@ impl<'a> Iterator for Ancestors<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "path_ancestors", issue = "48581")] impl<'a> FusedIterator for Ancestors<'a> {} //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 46d554d6411b..9fff8b91f96f 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -428,20 +428,15 @@ impl fmt::Debug for Wtf8 { formatter.write_str("\"")?; let mut pos = 0; - loop { - match self.next_surrogate(pos) { - None => break, - Some((surrogate_pos, surrogate)) => { - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked( - &self.bytes[pos .. surrogate_pos] - )}, - )?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - } + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped( + formatter, + unsafe { str::from_utf8_unchecked( + &self.bytes[pos .. surrogate_pos] + )}, + )?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; } write_str_escaped( formatter, diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 5dd9c6277509..de8b46d5f1b0 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -70,7 +70,7 @@ impl Iterator for ToLowercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. @@ -92,7 +92,7 @@ impl Iterator for ToUppercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToUppercase {} #[derive(Debug, Clone)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index dcae7d0af409..f155b62e3cc7 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -36,7 +36,6 @@ #![feature(str_internals)] #![feature(decode_utf8)] #![feature(fn_traits)] -#![feature(fused)] #![feature(lang_items)] #![feature(non_exhaustive)] #![feature(staged_api)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 5d1611acb7ee..a72e1210d93f 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -127,7 +127,6 @@ impl Iterator for Utf16Encoder } } -#[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Utf16Encoder where I: FusedIterator {} @@ -186,5 +185,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 728b3e4076d1..9162a582599f 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -26,7 +26,6 @@ use parse::token::Token::*; use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; -use std::cell::RefCell; use std::collections::HashMap; use std::collections::hash_map::Entry; @@ -184,7 +183,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -296,7 +295,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) } fn check_lhs_nt_follows(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], lhs: "ed::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the @@ -353,7 +352,7 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool { } fn check_matcher(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], matcher: &[quoted::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); @@ -601,7 +600,7 @@ impl TokenSet { // Requires that `first_sets` is pre-computed for `matcher`; // see `FirstSets::new`. fn check_matcher_core(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], first_sets: &FirstSets, matcher: &[quoted::TokenTree], @@ -869,7 +868,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result, + features: &Features, attrs: &[ast::Attribute], tok: "ed::TokenTree) -> Result<(), String> { debug!("has_legal_fragment_specifier({:?})", tok); @@ -884,7 +883,7 @@ fn has_legal_fragment_specifier(sess: &ParseSess, } fn is_legal_fragment_specifier(sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], frag_name: &str, frag_span: Span) -> bool { @@ -892,7 +891,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, "item" | "block" | "stmt" | "expr" | "pat" | "path" | "ty" | "ident" | "meta" | "tt" | "" => true, "lifetime" => { - if !features.borrow().macro_lifetime_matcher && + if !features.macro_lifetime_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER; emit_feature_err(sess, @@ -904,7 +903,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, true }, "vis" => { - if !features.borrow().macro_vis_matcher && + if !features.macro_vis_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_VIS_MATCHER; emit_feature_err(sess, diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index c9d7f78c2e30..122bb9ba024a 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -17,7 +17,6 @@ use symbol::keywords; use syntax_pos::{BytePos, Span, DUMMY_SP}; use tokenstream; -use std::cell::RefCell; use std::iter::Peekable; use rustc_data_structures::sync::Lrc; @@ -183,7 +182,7 @@ pub fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> Vec { // Will contain the final collection of `self::TokenTree` @@ -251,7 +250,7 @@ fn parse_tree( trees: &mut Peekable, expect_matchers: bool, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> TokenTree where @@ -382,7 +381,7 @@ fn parse_sep_and_kleene_op( input: &mut Peekable, span: Span, sess: &ParseSess, - features: &RefCell, + features: &Features, attrs: &[ast::Attribute], ) -> (Option, KleeneOp) where @@ -415,7 +414,7 @@ where match parse_kleene_op(input, span) { // #2 is a KleeneOp (this is the only valid option) :) Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -438,7 +437,7 @@ where Err(span) => span, } } else { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -460,7 +459,7 @@ where Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; @@ -487,7 +486,7 @@ where Err(span) => span, }; - if !features.borrow().macro_at_most_once_rep + if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") { sess.span_diagnostic diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 058df1d51690..45d82bc7af38 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -62,6 +62,7 @@ macro_rules! declare_features { &[$((stringify!($feature), $ver, $issue, set!($feature))),+]; /// A set of features to be used by later passes. + #[derive(Clone)] pub struct Features { /// `#![feature]` attrs for stable language features, for error reporting pub declared_stable_lang_features: Vec<(Symbol, Span)>, @@ -78,6 +79,12 @@ macro_rules! declare_features { $($feature: false),+ } } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } } }; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b5368b3ecabd..94195ccc72c4 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -132,6 +132,18 @@ impl<'a> StringReader<'a> { self.advance_token()?; Ok(ret_val) } + + fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: usize) { + let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string"); + err.span_label(self.mk_sp(pos, pos), "unterminated raw string"); + if hash_count > 0 { + err.note(&format!("this raw string should be terminated with `\"{}`", + "#".repeat(hash_count))); + } + err.emit(); + FatalError.raise(); + } + fn fatal(&self, m: &str) -> FatalError { self.fatal_span(self.peek_span, m) } @@ -269,6 +281,15 @@ impl<'a> StringReader<'a> { Self::push_escaped_char_for_msg(&mut m, c); self.fatal_span_(from_pos, to_pos, &m[..]) } + + fn struct_span_fatal(&self, + from_pos: BytePos, + to_pos: BytePos, + m: &str) + -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), m) + } + fn struct_fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, @@ -1404,8 +1425,7 @@ impl<'a> StringReader<'a> { } if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise(); + self.fail_unterminated_raw_string(start_bpos, hash_count); } else if !self.ch_is('"') { let last_bpos = self.pos; let curr_char = self.ch.unwrap(); @@ -1421,8 +1441,7 @@ impl<'a> StringReader<'a> { let mut valid = true; 'outer: loop { if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise(); + self.fail_unterminated_raw_string(start_bpos, hash_count); } // if self.ch_is('"') { // content_end_bpos = self.pos; @@ -1636,8 +1655,7 @@ impl<'a> StringReader<'a> { } if self.is_eof() { - let pos = self.pos; - self.fatal_span_(start_bpos, pos, "unterminated raw string").raise(); + self.fail_unterminated_raw_string(start_bpos, hash_count); } else if !self.ch_is('"') { let pos = self.pos; let ch = self.ch.unwrap(); @@ -1653,8 +1671,7 @@ impl<'a> StringReader<'a> { 'outer: loop { match self.ch { None => { - let pos = self.pos; - self.fatal_span_(start_bpos, pos, "unterminated raw string").raise() + self.fail_unterminated_raw_string(start_bpos, hash_count); } Some('"') => { content_end_bpos = self.pos; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 92584f5b5194..da2a22df997d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3114,7 +3114,7 @@ impl<'a> Parser<'a> { let expr_str = self.sess.codemap().span_to_snippet(expr.span) .unwrap_or(pprust::expr_to_string(&expr)); err.span_suggestion(expr.span, - &format!("try {} the casted value", op_verb), + &format!("try {} the cast value", op_verb), format!("({})", expr_str)); err.emit(); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index a7822414c695..8fd95aa1ca86 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -732,18 +732,13 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let mut parser = parse::Parser::new(fmt_str); let mut pieces = vec![]; - loop { - match parser.next() { - Some(mut piece) => { - if !parser.errors.is_empty() { - break; - } - cx.verify_piece(&piece); - cx.resolve_name_inplace(&mut piece); - pieces.push(piece); - } - None => break, + while let Some(mut piece) = parser.next() { + if !parser.errors.is_empty() { + break; } + cx.verify_piece(&piece); + cx.resolve_name_inplace(&mut piece); + pieces.push(piece); } let numbered_position_args = pieces.iter().any(|arg: &parse::Piece| { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9f746adbe657..ed9eb5d5c926 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -322,12 +322,7 @@ impl Span { pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; - loop { - let info = match self.ctxt().outer().expn_info() { - Some(info) => info, - None => break, - }; - + while let Some(info) = self.ctxt().outer().expn_info() { let (pre, post) = match info.callee.format { ExpnFormat::MacroAttribute(..) => ("#[", "]"), ExpnFormat::MacroBang(..) => ("", "!"), diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index fbe2fd10e7a1..1e02fe4befdf 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -18,7 +18,6 @@ // ignore-hexagon // ignore-mips // ignore-powerpc -// ignore-powerpc64 // ignore-s390x // ignore-sparc // ignore-wasm32 diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index 346c5da8d1b8..b24899cc363a 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -25,8 +25,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs index 5bd0c1b4076e..5661592d0c7b 100644 --- a/src/test/codegen/global_asm.rs +++ b/src/test/codegen/global_asm.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs index 401b1fad566d..d8b5db12404a 100644 --- a/src/test/codegen/global_asm_include.rs +++ b/src/test/codegen/global_asm_include.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs index 8b59165e9e61..caa0506550dd 100644 --- a/src/test/codegen/global_asm_x2.rs +++ b/src/test/codegen/global_asm_x2.rs @@ -21,8 +21,6 @@ // ignore-mips64 // ignore-mips64el // ignore-msp430 -// ignore-powerpc64 -// ignore-powerpc64le // ignore-powerpc // ignore-r600 // ignore-amdgcn diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 2eeed2b788ce..655e67cf7eef 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -14,7 +14,6 @@ // ignore-mips // ignore-mips64 // ignore-powerpc -// ignore-powerpc64 // See repr-transparent.rs #![crate_type="lib"] diff --git a/src/test/incremental/feature_gate.rs b/src/test/incremental/feature_gate.rs new file mode 100644 index 000000000000..de2f9ab52f60 --- /dev/null +++ b/src/test/incremental/feature_gate.rs @@ -0,0 +1,23 @@ +// 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. + +// This test makes sure that we detect changed feature gates. + +// revisions:rpass1 cfail2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![cfg_attr(rpass1, feature(nll))] + +fn main() { + let mut v = vec![1]; + v.push(v[0]); + //[cfail2]~^ ERROR cannot borrow +} diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 9ebc438ad5a0..fd8f7b9e384f 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -41,7 +41,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(), true, cx.parse_sess, - &RefCell::new(Features::new()), + &Features::new(), &[]); let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) { Success(map) => map, diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs index 628a570665a3..0dede8eb70de 100644 --- a/src/test/run-pass/extern-types-pointer-cast.rs +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that pointers to extern types can be casted from/to usize, +// Test that pointers to extern types can be cast from/to usize, // despite being !Sized. #![feature(extern_types)] diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 4896f02da20b..bfa3a1e128a9 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(intrinsics)] +#![feature(intrinsics, i128_type)] mod rusti { extern "rust-intrinsic" { @@ -18,6 +18,7 @@ mod rusti { pub fn cttz(x: T) -> T; pub fn cttz_nonzero(x: T) -> T; pub fn bswap(x: T) -> T; + pub fn bitreverse(x: T) -> T; } } @@ -29,106 +30,127 @@ pub fn main() { assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0); + assert_eq!(ctpop(0u128), 0); assert_eq!(ctpop(0i128), 0); assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1); assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1); assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1); assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1); + assert_eq!(ctpop(1u128), 1); assert_eq!(ctpop(1i128), 1); assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2); assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2); assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2); assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2); + assert_eq!(ctpop(10u128), 2); assert_eq!(ctpop(10i128), 2); assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3); assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3); assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3); assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3); + assert_eq!(ctpop(100u128), 3); assert_eq!(ctpop(100i128), 3); assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8); assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16); assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32); assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64); + assert_eq!(ctpop(-1i128 as u128), 128); assert_eq!(ctpop(-1i128), 128); assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8); assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16); assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32); assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64); + assert_eq!(ctlz(0u128), 128); assert_eq!(ctlz(0i128), 128); assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7); assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15); assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31); assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63); + assert_eq!(ctlz(1u128), 127); assert_eq!(ctlz(1i128), 127); assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4); assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12); assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28); assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60); + assert_eq!(ctlz(10u128), 124); assert_eq!(ctlz(10i128), 124); assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1); assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9); assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); + assert_eq!(ctlz(100u128), 121); assert_eq!(ctlz(100i128), 121); assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7); assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15); assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31); assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63); + assert_eq!(ctlz_nonzero(1u128), 127); assert_eq!(ctlz_nonzero(1i128), 127); assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4); assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12); assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28); assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60); + assert_eq!(ctlz_nonzero(10u128), 124); assert_eq!(ctlz_nonzero(10i128), 124); assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1); assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9); assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25); assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57); + assert_eq!(ctlz_nonzero(100u128), 121); assert_eq!(ctlz_nonzero(100i128), 121); assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0); + assert_eq!(cttz(-1i128 as u128), 0); assert_eq!(cttz(-1i128), 0); assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8); assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16); assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32); assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64); + assert_eq!(cttz(0u128), 128); assert_eq!(cttz(0i128), 128); assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0); assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0); assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0); assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0); + assert_eq!(cttz(1u128), 0); assert_eq!(cttz(1i128), 0); assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1); assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1); assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1); assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1); + assert_eq!(cttz(10u128), 1); assert_eq!(cttz(10i128), 1); assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2); assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2); assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); + assert_eq!(cttz(100u128), 2); assert_eq!(cttz(100i128), 2); assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0); assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0); assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0); assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0); + assert_eq!(cttz_nonzero(-1i128 as u128), 0); assert_eq!(cttz_nonzero(-1i128), 0); assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0); assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0); assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0); assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0); + assert_eq!(cttz_nonzero(1u128), 0); assert_eq!(cttz_nonzero(1i128), 0); assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1); assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1); assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1); assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1); + assert_eq!(cttz_nonzero(10u128), 1); assert_eq!(cttz_nonzero(10i128), 1); assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2); assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2); assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2); assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2); + assert_eq!(cttz_nonzero(100u128), 2); assert_eq!(cttz_nonzero(100i128), 2); assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op @@ -138,5 +160,18 @@ pub fn main() { assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + assert_eq!(bswap(0x0122334455667708u128), 0x08776655443322010000000000000000); + assert_eq!(bswap(0x0122334455667708i128), 0x08776655443322010000000000000000); + + assert_eq!(bitreverse(0x0Au8), 0x50); + assert_eq!(bitreverse(0x0Ai8), 0x50); + assert_eq!(bitreverse(0x0A0Cu16), 0x3050); + assert_eq!(bitreverse(0x0A0Ci16), 0x3050); + assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50); + assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50); + assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480); + assert_eq!(bitreverse(0x0122334455667708u128), 0x10EE66AA22CC44800000000000000000); + assert_eq!(bitreverse(0x0122334455667708i128), 0x10EE66AA22CC44800000000000000000); } } diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs index 2411996cf054..ece58eedc56e 100644 --- a/src/test/run-pass/issue-36053.rs +++ b/src/test/run-pass/issue-36053.rs @@ -14,7 +14,6 @@ // `FusedIterator` in std but I was not able to isolate that into an // external crate. -#![feature(fused)] use std::iter::FusedIterator; struct Thing<'a>(&'a str); diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs index cd8ade5e51a1..4dfa5037bc55 100644 --- a/src/test/ui/cast_char.rs +++ b/src/test/ui/cast_char.rs @@ -12,9 +12,9 @@ fn main() { const XYZ: char = 0x1F888 as char; - //~^ ERROR only u8 can be casted into char + //~^ ERROR only u8 can be cast into char const XY: char = 129160 as char; - //~^ ERROR only u8 can be casted into char + //~^ ERROR only u8 can be cast into char const ZYX: char = '\u{01F888}'; println!("{}", XYZ); } diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr index 481715fd9ce3..600d7e61a098 100644 --- a/src/test/ui/cast_char.stderr +++ b/src/test/ui/cast_char.stderr @@ -1,4 +1,4 @@ -error: only u8 can be casted into char +error: only u8 can be cast into char --> $DIR/cast_char.rs:14:23 | LL | const XYZ: char = 0x1F888 as char; @@ -10,7 +10,7 @@ note: lint level defined here LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ -error: only u8 can be casted into char +error: only u8 can be cast into char --> $DIR/cast_char.rs:16:22 | LL | const XY: char = 129160 as char; diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr index d5e87f894178..257b9bd235d7 100644 --- a/src/test/ui/issue-22644.stderr +++ b/src/test/ui/issue-22644.stderr @@ -5,7 +5,7 @@ LL | println!("{}", a as usize < long_name); //~ ERROR `<` is interpreted as | ---------- ^ --------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:17:33 @@ -14,7 +14,7 @@ LL | println!("{}{}", a as usize < long_name, long_name); | ---------- ^ -------------------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:19:31 @@ -23,7 +23,7 @@ LL | println!("{}", a as usize < 4); //~ ERROR `<` is interpreted as a start | ---------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a as usize)` + | help: try comparing the cast value: `(a as usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:21:31 @@ -32,7 +32,7 @@ LL | println!("{}{}", a: usize < long_name, long_name); | -------- ^ -------------------- interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a: usize)` + | help: try comparing the cast value: `(a: usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:23:29 @@ -41,7 +41,7 @@ LL | println!("{}", a: usize < 4); //~ ERROR `<` is interpreted as a start o | -------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `(a: usize)` + | help: try comparing the cast value: `(a: usize)` error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison --> $DIR/issue-22644.rs:28:20 @@ -50,7 +50,7 @@ LL | < //~ ERROR `<` is interpreted as a start of generic | ^ not interpreted as comparison LL | 4); | - interpreted as generic arguments -help: try comparing the casted value +help: try comparing the cast value | LL | println!("{}", (a LL | as @@ -64,7 +64,7 @@ LL | < //~ ERROR `<` is interpreted as a start of generic | ^ not interpreted as comparison LL | 5); | - interpreted as generic arguments -help: try comparing the casted value +help: try comparing the cast value | LL | println!("{}", (a LL | @@ -81,7 +81,7 @@ LL | println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted a | ---------- ^^ --------- interpreted as generic arguments | | | | | not interpreted as shift - | help: try shifting the casted value: `(a as usize)` + | help: try shifting the cast value: `(a as usize)` error: expected type, found `4` --> $DIR/issue-22644.rs:42:28 diff --git a/src/test/ui/issue-42954.stderr b/src/test/ui/issue-42954.stderr index 1a3984181f6e..9164434006f6 100644 --- a/src/test/ui/issue-42954.stderr +++ b/src/test/ui/issue-42954.stderr @@ -5,7 +5,7 @@ LL | $i as u32 < 0 //~ `<` is interpreted as a start of generic argument | --------- ^ - interpreted as generic arguments | | | | | not interpreted as comparison - | help: try comparing the casted value: `($i as u32)` + | help: try comparing the cast value: `($i as u32)` ... LL | is_plainly_printable!(c); | ------------------------- in this macro invocation diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs new file mode 100644 index 000000000000..495989587e58 --- /dev/null +++ b/src/test/ui/lint/type-overflow.rs @@ -0,0 +1,33 @@ +// 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. + +// must-compile-successfully + +#![feature(i128_type)] + +fn main() { + let error = 255i8; //~WARNING literal out of range for i8 + + let ok = 0b1000_0001; // should be ok -> i32 + let ok = 0b0111_1111i8; // should be ok -> 127i8 + + let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 + + let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 + + let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 + + let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + //~^ WARNING literal out of range for i128 + + let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 + + let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 +} diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr new file mode 100644 index 000000000000..d3fcb1335e20 --- /dev/null +++ b/src/test/ui/lint/type-overflow.stderr @@ -0,0 +1,58 @@ +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:16:17 + | +LL | let error = 255i8; //~WARNING literal out of range for i8 + | ^^^^^ + | + = note: #[warn(overflowing_literals)] on by default + +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:21:16 + | +LL | let fail = 0b1000_0001i8; //~WARNING literal out of range for i8 + | ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8` + | + = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into an `i8` and will become `-127i8` + +warning: literal out of range for i64 + --> $DIR/type-overflow.rs:23:16 + | +LL | let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64 + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64` + | + = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into an `i64` and will become `-9223372036854775808i64` + +warning: literal out of range for u32 + --> $DIR/type-overflow.rs:25:16 + | +LL | let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32 + | ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64` + | + = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into an `u32` and will become `4294967295u32` + +warning: literal out of range for i128 + --> $DIR/type-overflow.rs:27:22 + | +LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into an `i128` and will become `-170141183460469231731687303715884105728i128` + = help: consider using `u128` instead + +warning: literal out of range for i32 + --> $DIR/type-overflow.rs:30:16 + | +LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32 + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into an `i32` and will become `-2i32` + = help: consider using `i128` instead + +warning: literal out of range for i8 + --> $DIR/type-overflow.rs:32:17 + | +LL | let fail = -0b1111_1111i8; //~WARNING literal out of range for i8 + | ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16` + | + = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into an `i8` and will become `-1i8` + diff --git a/src/test/ui/nll/borrowed-local-error.rs b/src/test/ui/nll/borrowed-local-error.rs new file mode 100644 index 000000000000..785a38da9598 --- /dev/null +++ b/src/test/ui/nll/borrowed-local-error.rs @@ -0,0 +1,26 @@ +// 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. + +// compile-flags: -Znll-dump-cause + +#![feature(nll)] + +fn gimme(x: &(u32,)) -> &u32 { + &x.0 +} + +fn main() { + let x = gimme({ + let v = (22,); + &v + //~^ ERROR `v` does not live long enough [E0597] + }); + println!("{:?}", x); +} diff --git a/src/test/ui/nll/borrowed-local-error.stderr b/src/test/ui/nll/borrowed-local-error.stderr new file mode 100644 index 000000000000..3bc197855482 --- /dev/null +++ b/src/test/ui/nll/borrowed-local-error.stderr @@ -0,0 +1,17 @@ +error[E0597]: `v` does not live long enough + --> $DIR/borrowed-local-error.rs:22:9 + | +LL | let x = gimme({ + | _____________- +LL | | let v = (22,); +LL | | &v + | | ^^ borrowed value does not live long enough +LL | | //~^ ERROR `v` does not live long enough [E0597] +LL | | }); + | |_____-- borrow later used here + | | + | borrowed value only lives until here + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0597" diff --git a/src/test/ui/nll/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs new file mode 100644 index 000000000000..e1a6112d173f --- /dev/null +++ b/src/test/ui/nll/borrowed-temporary-error.rs @@ -0,0 +1,26 @@ +// 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. + +// compile-flags: -Znll-dump-cause + +#![feature(nll)] + +fn gimme(x: &(u32,)) -> &u32 { + &x.0 +} + +fn main() { + let x = gimme({ + let v = 22; + &(v,) + //~^ ERROR borrowed value does not live long enough [E0597] + }); + println!("{:?}", x); +} diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr new file mode 100644 index 000000000000..f5cb1dccc378 --- /dev/null +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/borrowed-temporary-error.rs:22:10 + | +LL | &(v,) + | ^^^^ temporary value does not live long enough +LL | //~^ ERROR borrowed value does not live long enough [E0597] +LL | }); + | - temporary value only lives until here +LL | println!("{:?}", x); + | - borrow later used here + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0597" diff --git a/src/test/ui/nll/borrowed-universal-error-2.rs b/src/test/ui/nll/borrowed-universal-error-2.rs new file mode 100644 index 000000000000..da03a9fc39b6 --- /dev/null +++ b/src/test/ui/nll/borrowed-universal-error-2.rs @@ -0,0 +1,22 @@ +// 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. + +// compile-flags: -Znll-dump-cause + +#![feature(nll)] +#![allow(warnings)] + +fn foo<'a>(x: &'a (u32,)) -> &'a u32 { + let v = 22; + &v + //~^ ERROR `v` does not live long enough [E0597] +} + +fn main() {} diff --git a/src/test/ui/nll/borrowed-universal-error-2.stderr b/src/test/ui/nll/borrowed-universal-error-2.stderr new file mode 100644 index 000000000000..ff999a71e0f9 --- /dev/null +++ b/src/test/ui/nll/borrowed-universal-error-2.stderr @@ -0,0 +1,18 @@ +error[E0597]: `v` does not live long enough + --> $DIR/borrowed-universal-error-2.rs:18:5 + | +LL | &v + | ^^ borrowed value does not live long enough +LL | //~^ ERROR `v` does not live long enough [E0597] +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 16:1... + --> $DIR/borrowed-universal-error-2.rs:16:1 + | +LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0597" diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs new file mode 100644 index 000000000000..fdc4c29071ee --- /dev/null +++ b/src/test/ui/nll/borrowed-universal-error.rs @@ -0,0 +1,26 @@ +// 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. + +// compile-flags: -Znll-dump-cause + +#![feature(nll)] +#![allow(warnings)] + +fn gimme(x: &(u32,)) -> &u32 { + &x.0 +} + +fn foo<'a>(x: &'a (u32,)) -> &'a u32 { + let v = 22; + gimme(&(v,)) + //~^ ERROR borrowed value does not live long enough [E0597] +} + +fn main() {} diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr new file mode 100644 index 000000000000..4a3d0c6d959f --- /dev/null +++ b/src/test/ui/nll/borrowed-universal-error.stderr @@ -0,0 +1,18 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/borrowed-universal-error.rs:22:12 + | +LL | gimme(&(v,)) + | ^^^^ temporary value does not live long enough +LL | //~^ ERROR borrowed value does not live long enough [E0597] +LL | } + | - temporary value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 20:1... + --> $DIR/borrowed-universal-error.rs:20:1 + | +LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0597" diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr index 316a918e4ee9..1c545906893a 100644 --- a/src/test/ui/nll/capture-ref-in-struct.stderr +++ b/src/test/ui/nll/capture-ref-in-struct.stderr @@ -9,8 +9,6 @@ LL | } LL | LL | deref(p); | - borrow later used here - | - = note: borrowed value must be valid for lifetime '_#5r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index 93a7bab3386d..18ffdc583497 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -34,8 +34,6 @@ LL | } LL | LL | deref(p); | - borrow later used here - | - = note: borrowed value must be valid for lifetime '_#6r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index b6c1d808ff5b..7b2b2f748726 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -61,8 +61,6 @@ LL | } LL | LL | deref(p); | - borrow later used here - | - = note: borrowed value must be valid for lifetime '_#4r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 3cb6524f3b48..0a45603a42cd 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -38,8 +38,6 @@ LL | } LL | LL | deref(p); | - borrow later used here - | - = note: borrowed value must be valid for lifetime '_#4r... error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index eb4d264bf827..21ed421fe96c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -78,8 +78,6 @@ LL | let cell = Cell::new(&a); ... LL | } | - borrowed value only lives until here - | - = note: borrowed value must be valid for lifetime '_#2r... error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr index f7e85e4277ba..c77e0772ce96 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr +++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr @@ -6,8 +6,6 @@ LL | let ref mut x = 1234543; //~ ERROR borrowed value does not live long en LL | x LL | } | - temporary value only lives until here - | - = note: borrowed value must be valid for lifetime '_#2r... error: aborting due to previous error diff --git a/src/test/ui/raw_string.rs b/src/test/ui/raw_string.rs new file mode 100644 index 000000000000..f1eb91d44fda --- /dev/null +++ b/src/test/ui/raw_string.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let x = r##"lol"#; + //~^ ERROR unterminated raw string +} diff --git a/src/test/ui/raw_string.stderr b/src/test/ui/raw_string.stderr new file mode 100644 index 000000000000..b8aa596ef953 --- /dev/null +++ b/src/test/ui/raw_string.stderr @@ -0,0 +1,8 @@ +error: unterminated raw string + --> $DIR/raw_string.rs:12:13 + | +LL | let x = r##"lol"#; + | ^ unterminated raw string + | + = note: this raw string should be terminated with `"##` + diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 3c9dae915b5a..cf63cb2e5d90 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -43,7 +43,6 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("mips", "mips"), ("msp430", "msp430"), ("powerpc", "powerpc"), - ("powerpc64", "powerpc64"), ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"), diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 664aecfcbdb9..f7b491823f83 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -2,3 +2,8 @@ name = "tidy" version = "0.1.0" authors = ["Alex Crichton "] + +[dependencies] +serde = "1.0.8" +serde_derive = "1.0.8" +serde_json = "1.0.2" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4dedf6bfe779..f40c7a72a452 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -10,9 +10,13 @@ //! Check license of third-party deps by inspecting src/vendor +use std::collections::{BTreeSet, HashSet}; use std::fs::File; use std::io::Read; use std::path::Path; +use std::process::Command; + +use serde_json; static LICENSES: &'static [&'static str] = &[ "MIT/Apache-2.0", @@ -24,52 +28,182 @@ static LICENSES: &'static [&'static str] = &[ "Unlicense/MIT", ]; -// These are exceptions to Rust's permissive licensing policy, and -// should be considered bugs. Exceptions are only allowed in Rust -// tooling. It is _crucial_ that no exception crates be dependencies -// of the Rust runtime (std / test). +/// These are exceptions to Rust's permissive licensing policy, and +/// should be considered bugs. Exceptions are only allowed in Rust +/// tooling. It is _crucial_ that no exception crates be dependencies +/// of the Rust runtime (std / test). static EXCEPTIONS: &'static [&'static str] = &[ - "mdbook", // MPL2, mdbook - "openssl", // BSD+advertising clause, cargo, mdbook - "pest", // MPL2, mdbook via handlebars - "thread-id", // Apache-2.0, mdbook - "toml-query", // MPL-2.0, mdbook - "is-match", // MPL-2.0, mdbook - "cssparser", // MPL-2.0, rustdoc - "smallvec", // MPL-2.0, rustdoc + "mdbook", // MPL2, mdbook + "openssl", // BSD+advertising clause, cargo, mdbook + "pest", // MPL2, mdbook via handlebars + "thread-id", // Apache-2.0, mdbook + "toml-query", // MPL-2.0, mdbook + "is-match", // MPL-2.0, mdbook + "cssparser", // MPL-2.0, rustdoc + "smallvec", // MPL-2.0, rustdoc "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo - "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) - "cssparser-macros", // MPL-2.0, rustdoc - "selectors", // MPL-2.0, rustdoc - "clippy_lints", // MPL-2.0 rls + "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) + "cssparser-macros", // MPL-2.0, rustdoc + "selectors", // MPL-2.0, rustdoc + "clippy_lints", // MPL-2.0 rls ]; +/// Which crates to check against the whitelist? +static WHITELIST_CRATES: &'static [CrateVersion] = &[ + CrateVersion("rustc", "0.0.0"), + CrateVersion("rustc_trans", "0.0.0"), +]; + +/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible. +static WHITELIST: &'static [Crate] = &[ + Crate("ar"), + Crate("backtrace"), + Crate("backtrace-sys"), + Crate("bitflags"), + Crate("byteorder"), + Crate("cc"), + Crate("cfg-if"), + Crate("cmake"), + Crate("ena"), + Crate("filetime"), + Crate("flate2"), + Crate("fuchsia-zircon"), + Crate("fuchsia-zircon-sys"), + Crate("jobserver"), + Crate("kernel32-sys"), + Crate("lazy_static"), + Crate("libc"), + Crate("log"), + Crate("log_settings"), + Crate("miniz-sys"), + Crate("num_cpus"), + Crate("owning_ref"), + Crate("parking_lot"), + Crate("parking_lot_core"), + Crate("rand"), + Crate("redox_syscall"), + Crate("rustc-demangle"), + Crate("smallvec"), + Crate("stable_deref_trait"), + Crate("tempdir"), + Crate("unicode-width"), + Crate("winapi"), + Crate("winapi-build"), + Crate("winapi-i686-pc-windows-gnu"), + Crate("winapi-x86_64-pc-windows-gnu"), +]; + +// Some types for Serde to deserialize the output of `cargo metadata` to... + +#[derive(Deserialize)] +struct Output { + resolve: Resolve, +} + +#[derive(Deserialize)] +struct Resolve { + nodes: Vec, +} + +#[derive(Deserialize)] +struct ResolveNode { + id: String, + dependencies: Vec, +} + +/// A unique identifier for a crate +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] +struct Crate<'a>(&'a str); // (name,) + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] +struct CrateVersion<'a>(&'a str, &'a str); // (name, version) + +impl<'a> Crate<'a> { + pub fn id_str(&self) -> String { + format!("{} ", self.0) + } +} + +impl<'a> CrateVersion<'a> { + /// Returns the struct and whether or not the dep is in-tree + pub fn from_str(s: &'a str) -> (Self, bool) { + let mut parts = s.split(" "); + let name = parts.next().unwrap(); + let version = parts.next().unwrap(); + let path = parts.next().unwrap(); + + let is_path_dep = path.starts_with("(path+"); + + (CrateVersion(name, version), is_path_dep) + } + + pub fn id_str(&self) -> String { + format!("{} {}", self.0, self.1) + } +} + +impl<'a> From> for Crate<'a> { + fn from(cv: CrateVersion<'a>) -> Crate<'a> { + Crate(cv.0) + } +} + +/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed. +/// +/// Specifically, this checks that the license is correct. pub fn check(path: &Path, bad: &mut bool) { + // Check licences let path = path.join("vendor"); assert!(path.exists(), "vendor directory missing"); let mut saw_dir = false; - 'next_path: for dir in t!(path.read_dir()) { + for dir in t!(path.read_dir()) { saw_dir = true; let dir = t!(dir); // skip our exceptions - for exception in EXCEPTIONS { - if dir.path() + if EXCEPTIONS.iter().any(|exception| { + dir.path() .to_str() .unwrap() - .contains(&format!("src/vendor/{}", exception)) { - continue 'next_path; - } + .contains(&format!("src/vendor/{}", exception)) + }) { + continue; } let toml = dir.path().join("Cargo.toml"); - if !check_license(&toml) { - *bad = true; - } + *bad = *bad || !check_license(&toml); } assert!(saw_dir, "no vendored source"); } +/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check +/// failed. +/// +/// Specifically, this checks that the dependencies are on the WHITELIST. +pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) { + // Get dependencies from cargo metadata + let resolve = get_deps(path, cargo); + + // Get the whitelist into a convenient form + let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect(); + + // Check dependencies + let mut visited = BTreeSet::new(); + let mut unapproved = BTreeSet::new(); + for &krate in WHITELIST_CRATES.iter() { + let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false); + unapproved.append(&mut bad); + } + + if unapproved.len() > 0 { + println!("Dependencies not on the whitelist:"); + for dep in unapproved { + println!("* {}", dep.id_str()); + } + *bad = true; + } +} + fn check_license(path: &Path) -> bool { if !path.exists() { panic!("{} does not exist", path.display()); @@ -102,9 +236,71 @@ fn extract_license(line: &str) -> String { let first_quote = line.find('"'); let last_quote = line.rfind('"'); if let (Some(f), Some(l)) = (first_quote, last_quote) { - let license = &line[f + 1 .. l]; + let license = &line[f + 1..l]; license.into() } else { "bad-license-parse".into() } } + +/// Get the dependencies of the crate at the given path using `cargo metadata`. +fn get_deps(path: &Path, cargo: &Path) -> Resolve { + // Run `cargo metadata` to get the set of dependencies + let output = Command::new(cargo) + .arg("metadata") + .arg("--format-version") + .arg("1") + .arg("--manifest-path") + .arg(path.join("Cargo.toml")) + .output() + .expect("Unable to run `cargo metadata`") + .stdout; + let output = String::from_utf8_lossy(&output); + let output: Output = serde_json::from_str(&output).unwrap(); + + output.resolve +} + +/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on +/// the whitelist. Returns a list of illegal dependencies. +fn check_crate_whitelist<'a, 'b>( + whitelist: &'a HashSet, + resolve: &'a Resolve, + visited: &'b mut BTreeSet>, + krate: CrateVersion<'a>, + must_be_on_whitelist: bool, +) -> BTreeSet> { + // Will contain bad deps + let mut unapproved = BTreeSet::new(); + + // Check if we have already visited this crate + if visited.contains(&krate) { + return unapproved; + } + + visited.insert(krate); + + // If this path is in-tree, we don't require it to be on the whitelist + if must_be_on_whitelist { + // If this dependency is not on the WHITELIST, add to bad set + if !whitelist.contains(&krate.into()) { + unapproved.insert(krate.into()); + } + } + + // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!) + let to_check = resolve + .nodes + .iter() + .find(|n| n.id.starts_with(&krate.id_str())) + .expect("crate does not exist"); + + for dep in to_check.dependencies.iter() { + let (krate, is_path_dep) = CrateVersion::from_str(dep); + + let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep); + unapproved.append(&mut bad); + } + + unapproved +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 5134c8699126..c927ff19b279 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -15,6 +15,11 @@ #![deny(warnings)] +extern crate serde; +extern crate serde_json; +#[macro_use] +extern crate serde_derive; + use std::fs; use std::path::Path; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index f6640c902bcb..afa3ebd19831 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -24,9 +24,12 @@ use std::path::PathBuf; use std::env; fn main() { - let path = env::args_os().skip(1).next().expect("need an argument"); + let path = env::args_os().skip(1).next().expect("need path to src"); let path = PathBuf::from(path); + let cargo = env::args_os().skip(2).next().expect("need path to cargo"); + let cargo = PathBuf::from(cargo); + let args: Vec = env::args().skip(1).collect(); let mut bad = false; @@ -41,6 +44,7 @@ fn main() { if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); } + deps::check_whitelist(&path, &cargo, &mut bad); if bad { eprintln!("some tidy checks failed");