[[package]]
name = "rls"
-version = "0.122.0"
+version = "0.123.0"
dependencies = [
"cargo 0.24.0",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.2.13",
+ "rustfmt-nightly 0.2.14",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-analysis"
-version = "0.7.1"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"arena 0.0.0",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
+ "rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
[[package]]
name = "rustfmt-nightly"
-version = "0.2.13"
+version = "0.2.14"
dependencies = [
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"rustc_data_structures 0.0.0",
"serialize 0.0.0",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
-"checksum rls-analysis 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3e4c03af262074324e732ba2313ce74968b4262b060367ed4d52940b6586fa1"
+"checksum rls-analysis 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10fbe17ed9da2fa3686ebb018958e194a4a25f0b3a78382bfe334d09d3c641f4"
"checksum rls-data 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48257ceade23c2e01a3ca8d2fc4226101b107f6a3c868f829cf3fd2f204a1fe6"
"checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
install_sh(builder, "docs", "rust-docs", stage, Some(host));
}
-pub fn install_std(builder: &Builder, stage: u32) {
- for target in &builder.build.targets {
- install_sh(builder, "std", "rust-std", stage, Some(*target));
- }
+pub fn install_std(builder: &Builder, stage: u32, target: Interned<String>) {
+ install_sh(builder, "std", "rust-std", stage, Some(target));
}
pub fn install_cargo(builder: &Builder, stage: u32, host: Interned<String>) {
install_docs(builder, self.stage, self.target);
};
Std, "src/libstd", true, only_hosts: true, {
- builder.ensure(dist::Std {
- compiler: builder.compiler(self.stage, self.host),
- target: self.target
- });
- install_std(builder, self.stage);
+ for target in &builder.build.targets {
+ builder.ensure(dist::Std {
+ compiler: builder.compiler(self.stage, self.host),
+ target: *target
+ });
+ install_std(builder, self.stage, *target);
+ }
};
Cargo, "cargo", _config.extended, only_hosts: true, {
builder.ensure(dist::Cargo { stage: self.stage, target: self.target });
}
}
-const OPENSSL_VERS: &'static str = "1.0.2k";
+const OPENSSL_VERS: &'static str = "1.0.2m";
const OPENSSL_SHA256: &'static str =
- "6b3977c61f2aedf0f96367dcfb5c6e578cf37e7b8d913b4ecb6643c3cb88d8c0";
+ "8c6ff15ec6b319b50788f42c7abc2890c08ba5a1cdcd3810eb9092deada37b0f";
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Openssl {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
- run.path("src/tools/clippy")
+ let builder = run.builder;
+ run.path("src/tools/clippy").default_condition(builder.build.config.extended)
}
fn make_run(run: RunConfig) {
mkdir -p $SYSROOT
pushd $SYSROOT
-centos_base=http://mirror.centos.org/altarch/7.3.1611/os/ppc64le/Packages
-glibc_v=2.17-157.el7
-kernel_v=3.10.0-514.el7
+centos_base=http://mirror.centos.org/altarch/7/os/ppc64le/Packages
+glibc_v=2.17-196.el7
+kernel_v=3.10.0-693.el7
for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do
curl $centos_base/$package.ppc64le.rpm | \
rpm2cpio - | cpio -idm
--- /dev/null
+# `non_exhaustive`
+
+The tracking issue for this feature is: [#44109]
+
+[#44109]: https://github.com/rust-lang/rust/issues/44109
+
+------------------------
+
+The `non_exhaustive` gate allows you to use the `#[non_exhaustive]` attribute
+on structs and enums. When applied within a crate, users of the crate will need
+to use the `_` pattern when matching enums and use the `..` pattern when
+matching structs. Structs marked as `non_exhaustive` will not be able to be
+created normally outside of the defining crate. This is demonstrated below:
+
+```rust,ignore (pseudo-Rust)
+use std::error::Error as StdError;
+
+#[non_exhaustive]
+pub enum Error {
+ Message(String),
+ Other,
+}
+impl StdError for Error {
+ fn description(&self) -> &str {
+ // This will not error, despite being marked as non_exhaustive, as this
+ // enum is defined within the current crate, it can be matched
+ // exhaustively.
+ match *self {
+ Message(ref s) => s,
+ Other => "other or unknown error",
+ }
+ }
+}
+```
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Error;
+
+// This will not error as the non_exhaustive Error enum has been matched with
+// a wildcard.
+match error {
+ Message(ref s) => ...,
+ Other => ...,
+ _ => ...,
+}
+```
+
+```rust,ignore (pseudo-Rust)
+#[non_exhaustive]
+pub struct Config {
+ pub window_width: u16,
+ pub window_height: u16,
+}
+
+// We can create structs as normal within the defining crate when marked as
+// non_exhaustive.
+let config = Config { window_width: 640, window_height: 480 };
+
+// We can match structs exhaustively when within the defining crate.
+if let Ok(Config { window_width, window_height }) = load_config() {
+ // ...
+}
+```
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Config;
+
+// We cannot create a struct like normal if it has been marked as
+// non_exhaustive.
+let config = Config { window_width: 640, window_height: 480 };
+// By adding the `..` we can match the config as below outside of the crate
+// when marked non_exhaustive.
+let &Config { window_width, window_height, .. } = config;
+```
+
```rust
#![feature(optin_builtin_traits)]
-trait Valid {}
-
-impl Valid for .. {}
+auto trait Valid {}
struct True;
struct False;
make_test!(split_a_str, s, s.split("a").count());
make_test!(trim_ascii_char, s, {
- use std::ascii::AsciiExt;
s.trim_matches(|c: char| c.is_ascii())
});
make_test!(trim_left_ascii_char, s, {
- use std::ascii::AsciiExt;
s.trim_left_matches(|c: char| c.is_ascii())
});
make_test!(trim_right_ascii_char, s, {
- use std::ascii::AsciiExt;
s.trim_right_matches(|c: char| c.is_ascii())
});
/// # Examples
///
/// ```
- /// use std::ascii::AsciiExt;
/// use std::borrow::Cow;
///
/// let mut cow = Cow::Borrowed("foo");
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allow_internal_unstable)]
+#![feature(ascii_ctype)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
impl<T> RawVec<T, Heap> {
/// Creates the biggest possible RawVec (on the system heap)
/// without allocating. If T has positive size, then this makes a
- /// RawVec with capacity 0. If T has 0 size, then it it makes a
+ /// RawVec with capacity 0. If T has 0 size, then it makes a
/// RawVec with capacity `usize::MAX`. Useful for implementing
/// delayed allocation.
pub fn new() -> Self {
}
}
+// FIXME(LukasKalbertodt): the `not(stage0)` constraint can be removed in the
+// future once the stage0 compiler is new enough to know about the `slice_u8`
+// lang item.
+#[lang = "slice_u8"]
+#[cfg(all(not(stage0), not(test)))]
+impl [u8] {
+ /// Checks if all bytes in this slice are within the ASCII range.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ self.iter().all(|b| b.is_ascii())
+ }
+
+ /// Returns a vector containing a copy of this slice where each byte
+ /// is mapped to its ASCII upper case equivalent.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_uppercase(&self) -> Vec<u8> {
+ let mut me = self.to_vec();
+ me.make_ascii_uppercase();
+ me
+ }
+
+ /// Returns a vector containing a copy of this slice where each byte
+ /// is mapped to its ASCII lower case equivalent.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
+ ///
+ /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_lowercase(&self) -> Vec<u8> {
+ let mut me = self.to_vec();
+ me.make_ascii_lowercase();
+ me
+ }
+
+ /// Checks that two slices are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
+ self.len() == other.len() &&
+ self.iter().zip(other).all(|(a, b)| {
+ a.eq_ignore_ascii_case(b)
+ })
+ }
+
+ /// Converts this slice to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_uppercase();
+ }
+ }
+
+ /// Converts this slice to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_lowercase();
+ }
+ }
+
+ /// Checks if all bytes of this slice are ASCII alphabetic characters:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphabetic(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_alphabetic())
+ }
+
+ /// Checks if all bytes of this slice are ASCII uppercase characters:
+ /// U+0041 'A' ... U+005A 'Z'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_uppercase(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_uppercase())
+ }
+
+ /// Checks if all bytes of this slice are ASCII lowercase characters:
+ /// U+0061 'a' ... U+007A 'z'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_lowercase(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_lowercase())
+ }
+
+ /// Checks if all bytes of this slice are ASCII alphanumeric characters:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z', or
+ /// - U+0030 '0' ... U+0039 '9'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphanumeric(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_alphanumeric())
+ }
+
+ /// Checks if all bytes of this slice are ASCII decimal digit:
+ /// U+0030 '0' ... U+0039 '9'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_digit(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_digit())
+ }
+
+ /// Checks if all bytes of this slice are ASCII hexadecimal digits:
+ ///
+ /// - U+0030 '0' ... U+0039 '9', or
+ /// - U+0041 'A' ... U+0046 'F', or
+ /// - U+0061 'a' ... U+0066 'f'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_hexdigit(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_hexdigit())
+ }
+
+ /// Checks if all bytes of this slice are ASCII punctuation characters:
+ ///
+ /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or
+ /// - U+003A ... U+0040 `: ; < = > ? @`, or
+ /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or
+ /// - U+007B ... U+007E `{ | } ~`
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_punctuation(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_punctuation())
+ }
+
+ /// Checks if all bytes of this slice are ASCII graphic characters:
+ /// U+0021 '@' ... U+007E '~'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_graphic(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_graphic())
+ }
+
+ /// Checks if all bytes of this slice are ASCII whitespace characters:
+ /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+ /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+ ///
+ /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+ /// whitespace][infra-aw]. There are several other definitions in
+ /// wide use. For instance, [the POSIX locale][pct] includes
+ /// U+000B VERTICAL TAB as well as all the above characters,
+ /// but—from the very same specification—[the default rule for
+ /// "field splitting" in the Bourne shell][bfs] considers *only*
+ /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+ ///
+ /// If you are writing a program that will process an existing
+ /// file format, check what that format's definition of whitespace is
+ /// before using this function.
+ ///
+ /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+ /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+ /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_whitespace(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_whitespace())
+ }
+
+ /// Checks if all bytes of this slice are ASCII control characters:
+ ///
+ /// - U+0000 NUL ... U+001F UNIT SEPARATOR, or
+ /// - U+007F DELETE.
+ ///
+ /// Note that most ASCII whitespace characters are control
+ /// characters, but SPACE is not.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_control(&self) -> bool {
+ self.iter().all(|b| b.is_ascii_control())
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Extension traits for slices over specific kinds of data
////////////////////////////////////////////////////////////////////////////////
/// # Examples
///
/// ```
- /// use std::ascii::AsciiExt;
- ///
/// let mut v = String::from("hello");
/// // correct length
/// assert!(v.get_mut(0..5).is_some());
/// Basic usage:
///
/// ```
- /// use std::ascii::AsciiExt;
- ///
/// let mut s = "Per Martin-Löf".to_string();
/// {
/// let (first, last) = s.split_at_mut(3);
s.extend((0..n).map(|_| self));
s
}
+
+ /// Checks if all characters in this string are within the ASCII range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = "hello!\n";
+ /// let non_ascii = "Grüße, Jürgen ❤";
+ ///
+ /// assert!(ascii.is_ascii());
+ /// assert!(!non_ascii.is_ascii());
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ // We can treat each byte as character here: all multibyte characters
+ // start with a byte that is not in the ascii range, so we will stop
+ // there already.
+ self.bytes().all(|b| b.is_ascii())
+ }
+
+ /// Returns a copy of this string where each character is mapped to its
+ /// ASCII upper case equivalent.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// To uppercase ASCII characters in addition to non-ASCII characters, use
+ /// [`to_uppercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Grüße, Jürgen ❤";
+ ///
+ /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase());
+ /// ```
+ ///
+ /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+ /// [`to_uppercase`]: #method.to_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub fn to_ascii_uppercase(&self) -> String {
+ let mut bytes = self.as_bytes().to_vec();
+ bytes.make_ascii_uppercase();
+ // make_ascii_uppercase() preserves the UTF-8 invariant.
+ unsafe { String::from_utf8_unchecked(bytes) }
+ }
+
+ /// Returns a copy of this string where each character is mapped to its
+ /// ASCII lower case equivalent.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
+ ///
+ /// To lowercase ASCII characters in addition to non-ASCII characters, use
+ /// [`to_lowercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Grüße, Jürgen ❤";
+ ///
+ /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase());
+ /// ```
+ ///
+ /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+ /// [`to_lowercase`]: #method.to_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub fn to_ascii_lowercase(&self) -> String {
+ let mut bytes = self.as_bytes().to_vec();
+ bytes.make_ascii_lowercase();
+ // make_ascii_lowercase() preserves the UTF-8 invariant.
+ unsafe { String::from_utf8_unchecked(bytes) }
+ }
+
+ /// Checks that two strings are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!("Ferris".eq_ignore_ascii_case("FERRIS"));
+ /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS"));
+ /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
+ self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
+ }
+
+ /// Converts this string to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[cfg(not(stage0))]
+ pub fn make_ascii_uppercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_uppercase()
+ }
+
+ /// Converts this string to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[cfg(not(stage0))]
+ pub fn make_ascii_lowercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_lowercase()
+ }
+
+ /// Checks if all characters of this string are ASCII alphabetic
+ /// characters:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphabetic(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_alphabetic())
+ }
+
+ /// Checks if all characters of this string are ASCII uppercase characters:
+ /// U+0041 'A' ... U+005A 'Z'.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// // Only ascii uppercase characters
+ /// assert!("HELLO".is_ascii_uppercase());
+ ///
+ /// // While all characters are ascii, 'y' and 'e' are not uppercase
+ /// assert!(!"Bye".is_ascii_uppercase());
+ ///
+ /// // While all characters are uppercase, 'Ü' is not ascii
+ /// assert!(!"TSCHÜSS".is_ascii_uppercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_uppercase(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_uppercase())
+ }
+
+ /// Checks if all characters of this string are ASCII lowercase characters:
+ /// U+0061 'a' ... U+007A 'z'.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// // Only ascii uppercase characters
+ /// assert!("hello".is_ascii_lowercase());
+ ///
+ /// // While all characters are ascii, 'B' is not lowercase
+ /// assert!(!"Bye".is_ascii_lowercase());
+ ///
+ /// // While all characters are lowercase, 'Ü' is not ascii
+ /// assert!(!"tschüss".is_ascii_lowercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_lowercase(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_lowercase())
+ }
+
+ /// Checks if all characters of this string are ASCII alphanumeric
+ /// characters:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z', or
+ /// - U+0030 '0' ... U+0039 '9'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphanumeric(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_alphanumeric())
+ }
+
+ /// Checks if all characters of this string are ASCII decimal digit:
+ /// U+0030 '0' ... U+0039 '9'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_digit(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_digit())
+ }
+
+ /// Checks if all characters of this string are ASCII hexadecimal digits:
+ ///
+ /// - U+0030 '0' ... U+0039 '9', or
+ /// - U+0041 'A' ... U+0046 'F', or
+ /// - U+0061 'a' ... U+0066 'f'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_hexdigit(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_hexdigit())
+ }
+
+ /// Checks if all characters of this string are ASCII punctuation
+ /// characters:
+ ///
+ /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or
+ /// - U+003A ... U+0040 `: ; < = > ? @`, or
+ /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or
+ /// - U+007B ... U+007E `{ | } ~`
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_punctuation(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_punctuation())
+ }
+
+ /// Checks if all characters of this string are ASCII graphic characters:
+ /// U+0021 '@' ... U+007E '~'.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_graphic(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_graphic())
+ }
+
+ /// Checks if all characters of this string are ASCII whitespace characters:
+ /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+ /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+ ///
+ /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+ /// whitespace][infra-aw]. There are several other definitions in
+ /// wide use. For instance, [the POSIX locale][pct] includes
+ /// U+000B VERTICAL TAB as well as all the above characters,
+ /// but—from the very same specification—[the default rule for
+ /// "field splitting" in the Bourne shell][bfs] considers *only*
+ /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+ ///
+ /// If you are writing a program that will process an existing
+ /// file format, check what that format's definition of whitespace is
+ /// before using this function.
+ ///
+ /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+ /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+ /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_whitespace(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_whitespace())
+ }
+
+ /// Checks if all characters of this string are ASCII control characters:
+ ///
+ /// - U+0000 NUL ... U+001F UNIT SEPARATOR, or
+ /// - U+007F DELETE.
+ ///
+ /// Note that most ASCII whitespace characters are control
+ /// characters, but SPACE is not.
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_control(&self) -> bool {
+ self.bytes().all(|b| b.is_ascii_control())
+ }
}
/// Converts a boxed slice of bytes to a boxed string slice without checking
/// Basic usage:
///
/// ```
- /// use std::ascii::AsciiExt;
- ///
/// let mut s = String::from("foobar");
/// let s_mut_str = s.as_mut_str();
///
#[test]
fn test_split_at_mut() {
- use std::ascii::AsciiExt;
let mut s = "Hello World".to_string();
{
let (a, b) = s.split_at_mut(5);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::mem::size_of;
use std::panic;
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
}
}
-
-
/// # Examples
///
/// ```
- /// use std::ascii::AsciiExt;
- ///
/// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
///
/// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
// ABI
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
System.oom((*(err as *const AllocErr)).clone())
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
size: usize,
align: usize) {
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize) {
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_realloc(ptr: *mut u8,
_old_size: usize,
old_align: usize,
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc_zeroed(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
err: *mut u8) -> *mut u8 {
let p = __rde_alloc(size, align, err);
if !p.is_null() {
- *excess = size;
+ let flags = align_to_flags(align);
+ *excess = nallocx(size, flags) as usize;
}
return p
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
err: *mut u8) -> *mut u8 {
let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
if !p.is_null() {
- *excess = new_size;
+ let flags = align_to_flags(new_align);
+ *excess = nallocx(new_size, flags) as usize;
}
- return p
+ p
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
}
#[no_mangle]
- #[linkage = "external"]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
_old_size: usize,
old_align: usize,
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
unsafe impl Send for .. { }
#[stable(feature = "rust1", since = "1.0.0")]
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
unsafe impl Sync for .. { }
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "freeze"]
unsafe trait Freeze {}
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
unsafe impl Freeze for .. {}
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
use convert::{Infallible, TryFrom};
use fmt;
use intrinsics;
+use ops;
use str::FromStr;
/// Provides intentionally-wrapped arithmetic on `T`.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn next_power_of_two(self) -> Self {
- self.one_less_than_next_power_of_two() + 1
+ // Call the trait to get overflow checks
+ ops::Add::add(self.one_less_than_next_power_of_two(), 1)
}
/// Returns the smallest power of two greater than or equal to `n`. If
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
+
+
+ /// Checks if the value is within the ASCII range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = 97u8;
+ /// let non_ascii = 150u8;
+ ///
+ /// assert!(ascii.is_ascii());
+ /// assert!(!non_ascii.is_ascii());
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ *self & 128 == 0
+ }
+
+ /// Makes a copy of the value in its ASCII upper case equivalent.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let lowercase_a = 97u8;
+ ///
+ /// assert_eq!(65, lowercase_a.to_ascii_uppercase());
+ /// ```
+ ///
+ /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_uppercase(&self) -> u8 {
+ ASCII_UPPERCASE_MAP[*self as usize]
+ }
+
+ /// Makes a copy of the value in its ASCII lower case equivalent.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let uppercase_a = 65u8;
+ ///
+ /// assert_eq!(97, uppercase_a.to_ascii_lowercase());
+ /// ```
+ ///
+ /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_lowercase(&self) -> u8 {
+ ASCII_LOWERCASE_MAP[*self as usize]
+ }
+
+ /// Checks that two values are an ASCII case-insensitive match.
+ ///
+ /// This is equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let lowercase_a = 97u8;
+ /// let uppercase_a = 65u8;
+ ///
+ /// assert!(lowercase_a.eq_ignore_ascii_case(&uppercase_a));
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &u8) -> bool {
+ self.to_ascii_lowercase() == other.to_ascii_lowercase()
+ }
+
+ /// Converts this value to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut byte = b'a';
+ ///
+ /// byte.make_ascii_uppercase();
+ ///
+ /// assert_eq!(b'A', byte);
+ /// ```
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ *self = self.to_ascii_uppercase();
+ }
+
+ /// Converts this value to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut byte = b'A';
+ ///
+ /// byte.make_ascii_lowercase();
+ ///
+ /// assert_eq!(b'a', byte);
+ /// ```
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ *self = self.to_ascii_lowercase();
+ }
+
+ /// Checks if the value is an ASCII alphabetic character:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(uppercase_a.is_ascii_alphabetic());
+ /// assert!(uppercase_g.is_ascii_alphabetic());
+ /// assert!(a.is_ascii_alphabetic());
+ /// assert!(g.is_ascii_alphabetic());
+ /// assert!(!zero.is_ascii_alphabetic());
+ /// assert!(!percent.is_ascii_alphabetic());
+ /// assert!(!space.is_ascii_alphabetic());
+ /// assert!(!lf.is_ascii_alphabetic());
+ /// assert!(!esc.is_ascii_alphabetic());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphabetic(&self) -> bool {
+ if *self >= 0x80 { return false; }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ L | Lx | U | Ux => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII uppercase character:
+ /// U+0041 'A' ... U+005A 'Z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(uppercase_a.is_ascii_uppercase());
+ /// assert!(uppercase_g.is_ascii_uppercase());
+ /// assert!(!a.is_ascii_uppercase());
+ /// assert!(!g.is_ascii_uppercase());
+ /// assert!(!zero.is_ascii_uppercase());
+ /// assert!(!percent.is_ascii_uppercase());
+ /// assert!(!space.is_ascii_uppercase());
+ /// assert!(!lf.is_ascii_uppercase());
+ /// assert!(!esc.is_ascii_uppercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_uppercase(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ U | Ux => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII lowercase character:
+ /// U+0061 'a' ... U+007A 'z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(!uppercase_a.is_ascii_lowercase());
+ /// assert!(!uppercase_g.is_ascii_lowercase());
+ /// assert!(a.is_ascii_lowercase());
+ /// assert!(g.is_ascii_lowercase());
+ /// assert!(!zero.is_ascii_lowercase());
+ /// assert!(!percent.is_ascii_lowercase());
+ /// assert!(!space.is_ascii_lowercase());
+ /// assert!(!lf.is_ascii_lowercase());
+ /// assert!(!esc.is_ascii_lowercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_lowercase(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ L | Lx => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII alphanumeric character:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z', or
+ /// - U+0030 '0' ... U+0039 '9'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(uppercase_a.is_ascii_alphanumeric());
+ /// assert!(uppercase_g.is_ascii_alphanumeric());
+ /// assert!(a.is_ascii_alphanumeric());
+ /// assert!(g.is_ascii_alphanumeric());
+ /// assert!(zero.is_ascii_alphanumeric());
+ /// assert!(!percent.is_ascii_alphanumeric());
+ /// assert!(!space.is_ascii_alphanumeric());
+ /// assert!(!lf.is_ascii_alphanumeric());
+ /// assert!(!esc.is_ascii_alphanumeric());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphanumeric(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ D | L | Lx | U | Ux => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII decimal digit:
+ /// U+0030 '0' ... U+0039 '9'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(!uppercase_a.is_ascii_digit());
+ /// assert!(!uppercase_g.is_ascii_digit());
+ /// assert!(!a.is_ascii_digit());
+ /// assert!(!g.is_ascii_digit());
+ /// assert!(zero.is_ascii_digit());
+ /// assert!(!percent.is_ascii_digit());
+ /// assert!(!space.is_ascii_digit());
+ /// assert!(!lf.is_ascii_digit());
+ /// assert!(!esc.is_ascii_digit());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_digit(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ D => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII hexadecimal digit:
+ ///
+ /// - U+0030 '0' ... U+0039 '9', or
+ /// - U+0041 'A' ... U+0046 'F', or
+ /// - U+0061 'a' ... U+0066 'f'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(uppercase_a.is_ascii_hexdigit());
+ /// assert!(!uppercase_g.is_ascii_hexdigit());
+ /// assert!(a.is_ascii_hexdigit());
+ /// assert!(!g.is_ascii_hexdigit());
+ /// assert!(zero.is_ascii_hexdigit());
+ /// assert!(!percent.is_ascii_hexdigit());
+ /// assert!(!space.is_ascii_hexdigit());
+ /// assert!(!lf.is_ascii_hexdigit());
+ /// assert!(!esc.is_ascii_hexdigit());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_hexdigit(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ D | Lx | Ux => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII punctuation character:
+ ///
+ /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or
+ /// - U+003A ... U+0040 `: ; < = > ? @`, or
+ /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or
+ /// - U+007B ... U+007E `{ | } ~`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(!uppercase_a.is_ascii_punctuation());
+ /// assert!(!uppercase_g.is_ascii_punctuation());
+ /// assert!(!a.is_ascii_punctuation());
+ /// assert!(!g.is_ascii_punctuation());
+ /// assert!(!zero.is_ascii_punctuation());
+ /// assert!(percent.is_ascii_punctuation());
+ /// assert!(!space.is_ascii_punctuation());
+ /// assert!(!lf.is_ascii_punctuation());
+ /// assert!(!esc.is_ascii_punctuation());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_punctuation(&self) -> bool {
+ if *self >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ P => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII graphic character:
+ /// U+0021 '@' ... U+007E '~'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(uppercase_a.is_ascii_graphic());
+ /// assert!(uppercase_g.is_ascii_graphic());
+ /// assert!(a.is_ascii_graphic());
+ /// assert!(g.is_ascii_graphic());
+ /// assert!(zero.is_ascii_graphic());
+ /// assert!(percent.is_ascii_graphic());
+ /// assert!(!space.is_ascii_graphic());
+ /// assert!(!lf.is_ascii_graphic());
+ /// assert!(!esc.is_ascii_graphic());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_graphic(&self) -> bool {
+ if *self >= 0x80 { return false; }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ Ux | U | Lx | L | D | P => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII whitespace character:
+ /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+ /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+ ///
+ /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+ /// whitespace][infra-aw]. There are several other definitions in
+ /// wide use. For instance, [the POSIX locale][pct] includes
+ /// U+000B VERTICAL TAB as well as all the above characters,
+ /// but—from the very same specification—[the default rule for
+ /// "field splitting" in the Bourne shell][bfs] considers *only*
+ /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+ ///
+ /// If you are writing a program that will process an existing
+ /// file format, check what that format's definition of whitespace is
+ /// before using this function.
+ ///
+ /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+ /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+ /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(!uppercase_a.is_ascii_whitespace());
+ /// assert!(!uppercase_g.is_ascii_whitespace());
+ /// assert!(!a.is_ascii_whitespace());
+ /// assert!(!g.is_ascii_whitespace());
+ /// assert!(!zero.is_ascii_whitespace());
+ /// assert!(!percent.is_ascii_whitespace());
+ /// assert!(space.is_ascii_whitespace());
+ /// assert!(lf.is_ascii_whitespace());
+ /// assert!(!esc.is_ascii_whitespace());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_whitespace(&self) -> bool {
+ if *self >= 0x80 { return false; }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ Cw | W => true,
+ _ => false
+ }
+ }
+
+ /// Checks if the value is an ASCII control character:
+ /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
+ /// Note that most ASCII whitespace characters are control
+ /// characters, but SPACE is not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = b'A';
+ /// let uppercase_g = b'G';
+ /// let a = b'a';
+ /// let g = b'g';
+ /// let zero = b'0';
+ /// let percent = b'%';
+ /// let space = b' ';
+ /// let lf = b'\n';
+ /// let esc = 0x1b_u8;
+ ///
+ /// assert!(!uppercase_a.is_ascii_control());
+ /// assert!(!uppercase_g.is_ascii_control());
+ /// assert!(!a.is_ascii_control());
+ /// assert!(!g.is_ascii_control());
+ /// assert!(!zero.is_ascii_control());
+ /// assert!(!percent.is_ascii_control());
+ /// assert!(!space.is_ascii_control());
+ /// assert!(lf.is_ascii_control());
+ /// assert!(esc.is_ascii_control());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_control(&self) -> bool {
+ if *self >= 0x80 { return false; }
+ match ASCII_CHARACTER_CLASS[*self as usize] {
+ C | Cw => true,
+ _ => false
+ }
+ }
}
#[lang = "u16"]
// Float -> Float
impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+static ASCII_LOWERCASE_MAP: [u8; 256] = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
+ b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
+ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
+ b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
+ b'@',
+
+ b'a', b'b', b'c', b'd', b'e', b'f', b'g',
+ b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
+ b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
+ b'x', b'y', b'z',
+
+ b'[', b'\\', b']', b'^', b'_',
+ b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
+ b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
+ b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
+ b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+static ASCII_UPPERCASE_MAP: [u8; 256] = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
+ b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
+ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
+ b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
+ b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+ b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+ b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+ b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
+ b'`',
+
+ b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+ b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+ b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+ b'X', b'Y', b'Z',
+
+ b'{', b'|', b'}', b'~', 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+enum AsciiCharacterClass {
+ C, // control
+ Cw, // control whitespace
+ W, // whitespace
+ D, // digit
+ L, // lowercase
+ Lx, // lowercase hex digit
+ U, // uppercase
+ Ux, // uppercase hex digit
+ P, // punctuation
+}
+use self::AsciiCharacterClass::*;
+
+static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [
+// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
+ C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
+ W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
+ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
+ P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
+ U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
+ P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
+ L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
+];
/// Implementing `Deref` for smart pointers makes accessing the data behind them
/// convenient, which is why they implement `Deref`. On the other hand, the
/// rules regarding `Deref` and [`DerefMut`] were designed specifically to
-/// accomodate smart pointers. Because of this, **`Deref` should only be
+/// accommodate smart pointers. Because of this, **`Deref` should only be
/// implemented for smart pointers** to avoid confusion.
///
/// For similar reasons, **this trait should never fail**. Failure during
/// Implementing `DerefMut` for smart pointers makes mutating the data behind
/// them convenient, which is why they implement `DerefMut`. On the other hand,
/// the rules regarding [`Deref`] and `DerefMut` were designed specifically to
-/// accomodate smart pointers. Because of this, **`DerefMut` should only be
+/// accommodate smart pointers. Because of this, **`DerefMut` should only be
/// implemented for smart pointers** to avoid confusion.
///
/// For similar reasons, **this trait should never fail**. Failure during
}
}
+#[stable(feature = "atomic_from", since = "1.23.0")]
+impl<T> From<*mut T> for AtomicPtr<T> {
+ #[inline]
+ fn from(p: *mut T) -> Self { Self::new(p) }
+}
+
#[cfg(target_has_atomic = "ptr")]
macro_rules! atomic_int {
($stable:meta, $const_unstable:meta,
}
}
+ #[stable(feature = "atomic_from", since = "1.23.0")]
+ impl From<$int_type> for $atomic_type {
+ #[inline]
+ fn from(v: $int_type) -> Self { Self::new(v) }
+ }
+
#[$stable_debug]
impl fmt::Debug for $atomic_type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
[] SuperPredicatesOfItem(DefId),
[] TraitDefOfItem(DefId),
[] AdtDefOfItem(DefId),
- [] IsDefaultImpl(DefId),
+ [] IsAutoImpl(DefId),
[] ImplTraitRef(DefId),
[] ImplPolarity(DefId),
[] ClosureKind(DefId),
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct DepNodeIndex {
- index: u32,
-}
-
-impl Idx for DepNodeIndex {
- fn new(idx: usize) -> Self {
- debug_assert!((idx & 0xFFFF_FFFF) == idx);
- DepNodeIndex { index: idx as u32 }
- }
- fn index(self) -> usize {
- self.index as usize
- }
-}
+newtype_index!(DepNodeIndex);
impl DepNodeIndex {
- const INVALID: DepNodeIndex = DepNodeIndex {
- index: ::std::u32::MAX,
- };
+ const INVALID: DepNodeIndex = DepNodeIndex(::std::u32::MAX);
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
use std::fmt;
use std::u32;
-#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)]
-pub struct CrateNum(u32);
+newtype_index!(CrateNum
+ {
+ derive[Debug]
+ ENCODABLE = custom
-impl Idx for CrateNum {
- fn new(value: usize) -> Self {
- assert!(value < (u32::MAX) as usize);
- CrateNum(value as u32)
- }
-
- fn index(self) -> usize {
- self.0 as usize
- }
-}
-
-/// Item definitions in the currently-compiled crate would have the CrateNum
-/// LOCAL_CRATE in their DefId.
-pub const LOCAL_CRATE: CrateNum = CrateNum(0);
+ /// Item definitions in the currently-compiled crate would have the CrateNum
+ /// LOCAL_CRATE in their DefId.
+ const LOCAL_CRATE = 0,
-/// Virtual crate for builtin macros
-// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s.
-pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(u32::MAX);
+ /// Virtual crate for builtin macros
+ // FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
+ // `CrateNum`s.
+ const BUILTIN_MACROS_CRATE = u32::MAX,
-/// A CrateNum value that indicates that something is wrong.
-pub const INVALID_CRATE: CrateNum = CrateNum(u32::MAX - 1);
+ /// A CrateNum value that indicates that something is wrong.
+ const INVALID_CRATE = u32::MAX - 1,
+ });
impl CrateNum {
pub fn new(x: usize) -> CrateNum {
///
/// Since the DefIndex is mostly treated as an opaque ID, you probably
/// don't have to care about these ranges.
-#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
- RustcDecodable, Hash, Copy)]
-pub struct DefIndex(u32);
+newtype_index!(DefIndex
+ {
+ DEBUG_FORMAT = custom,
-impl Idx for DefIndex {
- fn new(value: usize) -> Self {
- assert!(value < (u32::MAX) as usize);
- DefIndex(value as u32)
- }
+ /// The start of the "high" range of DefIndexes.
+ const DEF_INDEX_HI_START = 1 << 31,
- fn index(self) -> usize {
- self.0 as usize
- }
-}
+ /// The crate root is always assigned index 0 by the AST Map code,
+ /// thanks to `NodeCollector::new`.
+ const CRATE_DEF_INDEX = 0,
+ });
impl fmt::Debug for DefIndex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
impl DefIndex {
- #[inline]
- pub fn new(x: usize) -> DefIndex {
- assert!(x < (u32::MAX as usize));
- DefIndex(x as u32)
- }
-
#[inline]
pub fn from_u32(x: u32) -> DefIndex {
DefIndex(x)
}
}
-/// The start of the "high" range of DefIndexes.
-const DEF_INDEX_HI_START: DefIndex = DefIndex(1 << 31);
-
-/// The crate root is always assigned index 0 by the AST Map code,
-/// thanks to `NodeCollector::new`.
-pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
-
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub enum DefIndexAddressSpace {
Low = 0,
// visit_enum_def() takes care of visiting the Item's NodeId
visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
}
- ItemDefaultImpl(_, ref trait_ref) => {
+ ItemAutoImpl(_, ref trait_ref) => {
visitor.visit_id(item.id);
visitor.visit_trait_ref(trait_ref)
}
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
- ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
+ ItemTrait(.., ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
exported_macros: Vec<hir::MacroDef>,
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
- trait_default_impl: BTreeMap<DefId, NodeId>,
+ trait_auto_impl: BTreeMap<DefId, NodeId>,
is_generator: bool,
impl_items: BTreeMap::new(),
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
- trait_default_impl: BTreeMap::new(),
+ trait_auto_impl: BTreeMap::new(),
exported_macros: Vec::new(),
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
ItemKind::Union(_, ref generics) |
ItemKind::Enum(_, ref generics) |
ItemKind::Ty(_, ref generics) |
- ItemKind::Trait(_, ref generics, ..) => {
+ ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics.lifetimes.len();
self.lctx.type_def_lifetime_params.insert(def_id, count);
bodies: self.bodies,
body_ids,
trait_impls: self.trait_impls,
- trait_default_impl: self.trait_default_impl,
+ trait_auto_impl: self.trait_auto_impl,
}
}
let vdata = self.lower_variant_data(vdata);
hir::ItemUnion(vdata, self.lower_generics(generics))
}
- ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+ ItemKind::AutoImpl(unsafety, ref trait_ref) => {
let trait_ref = self.lower_trait_ref(trait_ref);
if let Def::Trait(def_id) = trait_ref.path.def {
- self.trait_default_impl.insert(def_id, id);
+ self.trait_auto_impl.insert(def_id, id);
}
- hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
+ hir::ItemAutoImpl(self.lower_unsafety(unsafety),
trait_ref)
}
ItemKind::Impl(unsafety,
self.lower_ty(ty),
new_impl_items)
}
- ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
+ ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds);
let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
- hir::ItemTrait(self.lower_unsafety(unsafety),
+ hir::ItemTrait(self.lower_is_auto(is_auto),
+ self.lower_unsafety(unsafety),
self.lower_generics(generics),
bounds,
items)
}
}
+ fn lower_is_auto(&mut self, a: IsAuto) -> hir::IsAuto {
+ match a {
+ IsAuto::Yes => hir::IsAuto::Yes,
+ IsAuto::No => hir::IsAuto::No,
+ }
+ }
+
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,
impl_items: _,
bodies: _,
trait_impls: _,
- trait_default_impl: _,
+ trait_auto_impl: _,
body_ids: _,
} = *krate;
// Pick the def data. This need not be unique, but the more
// information we encapsulate into
let def_data = match i.node {
- ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
+ ItemKind::AutoImpl(..) | ItemKind::Impl(..) =>
DefPathData::Impl,
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
CRATE_DEF_INDEX};
use ich::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::stable_hasher::StableHasher;
use serialize::{Encodable, Decodable, Encoder, Decoder};
use session::CrateDisambiguator;
self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
}
- pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
+ pub fn trait_auto_impl(&self, trait_did: DefId) -> Option<NodeId> {
self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls));
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
- self.forest.krate.trait_default_impl.get(&trait_did).cloned()
+ self.forest.krate.trait_auto_impl.get(&trait_did).cloned()
}
pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
- self.trait_default_impl(trait_did).is_some()
+ self.trait_auto_impl(trait_did).is_some()
}
/// Get the attributes on the krate. This is preferable to
ItemUnion(..) => "union",
ItemTrait(..) => "trait",
ItemImpl(..) => "impl",
- ItemDefaultImpl(..) => "default impl",
+ ItemAutoImpl(..) => "default impl",
};
format!("{} {}{}", item_str, path_str(), id_str)
}
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub bodies: BTreeMap<BodyId, Body>,
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
- pub trait_default_impl: BTreeMap<DefId, NodeId>,
+ pub trait_auto_impl: BTreeMap<DefId, NodeId>,
/// A list of the body ids written out in the order in which they
/// appear in the crate. If you're going to process all the bodies
pub has_implicit_self: bool,
}
+/// Is the trait definition an auto trait?
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum IsAuto {
+ Yes,
+ No
+}
+
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
- ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
+ ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
- // Default trait implementations
+ /// Auto trait implementations
///
/// `impl Trait for .. {}`
- ItemDefaultImpl(Unsafety, TraitRef),
+ ItemAutoImpl(Unsafety, TraitRef),
/// An implementation, eg `impl<A> Trait for Foo { .. }`
ItemImpl(Unsafety,
ImplPolarity,
ItemUnion(..) => "union",
ItemTrait(..) => "trait",
ItemImpl(..) |
- ItemDefaultImpl(..) => "item",
+ ItemAutoImpl(..) => "item",
}
}
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) |
- ItemTrait(_, ref generics, _, _) |
+ ItemTrait(_, _, ref generics, _, _) |
ItemImpl(_, _, _, ref generics, _, _, _)=> generics,
_ => return None
})
self.head(&visibility_qualified(&item.vis, "union"))?;
self.print_struct(struct_def, generics, item.name, item.span, true)?;
}
- hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
+ hir::ItemAutoImpl(unsafety, ref trait_ref) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_unsafety(unsafety)?;
}
self.bclose(item.span)?;
}
- hir::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => {
+ hir::ItemTrait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
+ self.print_is_auto(is_auto)?;
self.print_unsafety(unsafety)?;
self.word_nbsp("trait")?;
self.print_name(item.name)?;
hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
}
}
+
+ pub fn print_is_auto(&mut self, s: hir::IsAuto) -> io::Result<()> {
+ match s {
+ hir::IsAuto::Yes => self.word_nbsp("auto"),
+ hir::IsAuto::No => Ok(()),
+ }
+ }
}
// Dup'ed from parse::classify, but adapted for the HIR.
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) |
hir::ItemMod(..) |
- hir::ItemDefaultImpl(..) |
+ hir::ItemAutoImpl(..) |
hir::ItemTrait(..) |
hir::ItemImpl(..) |
hir::ItemTy(..) |
ItemEnum(enum_def, generics),
ItemStruct(variant_data, generics),
ItemUnion(variant_data, generics),
- ItemTrait(unsafety, generics, bounds, item_refs),
- ItemDefaultImpl(unsafety, trait_ref),
+ ItemTrait(is_auto, unsafety, generics, bounds, item_refs),
+ ItemAutoImpl(unsafety, trait_ref),
ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs)
});
MutImmutable
});
+impl_stable_hash_for!(enum hir::IsAuto {
+ Yes,
+ No
+});
impl_stable_hash_for!(enum hir::Unsafety {
Unsafe,
mir::TerminatorKind::Drop { .. } |
mir::TerminatorKind::DropAndReplace { .. } |
mir::TerminatorKind::Yield { .. } |
- mir::TerminatorKind::Call { .. } => false,
+ mir::TerminatorKind::Call { .. } |
+ mir::TerminatorKind::FalseEdges { .. } => false,
};
if hash_spans_unconditionally {
target.hash_stable(hcx, hasher);
cleanup.hash_stable(hcx, hasher);
}
+ mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => {
+ real_target.hash_stable(hcx, hasher);
+ for target in imaginary_targets {
+ target.hash_stable(hcx, hasher);
+ }
+ }
}
}
}
end_pos: _,
ref lines,
ref multibyte_chars,
+ ref non_narrow_chars,
} = *self;
name.hash_stable(hcx, hasher);
for &char_pos in multibyte_chars.iter() {
stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
}
+
+ let non_narrow_chars = non_narrow_chars.borrow();
+ non_narrow_chars.len().hash_stable(hcx, hasher);
+ for &char_pos in non_narrow_chars.iter() {
+ stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
+ }
}
}
(pos.0 - filemap_start.0, bytes as u32)
}
+
+fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar,
+ filemap_start: ::syntax_pos::BytePos)
+ -> (u32, u32) {
+ let pos = swc.pos();
+ let width = swc.width();
+
+ (pos.0 - filemap_start.0, width as u32)
+}
def_id: _,
unsafety,
paren_sugar,
- has_default_impl,
+ has_auto_impl,
def_path_hash,
} = *self;
unsafety.hash_stable(hcx, hasher);
paren_sugar.hash_stable(hcx, hasher);
- has_default_impl.hash_stable(hcx, hasher);
+ has_auto_impl.hash_stable(hcx, hasher);
def_path_hash.hash_stable(hcx, hasher);
}
}
match self {
&VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher),
- &VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher),
+ &VtableAutoImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher),
&VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher),
&VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher),
&VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher),
}
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
-for traits::VtableDefaultImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
+for traits::VtableAutoImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
- let traits::VtableDefaultImplData {
+ let traits::VtableAutoImplData {
trait_def_id,
ref nested,
} = *self;
flexibility, because perhaps the user intended for A and B to end up
as different types and not the same type.
-Pictorally, what this does is to take two distinct variables with
+Pictorially, what this does is to take two distinct variables with
(hopefully not completely) distinct type ranges and produce one with
the intersection.
use hir::def_id::DefId;
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
-use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants};
use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span};
values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>)
{
- let (expected_found, is_simple_error) = match values {
- None => (None, false),
+ let (expected_found, exp_found, is_simple_error) = match values {
+ None => (None, None, false),
Some(values) => {
- let is_simple_error = match values {
+ let (is_simple_error, exp_found) = match values {
ValuePairs::Types(exp_found) => {
- 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))
}
- _ => false,
+ _ => (false, None),
};
let vals = match self.values_str(&values) {
Some((expected, found)) => Some((expected, found)),
return
}
};
- (vals, is_simple_error)
+ (vals, exp_found, is_simple_error)
}
};
let span = cause.span;
+ diag.span_label(span, terr.to_string());
+ if let Some((sp, msg)) = secondary_span {
+ diag.span_label(sp, msg);
+ }
+
if let Some((expected, found)) = expected_found {
match (terr, is_simple_error, expected == found) {
(&TypeError::Sorts(ref values), false, true) => {
&format!(" ({})", values.expected.sort_string(self.tcx)),
&format!(" ({})", values.found.sort_string(self.tcx)));
}
- (_, false, _) => {
+ (_, false, _) => {
+ if let Some(exp_found) = exp_found {
+ let (def_id, ret_ty) = match exp_found.found.sty {
+ TypeVariants::TyFnDef(def, _) => {
+ (Some(def), Some(self.tcx.fn_sig(def).output()))
+ }
+ _ => (None, None)
+ };
+
+ let exp_is_struct = match exp_found.expected.sty {
+ TypeVariants::TyAdt(def, _) => def.is_struct(),
+ _ => false
+ };
+
+ if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) {
+ if exp_is_struct && exp_found.expected == ret_ty.0 {
+ let message = format!(
+ "did you mean `{}(/* fields */)`?",
+ self.tcx.item_path_str(def_id)
+ );
+ diag.span_label(cause.span, message);
+ }
+ }
+ }
+
diag.note_expected_found(&"type", expected, found);
}
_ => (),
}
}
- diag.span_label(span, terr.to_string());
- if let Some((sp, msg)) = secondary_span {
- diag.span_label(sp, msg);
- }
-
self.note_error_origin(diag, &cause);
self.check_and_note_conflicting_crates(diag, terr, span);
self.tcx.note_and_explain_type_err(diag, terr, span);
.filter(|&&r| !skol_resolution_map.contains_key(r))
.cloned()
.next()
- .expect("no representative region");
+ .unwrap_or_else(|| {
+ bug!("no representative region for `{:?}` in `{:?}`",
+ skol, regions)
+ });
(skol, representative)
})
use graphviz as dot;
use hir::def_id::DefIndex;
+use rustc_data_structures::indexed_vec::Idx;
use ty;
use middle::free_region::RegionRelations;
use middle::region;
use std::rc::Rc;
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticId};
use hir::def_id::{CrateNum, LOCAL_CRATE};
use hir::intravisit::{self, FnKind};
use hir;
use session::Session;
+#[cfg(stage0)]
use std::ascii::AsciiExt;
use std::hash;
use syntax::ast;
}
}
+ err.code(DiagnosticId::Lint(name));
+
// Check for future incompatibility lints and issue a stronger warning.
let lints = sess.lint_store.borrow();
if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTrait(..) |
- hir::ItemDefaultImpl(..) |
+ hir::ItemAutoImpl(..) |
hir::ItemImpl(..) => self.tcx.sess.codemap().def_span(item.span),
_ => item.span,
};
CharImplItem, "char", char_impl;
StrImplItem, "str", str_impl;
SliceImplItem, "slice", slice_impl;
+ SliceU8ImplItem, "slice_u8", slice_u8_impl;
ConstPtrImplItem, "const_ptr", const_ptr_impl;
MutPtrImplItem, "mut_ptr", mut_ptr_impl;
I8ImplItem, "i8", i8_impl;
hir::ItemMod(..) | hir::ItemForeignMod(..) |
hir::ItemImpl(..) | hir::ItemTrait(..) |
hir::ItemStruct(..) | hir::ItemEnum(..) |
- hir::ItemUnion(..) | hir::ItemDefaultImpl(..) |
+ hir::ItemUnion(..) | hir::ItemAutoImpl(..) |
hir::ItemGlobalAsm(..) => {}
}
}
newtype_index!(FirstStatementIndex
{
- DEBUG_FORMAT = "{}",
- MAX = SCOPE_DATA_REMAINDER_MAX,
+ pub idx
+ MAX = SCOPE_DATA_REMAINDER_MAX
});
impl From<ScopeData> for Scope {
hir::ItemExternCrate(_) |
hir::ItemUse(..) |
hir::ItemMod(..) |
- hir::ItemDefaultImpl(..) |
+ hir::ItemAutoImpl(..) |
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) => {
// These sorts of items have no lifetime parameters at all.
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) |
- hir::ItemTrait(_, ref generics, ..) |
+ hir::ItemTrait(_, _, ref generics, ..) |
hir::ItemImpl(_, _, _, ref generics, ..) => {
// These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node {
hir::ItemUnion(_, ref generics) |
hir::ItemEnum(_, ref generics) |
hir::ItemTy(_, ref generics) |
- hir::ItemTrait(_, ref generics, ..) => {
+ hir::ItemTrait(_, _, ref generics, ..) => {
let result = object_lifetime_defaults_for_item(hir_map, generics);
// Debugging aid.
index += 1; // Self comes first.
}
match parent.node {
- hir::ItemTrait(_, ref generics, ..) |
+ hir::ItemTrait(_, _, ref generics, ..) |
hir::ItemImpl(_, _, _, ref generics, ..) => {
index += (generics.lifetimes.len() + generics.ty_params.len()) as u32;
}
/// Indicates the end of the dropping of a generator
GeneratorDrop,
+
+ FalseEdges {
+ real_target: BasicBlock,
+ imaginary_targets: Vec<BasicBlock>
+ },
}
impl<'tcx> Terminator<'tcx> {
}
Assert { target, cleanup: Some(unwind), .. } => vec![target, unwind].into_cow(),
Assert { ref target, .. } => slice::ref_slice(target).into_cow(),
+ FalseEdges { ref real_target, ref imaginary_targets } => {
+ let mut s = vec![*real_target];
+ s.extend_from_slice(imaginary_targets);
+ s.into_cow()
+ }
}
}
vec![target]
}
Assert { ref mut target, cleanup: Some(ref mut unwind), .. } => vec![target, unwind],
- Assert { ref mut target, .. } => vec![target]
+ Assert { ref mut target, .. } => vec![target],
+ FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
+ let mut s = vec![real_target];
+ s.extend(imaginary_targets.iter_mut());
+ s
+ }
}
}
}
}
write!(fmt, ")")
- }
+ },
+ FalseEdges { .. } => write!(fmt, "falseEdges")
}
}
}
Assert { cleanup: None, .. } => vec!["".into()],
Assert { .. } =>
- vec!["success".into_cow(), "unwind".into_cow()]
+ vec!["success".into_cow(), "unwind".into_cow()],
+ FalseEdges { ref imaginary_targets, .. } => {
+ let mut l = vec!["real".into()];
+ l.resize(imaginary_targets.len() + 1, "imaginary".into());
+ l
+ }
}
}
}
newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
+
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
Value {
Resume => Resume,
Return => Return,
Unreachable => Unreachable,
+ FalseEdges { real_target, ref imaginary_targets } =>
+ FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }
};
Terminator {
source_info: self.source_info,
Resume |
Return |
GeneratorDrop |
- Unreachable => false
+ Unreachable |
+ FalseEdges { .. } => false
}
}
}
self.visit_operand(value, source_location);
self.visit_branch(block, resume);
drop.map(|t| self.visit_branch(block, t));
+
}
+ TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
+ self.visit_branch(block, real_target);
+ for target in imaginary_targets {
+ self.visit_branch(block, *target);
+ }
+ }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorOutputType {
HumanReadable(ColorConfig),
- Json,
+ Json(bool),
Short(ColorConfig),
}
outputs
});
-pub const RUST_CGU_EXT: &str = "rust-cgu";
+pub const RUST_CGU_EXT: &str = "rcgu";
impl OutputFilenames {
pub fn path(&self, flavor: OutputType) -> PathBuf {
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
Some("human") => ErrorOutputType::HumanReadable(color),
- Some("json") => ErrorOutputType::Json,
+ Some("json") => ErrorOutputType::Json(false),
+ Some("pretty-json") => ErrorOutputType::Json(true),
Some("short") => ErrorOutputType::Short(color),
None => ErrorOutputType::HumanReadable(color),
let debugging_opts = build_debugging_options(matches, error_format);
+ if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
+ early_error(ErrorOutputType::Json(false),
+ "--error-format=pretty-json is unstable");
+ }
+
let mut output_types = BTreeMap::new();
if !debugging_opts.parse_only {
for list in matches.opt_strs("emit") {
let mut v5 = super::basic_options();
// Reference
- v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
// Native changed
- v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json);
- v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
// Crate changed
- v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json);
- v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
// Dependency changed
- v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json);
- v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
// Framework changed
- v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json);
- v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
+ v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
// All changed
- v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json);
+ v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json(false));
assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
let mut v4 = super::basic_options();
// Reference
- v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
-
- v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
-
- v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
- v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
-
- v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
- v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
- v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
- v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
- v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
+ v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
+
+ v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
+
+ v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
+
+ v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json(false));
+ v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json(false));
assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
use util::common::{duration_to_secs_str, ErrorReported};
use syntax::ast::NodeId;
-use errors::{self, DiagnosticBuilder};
+use errors::{self, DiagnosticBuilder, DiagnosticId};
use errors::emitter::{Emitter, EmitterWriter};
use syntax::json::JsonEmitter;
use syntax::feature_gate;
pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
}
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_err_with_code(sp, msg, code)
}
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_err(msg)
}
- pub fn struct_err_with_code<'a>(&'a self, msg: &str, code: &str) -> DiagnosticBuilder<'a> {
+ pub fn struct_err_with_code<'a>(
+ &'a self,
+ msg: &str,
+ code: DiagnosticId,
+ ) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_err_with_code(msg, code)
}
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
panic!(self.diagnostic().span_fatal(sp, msg))
}
- pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) -> ! {
+ pub fn span_fatal_with_code<S: Into<MultiSpan>>(
+ &self,
+ sp: S,
+ msg: &str,
+ code: DiagnosticId,
+ ) -> ! {
panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
}
pub fn fatal(&self, msg: &str) -> ! {
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.diagnostic().span_err(sp, msg)
}
- pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.diagnostic().span_err_with_code(sp, &msg, code)
}
pub fn err(&self, msg: &str) {
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.diagnostic().span_warn(sp, msg)
}
- pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.diagnostic().span_warn_with_code(sp, msg, code)
}
pub fn warn(&self, msg: &str) {
match self.opts.error_format {
// when outputting JSON for tool consumption, the tool might want
// the duplicates
- config::ErrorOutputType::Json => {
+ config::ErrorOutputType::Json(_) => {
do_method()
},
_ => {
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false))
}
- (config::ErrorOutputType::Json, None) => {
- Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
+ (config::ErrorOutputType::Json(pretty), None) => {
+ Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
}
- (config::ErrorOutputType::Json, Some(dst)) => {
- Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone()))
+ (config::ErrorOutputType::Json(pretty), Some(dst)) => {
+ Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
}
(config::ErrorOutputType::Short(color_config), None) => {
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true))
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false))
}
- config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+ config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Short(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, true))
}
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false))
}
- config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
+ config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Short(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, true))
}
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
- /// Vtable for default trait implementations
+ /// Vtable for auto trait implementations
/// This carries the information and nested obligations with regards
- /// to a default implementation for a trait `Trait`. The nested obligations
+ /// to an auto implementation for a trait `Trait`. The nested obligations
/// ensure the trait implementation holds for all the constituent types.
- VtableDefaultImpl(VtableDefaultImplData<N>),
+ VtableAutoImpl(VtableAutoImplData<N>),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter. The `Vec<N>` represents the
}
#[derive(Clone)]
-pub struct VtableDefaultImplData<N> {
+pub struct VtableAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>
}
VtableImpl(i) => i.nested,
VtableParam(n) => n,
VtableBuiltin(i) => i.nested,
- VtableDefaultImpl(d) => d.nested,
+ VtableAutoImpl(d) => d.nested,
VtableClosure(c) => c.nested,
VtableGenerator(c) => c.nested,
VtableObject(d) => d.nested,
&mut VtableImpl(ref mut i) => &mut i.nested,
&mut VtableParam(ref mut n) => n,
&mut VtableBuiltin(ref mut i) => &mut i.nested,
- &mut VtableDefaultImpl(ref mut d) => &mut d.nested,
+ &mut VtableAutoImpl(ref mut d) => &mut d.nested,
&mut VtableGenerator(ref mut c) => &mut c.nested,
&mut VtableClosure(ref mut c) => &mut c.nested,
&mut VtableObject(ref mut d) => &mut d.nested,
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
- VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData {
+ VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData {
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
// projection. And the projection where clause is handled
// in `assemble_candidates_from_param_env`.
}
- super::VtableDefaultImpl(..) |
+ super::VtableAutoImpl(..) |
super::VtableBuiltin(..) => {
// These traits have no associated types.
span_bug!(
confirm_fn_pointer_candidate(selcx, obligation, data),
super::VtableObject(_) =>
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
- super::VtableDefaultImpl(..) |
+ super::VtableAutoImpl(..) |
super::VtableParam(..) |
super::VtableBuiltin(..) =>
// we don't create Select candidates with this kind of resolution
use super::Selection;
use super::SelectionResult;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, VtableGenerator,
- VtableFnPointer, VtableObject, VtableDefaultImpl};
+ VtableFnPointer, VtableObject, VtableAutoImpl};
use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableGeneratorData,
- VtableClosureData, VtableDefaultImplData, VtableFnPointerData};
+ VtableClosureData, VtableAutoImplData, VtableFnPointerData};
use super::util;
use dep_graph::{DepNodeIndex, DepKind};
BuiltinCandidate { has_nested: bool },
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(DefId),
- DefaultImplCandidate(DefId),
+ AutoImplCandidate(DefId),
/// This is a trait matching with a projected type as `Self`, and
/// we found an applicable bound in the trait definition.
}
}
ImplCandidate(def_id) => ImplCandidate(def_id),
- DefaultImplCandidate(def_id) => DefaultImplCandidate(def_id),
+ AutoImplCandidate(def_id) => AutoImplCandidate(def_id),
ProjectionCandidate => ProjectionCandidate,
FnPointerCandidate => FnPointerCandidate,
ObjectCandidate => ObjectCandidate,
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
let result = match predicate {
ty::Predicate::Trait(ref data) => {
- self.tcx().trait_has_default_impl(data.def_id())
+ self.tcx().trait_is_auto(data.def_id())
}
_ => {
false
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
- // Default implementations have lower priority, so we only
+ // Auto implementations have lower priority, so we only
// consider triggering a default if there is no other impl that can apply.
if candidates.vec.is_empty() {
- self.assemble_candidates_from_default_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
Ok(())
}
- fn assemble_candidates_from_default_impls(&mut self,
+ fn assemble_candidates_from_auto_impls(&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>)
-> Result<(), SelectionError<'tcx>>
{
// OK to skip binder here because the tests we do below do not involve bound regions
let self_ty = *obligation.self_ty().skip_binder();
- debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty);
+ debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
let def_id = obligation.predicate.def_id();
- if self.tcx().trait_has_default_impl(def_id) {
+ if self.tcx().trait_is_auto(def_id) {
match self_ty.sty {
ty::TyDynamic(..) => {
// For object types, we don't know what the closed
// this path.
}
ty::TyInfer(ty::TyVar(_)) => {
- // the defaulted impl might apply, we don't know
+ // the auto impl might apply, we don't know
candidates.ambiguous = true;
}
_ => {
- candidates.vec.push(DefaultImplCandidate(def_id.clone()))
+ candidates.vec.push(AutoImplCandidate(def_id.clone()))
}
}
}
match other.candidate {
ObjectCandidate |
ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
- DefaultImplCandidate(..) => {
+ AutoImplCandidate(..) => {
bug!(
"default implementations shouldn't be recorded \
when there are other valid candidates");
Ok(VtableParam(obligations))
}
- DefaultImplCandidate(trait_def_id) => {
- let data = self.confirm_default_impl_candidate(obligation, trait_def_id);
- Ok(VtableDefaultImpl(data))
+ AutoImplCandidate(trait_def_id) => {
+ let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
+ Ok(VtableAutoImpl(data))
}
ImplCandidate(impl_def_id) => {
///
/// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
/// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
- fn confirm_default_impl_candidate(&mut self,
+ fn confirm_auto_impl_candidate(&mut self,
obligation: &TraitObligation<'tcx>,
trait_def_id: DefId)
- -> VtableDefaultImplData<PredicateObligation<'tcx>>
+ -> VtableAutoImplData<PredicateObligation<'tcx>>
{
- debug!("confirm_default_impl_candidate({:?}, {:?})",
+ debug!("confirm_auto_impl_candidate({:?}, {:?})",
obligation,
trait_def_id);
// binder is moved below
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
let types = self.constituent_types_for_ty(self_ty);
- self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types))
+ self.vtable_auto_impl(obligation, trait_def_id, ty::Binder(types))
}
- /// See `confirm_default_impl_candidate`
- fn vtable_default_impl(&mut self,
+ /// See `confirm_auto_impl_candidate`
+ fn vtable_auto_impl(&mut self,
obligation: &TraitObligation<'tcx>,
trait_def_id: DefId,
nested: ty::Binder<Vec<Ty<'tcx>>>)
- -> VtableDefaultImplData<PredicateObligation<'tcx>>
+ -> VtableAutoImplData<PredicateObligation<'tcx>>
{
- debug!("vtable_default_impl: nested={:?}", nested);
+ debug!("vtable_auto_impl: nested={:?}", nested);
let cause = obligation.derived_cause(BuiltinDerivedObligation);
let mut obligations = self.collect_predicates_for_types(
obligations.extend(trait_obligations);
- debug!("vtable_default_impl: obligations={:?}", obligations);
+ debug!("vtable_auto_impl: obligations={:?}", obligations);
- VtableDefaultImplData {
+ VtableAutoImplData {
trait_def_id,
nested: obligations
}
super::VtableImpl(ref v) =>
write!(f, "{:?}", v),
- super::VtableDefaultImpl(ref t) =>
+ super::VtableAutoImpl(ref t) =>
write!(f, "{:?}", t),
super::VtableClosure(ref d) =>
}
}
-impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData<N> {
+impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})",
+ write!(f, "VtableAutoImplData(trait_def_id={:?}, nested={:?})",
self.trait_def_id,
self.nested)
}
})
})
}
- traits::VtableDefaultImpl(t) => Some(traits::VtableDefaultImpl(t)),
+ traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
traits::VtableGenerator(traits::VtableGeneratorData {
closure_def_id,
substs,
}
}
-impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- traits::VtableDefaultImplData {
+ traits::VtableAutoImplData {
trait_def_id: self.trait_def_id,
nested: self.nested.fold_with(folder),
}
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
- traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
+ traits::VtableAutoImpl(ref t) => traits::VtableAutoImpl(t.fold_with(folder)),
traits::VtableGenerator(ref d) => {
traits::VtableGenerator(d.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
traits::VtableImpl(ref v) => v.visit_with(visitor),
- traits::VtableDefaultImpl(ref t) => t.visit_with(visitor),
+ traits::VtableAutoImpl(ref t) => t.visit_with(visitor),
traits::VtableGenerator(ref d) => d.visit_with(visitor),
traits::VtableClosure(ref d) => d.visit_with(visitor),
traits::VtableFnPointer(ref d) => d.visit_with(visitor),
let substituted = self.erase_regions(&substituted);
AssociatedTypeNormalizer::new(self).fold(&substituted)
}
+
+ pub fn trans_apply_param_substs_env<T>(
+ self,
+ param_substs: &Substs<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: &T,
+ ) -> T
+ where
+ T: TransNormalize<'tcx>,
+ {
+ debug!(
+ "apply_param_substs_env(param_substs={:?}, value={:?}, param_env={:?})",
+ param_substs,
+ value,
+ param_env,
+ );
+ let substituted = value.subst(self, param_substs);
+ let substituted = self.erase_regions(&substituted);
+ AssociatedTypeNormalizerEnv::new(self, param_env).fold(&substituted)
+ }
}
struct AssociatedTypeNormalizer<'a, 'gcx: 'a> {
}
}
+struct AssociatedTypeNormalizerEnv<'a, 'gcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'gcx>,
+ param_env: ty::ParamEnv<'gcx>,
+}
+
+impl<'a, 'gcx> AssociatedTypeNormalizerEnv<'a, 'gcx> {
+ fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>, param_env: ty::ParamEnv<'gcx>) -> Self {
+ Self { tcx, param_env }
+ }
+
+ fn fold<T: TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
+ if !value.has_projections() {
+ value.clone()
+ } else {
+ value.fold_with(self)
+ }
+ }
+}
+
+impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizerEnv<'a, 'gcx> {
+ fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
+ if !ty.has_projections() {
+ ty
+ } else {
+ debug!("AssociatedTypeNormalizerEnv: ty={:?}", ty);
+ self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
+ }
+ }
+}
+
// Implement DepTrackingMapConfig for `trait_cache`
pub struct TraitSelectionCache<'tcx> {
data: PhantomData<&'tcx ()>
resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
} else {
let ty = tcx.type_of(def_id);
- let item_type = tcx.trans_apply_param_substs(substs, &ty);
+ let item_type = tcx.trans_apply_param_substs_env(substs, param_env, &ty);
let def = match item_type.sty {
ty::TyFnDef(..) if {
None
}
}
- traits::VtableDefaultImpl(..) | traits::VtableParam(..) => None
+ traits::VtableAutoImpl(..) | traits::VtableParam(..) => None
}
}
// Always use types for non-local impls, where types are always
// available, and filename/line-number is mostly uninteresting.
- let use_types = !self.is_default_impl(impl_def_id) && (!impl_def_id.is_local() || {
+ let use_types = !self.is_auto_impl(impl_def_id) && (!impl_def_id.is_local() || {
// Otherwise, use filename/line-number if forced.
let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
!force_no_types
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
[] fn is_foreign_item: IsForeignItem(DefId) -> bool,
- /// True if this is a default impl (aka impl Foo for ..)
- [] fn is_default_impl: IsDefaultImpl(DefId) -> bool,
+ /// True if this is an auto impl (aka impl Foo for ..)
+ [] fn is_auto_impl: IsAutoImpl(DefId) -> bool,
/// Get a map with the variance of every item; use `item_variance`
/// instead.
DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
- DepKind::IsDefaultImpl => { force!(is_default_impl, def_id!()); }
+ DepKind::IsAutoImpl => { force!(is_auto_impl, def_id!()); }
DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); }
DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); }
DepKind::ClosureKind => { force!(closure_kind, def_id!()); }
const IS_FUNDAMENTAL = 1 << 2;
const IS_UNION = 1 << 3;
const IS_BOX = 1 << 4;
+ /// Indicates whether this abstract data type will be expanded on in future (new
+ /// fields/variants) and as such, whether downstream crates must match exhaustively on the
+ /// fields/variants of this data type.
+ ///
+ /// See RFC 2008 (https://github.com/rust-lang/rfcs/pull/2008).
+ const IS_NON_EXHAUSTIVE = 1 << 5;
}
}
if Some(did) == tcx.lang_items().owned_box() {
flags = flags | AdtFlags::IS_BOX;
}
+ if tcx.has_attr(did, "non_exhaustive") {
+ flags = flags | AdtFlags::IS_NON_EXHAUSTIVE;
+ }
match kind {
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
self.flags.intersects(AdtFlags::IS_ENUM)
}
+ #[inline]
+ pub fn is_non_exhaustive(&self) -> bool {
+ self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE)
+ }
+
/// Returns the kind of the ADT - Struct or Enum.
#[inline]
pub fn adt_kind(&self) -> AdtKind {
self.get_attrs(did).iter().any(|item| item.check_name(attr))
}
- pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
- self.trait_def(trait_def_id).has_default_impl
+ /// Returns true if this is an `auto trait`.
+ ///
+ /// NB. For a limited time, also returns true if `impl Trait for .. { }` is in the code-base.
+ pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
+ self.trait_def(trait_def_id).has_auto_impl
}
pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> {
/// be usable with the sugar (or without it).
pub paren_sugar: bool,
- pub has_default_impl: bool,
+ pub has_auto_impl: bool,
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
/// recomputed all the time.
pub fn new(def_id: DefId,
unsafety: hir::Unsafety,
paren_sugar: bool,
- has_default_impl: bool,
+ has_auto_impl: bool,
def_path_hash: DefPathHash)
-> TraitDef {
TraitDef {
def_id,
paren_sugar,
unsafety,
- has_default_impl,
+ has_auto_impl,
def_path_hash,
}
}
let no_mangle = Symbol::intern("no_mangle");
let no_mangle = self.cx.meta_word(self.span, no_mangle);
+
+ let special = Symbol::intern("rustc_std_internal_symbol");
+ let special = self.cx.meta_word(self.span, special);
vec![
self.cx.attribute(self.span, linkage),
self.cx.attribute(self.span, no_mangle),
+ self.cx.attribute(self.span, special),
]
}
use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax_pos::{MultiSpan, Span};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticId};
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor};
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a>
{
self.tcx.sess.struct_span_err_with_code(sp, msg, code)
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
s: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
self.tcx.sess.struct_span_err_with_code(s, msg, code)
}
- pub fn span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, code: &str) {
+ pub fn span_err_with_code<S: Into<MultiSpan>>(
+ &self,
+ s: S,
+ msg: &str,
+ code: DiagnosticId,
+ ) {
self.tcx.sess.span_err_with_code(s, msg, code);
}
}
}
+ fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
+ match ty.sty {
+ ty::TyAdt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
+ _ => false,
+ }
+ }
+
+ fn is_local(&self, ty: Ty<'tcx>) -> bool {
+ match ty.sty {
+ ty::TyAdt(adt_def, ..) => adt_def.did.is_local(),
+ _ => false,
+ }
+ }
+
fn is_variant_uninhabited(&self,
variant: &'tcx ty::VariantDef,
substs: &'tcx ty::subst::Substs<'tcx>)
let is_privately_empty =
all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
- debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors,
- is_privately_empty);
- if missing_ctors.is_empty() && !is_privately_empty {
+ let is_declared_nonexhaustive =
+ cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
+ debug!("missing_ctors={:?} is_privately_empty={:?} is_declared_nonexhaustive={:?}",
+ missing_ctors, is_privately_empty, is_declared_nonexhaustive);
+
+ // For privately empty and non-exhaustive enums, we work as if there were an "extra"
+ // `_` constructor for the type, so we can never match over all constructors.
+ let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
+
+ if missing_ctors.is_empty() && !is_non_exhaustive {
all_ctors.into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
match is_useful(cx, &matrix, &v[1..], witness) {
UsefulWithWitness(pats) => {
let cx = &*cx;
- let new_witnesses = if used_ctors.is_empty() {
+ // In this case, there's at least one "free"
+ // constructor that is only matched against by
+ // wildcard patterns.
+ //
+ // There are 2 ways we can report a witness here.
+ // Commonly, we can report all the "free"
+ // constructors as witnesses, e.g. if we have:
+ //
+ // ```
+ // enum Direction { N, S, E, W }
+ // let Direction::N = ...;
+ // ```
+ //
+ // we can report 3 witnesses: `S`, `E`, and `W`.
+ //
+ // However, there are 2 cases where we don't want
+ // to do this and instead report a single `_` witness:
+ //
+ // 1) If the user is matching against a non-exhaustive
+ // enum, there is no point in enumerating all possible
+ // variants, because the user can't actually match
+ // against them himself, e.g. in an example like:
+ // ```
+ // let err: io::ErrorKind = ...;
+ // match err {
+ // io::ErrorKind::NotFound => {},
+ // }
+ // ```
+ // we don't want to show every possible IO error,
+ // but instead have `_` as the witness (this is
+ // actually *required* if the user specified *all*
+ // IO errors, but is probably what we want in every
+ // case).
+ //
+ // 2) If the user didn't actually specify a constructor
+ // in this arm, e.g. in
+ // ```
+ // let x: (Direction, Direction, bool) = ...;
+ // let (_, _, false) = x;
+ // ```
+ // we don't want to show all 16 possible witnesses
+ // `(<direction-1>, <direction-2>, true)` - we are
+ // satisfied with `(_, _, true)`. In this case,
+ // `used_ctors` is empty.
+ let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
// All constructors are unused. Add wild patterns
// rather than each individual constructor
pats.into_iter().map(|mut witness| {
// Use default constants
($name:ident) => (
newtype_index!(
- @type[$name]
- @max[::std::u32::MAX]
- @debug_format["{}"]);
+ // Leave out derives marker so we can use its absence to ensure it comes first
+ @type [$name]
+ @max [::std::u32::MAX]
+ @debug_format ["{}"]);
);
// Define any constants
($name:ident { $($tokens:tt)+ }) => (
newtype_index!(
- @type[$name]
- @max[::std::u32::MAX]
- @debug_format["{}"]
- $($tokens)+);
+ // Leave out derives marker so we can use its absence to ensure it comes first
+ @type [$name]
+ @max [::std::u32::MAX]
+ @debug_format ["{}"]
+ $($tokens)+);
);
// ---- private rules ----
// Base case, user-defined constants (if any) have already been defined
- (@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]) => (
- #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
- RustcEncodable, RustcDecodable)]
- pub struct $type(pub u32);
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]) => (
+ #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
+ pub struct $type($($pub)* u32);
impl Idx for $type {
fn new(value: usize) -> Self {
assert!(value < ($max) as usize);
$type(value as u32)
}
+
fn index(self) -> usize {
self.0 as usize
}
}
+ newtype_index!(
+ @handle_debug
+ @derives [$($derives,)*]
+ @type [$type]
+ @debug_format [$debug_format]);
+ );
+
+ // base case for handle_debug where format is custom. No Debug implementation is emitted.
+ (@handle_debug
+ @derives [$($_derives:ident,)*]
+ @type [$type:ident]
+ @debug_format [custom]) => ();
+
+ // base case for handle_debug, no debug overrides found, so use default
+ (@handle_debug
+ @derives []
+ @type [$type:ident]
+ @debug_format [$debug_format:tt]) => (
impl ::std::fmt::Debug for $type {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(fmt, $debug_format, self.0)
}
);
+ // Debug is requested for derive, don't generate any Debug implementation.
+ (@handle_debug
+ @derives [Debug, $($derives:ident,)*]
+ @type [$type:ident]
+ @debug_format [$debug_format:tt]) => ();
+
+ // It's not Debug, so just pop it off the front of the derives stack and check the rest.
+ (@handle_debug
+ @derives [$_derive:ident, $($derives:ident,)*]
+ @type [$type:ident]
+ @debug_format [$debug_format:tt]) => (
+ newtype_index!(
+ @handle_debug
+ @derives [$($derives,)*]
+ @type [$type]
+ @debug_format [$debug_format]);
+ );
+
+ // Handle the case where someone wants to make the internal field public
+ (@type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ pub idx
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @pub [pub]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
+ // The default case is that the internal field is private
+ (@type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @pub []
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
+ // Append comma to end of derives list if it's missing
+ (@pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ derive [$($derives:ident),*]
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ derive [$($derives,)*]
+ $($tokens)*);
+ );
+
+ // By not including the @derives marker in this list nor in the default args, we can force it
+ // to come first if it exists. When encodable is custom, just use the derives list as-is.
+ (@pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ derive [$($derives:ident,)+]
+ ENCODABLE = custom
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives [$($derives,)+]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
+ // By not including the @derives marker in this list nor in the default args, we can force it
+ // to come first if it exists. When encodable isn't custom, add serialization traits by default.
+ (@pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ derive [$($derives:ident,)+]
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives [$($derives,)+ RustcDecodable, RustcEncodable,]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
+ // The case where no derives are added, but encodable is overriden. Don't
+ // derive serialization traits
+ (@pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ ENCODABLE = custom
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives []
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
+ // The case where no derives are added, add serialization derives by default
+ (@pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives [RustcDecodable, RustcEncodable,]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
+ );
+
// Rewrite final without comma to one that includes comma
- (@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
- $name:ident = $constant:expr) => (
- newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $name = $constant,);
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ $name:ident = $constant:expr) => (
+ newtype_index!(
+ @derives [$($derives,)*]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $name = $constant,);
);
// Rewrite final const without comma to one that includes comma
- (@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
- const $name:ident = $constant:expr) => (
- newtype_index!(@type[$type]
- @max[$max]
- @debug_format[$debug_format]
- const $name = $constant,);
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$_max:expr]
+ @debug_format [$debug_format:tt]
+ $(#[doc = $doc:expr])*
+ const $name:ident = $constant:expr) => (
+ newtype_index!(
+ @derives [$($derives,)*]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $(#[doc = $doc])* const $name = $constant,);
);
// Replace existing default for max
- (@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
- MAX = $max:expr, $($tokens:tt)*) => (
- newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$_max:expr]
+ @debug_format [$debug_format:tt]
+ MAX = $max:expr,
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives [$($derives,)*]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
);
// Replace existing default for debug_format
- (@type[$type:ident] @max[$max:expr] @debug_format[$_debug_format:expr]
- DEBUG_FORMAT = $debug_format:expr, $($tokens:tt)*) => (
- newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$_debug_format:tt]
+ DEBUG_FORMAT = $debug_format:tt,
+ $($tokens:tt)*) => (
+ newtype_index!(
+ @derives [$($derives,)*]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
);
- // Assign a user-defined constant (as final param)
- (@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
- const $name:ident = $constant:expr, $($tokens:tt)*) => (
+ // Assign a user-defined constant
+ (@derives [$($derives:ident,)*]
+ @pub [$($pub:tt)*]
+ @type [$type:ident]
+ @max [$max:expr]
+ @debug_format [$debug_format:tt]
+ $(#[doc = $doc:expr])*
+ const $name:ident = $constant:expr,
+ $($tokens:tt)*) => (
+ $(#[doc = $doc])*
pub const $name: $type = $type($constant);
- newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
+ newtype_index!(
+ @derives [$($derives,)*]
+ @pub [$($pub)*]
+ @type [$type]
+ @max [$max]
+ @debug_format [$debug_format]
+ $($tokens)*);
);
}
hir::ItemUnion(..) |
hir::ItemTrait(..) |
hir::ItemImpl(..) |
- hir::ItemDefaultImpl(..) => None,
+ hir::ItemAutoImpl(..) => None,
hir::ItemMod(ref m) => search_mod(this, m, idx, names),
};
pub struct Diagnostic {
pub level: Level,
pub message: Vec<(String, Style)>,
- pub code: Option<String>,
+ pub code: Option<DiagnosticId>,
pub span: MultiSpan,
pub children: Vec<SubDiagnostic>,
pub suggestions: Vec<CodeSuggestion>,
}
+#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DiagnosticId {
+ Error(String),
+ Lint(String),
+}
+
/// For example a note attached to an error.
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct SubDiagnostic {
Diagnostic::new_with_code(level, None, message)
}
- pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self {
+ pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
Diagnostic {
level,
message: vec![(message.to_owned(), Style::NoStyle)],
self
}
- pub fn code(&mut self, s: String) -> &mut Self {
+ pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
self.code = Some(s);
self
}
// except according to those terms.
use Diagnostic;
+use DiagnosticId;
use DiagnosticStyledString;
use Level;
suggestions: Vec<String>)
-> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
- forward!(pub fn code(&mut self, s: String) -> &mut Self);
+ forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
/// Convenience function for internal use, clients should use one of the
/// struct_* methods on Handler.
/// struct_* methods on Handler.
pub fn new_with_code(handler: &'a Handler,
level: Level,
- code: Option<String>,
+ code: Option<DiagnosticId>,
message: &str)
-> DiagnosticBuilder<'a> {
let diagnostic = Diagnostic::new_with_code(level, code, message);
use self::Destination::*;
-use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
+use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan};
-use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
+use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper, DiagnosticId};
use RenderSpan::*;
use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
use styled_buffer::StyledBuffer;
// 6..7. This is degenerate input, but it's best to degrade
// gracefully -- and the parser likes to supply a span like
// that for EOF, in particular.
- if lo.col == hi.col && lo.line == hi.line {
- hi.col = CharPos(lo.col.0 + 1);
+ if lo.col_display == hi.col_display && lo.line == hi.line {
+ hi.col_display += 1;
}
let ann_type = if lo.line != hi.line {
depth: 1,
line_start: lo.line,
line_end: hi.line,
- start_col: lo.col.0,
- end_col: hi.col.0,
+ start_col: lo.col_display,
+ end_col: hi.col_display,
is_primary: span_label.is_primary,
label: span_label.label.clone(),
};
AnnotationType::Singleline
};
let ann = Annotation {
- start_col: lo.col.0,
- end_col: hi.col.0,
+ start_col: lo.col_display,
+ end_col: hi.col_display,
is_primary: span_label.is_primary,
label: span_label.label.clone(),
annotation_type: ann_type,
fn emit_message_default(&mut self,
msp: &MultiSpan,
msg: &Vec<(String, Style)>,
- code: &Option<String>,
+ code: &Option<DiagnosticId>,
level: &Level,
max_line_num_len: usize,
is_secondary: bool)
self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None);
} else {
buffer.append(0, &level.to_string(), Style::Level(level.clone()));
- match code {
- &Some(ref code) => {
- buffer.append(0, "[", Style::Level(level.clone()));
- buffer.append(0, &code, Style::Level(level.clone()));
- buffer.append(0, "]", Style::Level(level.clone()));
- }
- _ => {}
+ // only render error codes, not lint codes
+ if let Some(DiagnosticId::Error(ref code)) = *code {
+ buffer.append(0, "[", Style::Level(level.clone()));
+ buffer.append(0, &code, Style::Level(level.clone()));
+ buffer.append(0, "]", Style::Level(level.clone()));
}
buffer.append(0, ": ", Style::HeaderMsg);
for &(ref text, _) in msg.iter() {
fn emit_messages_default(&mut self,
level: &Level,
message: &Vec<(String, Style)>,
- code: &Option<String>,
+ code: &Option<DiagnosticId>,
span: &MultiSpan,
children: &Vec<SubDiagnostic>) {
let max_line_num = self.get_max_line_num(span, children);
}
}
-pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString};
+pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
pub use diagnostic_builder::DiagnosticBuilder;
/// A handler deals with errors; certain errors
pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
result.set_span(sp);
- result.code(code.to_owned());
+ result.code(code);
if !self.can_emit_warnings {
result.cancel();
}
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.set_span(sp);
- result.code(code.to_owned());
+ result.code(code);
result
}
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
DiagnosticBuilder::new(self, Level::Error, msg)
}
- pub fn struct_err_with_code<'a>(&'a self, msg: &str, code: &str) -> DiagnosticBuilder<'a> {
+ pub fn struct_err_with_code<'a>(
+ &'a self,
+ msg: &str,
+ code: DiagnosticId,
+ ) -> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
- result.code(code.to_owned());
+ result.code(code);
result
}
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
result.set_span(sp);
- result.code(code.to_owned());
+ result.code(code);
result
}
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> FatalError {
self.emit_with_code(&sp.into(), msg, code, Fatal);
FatalError
result.set_span(sp);
result
}
- pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_with_code(&sp.into(), msg, code, Error);
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Warning);
}
- pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
+ pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
self.emit_with_code(&sp.into(), msg, code, Warning);
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
self.abort_if_errors();
}
}
- pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) {
+ pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
if lvl == Warning && !self.can_emit_warnings {
return;
}
- let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg);
+ let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
db.set_span(msp.clone());
db.emit();
if !self.continue_after_error.get() {
//HirItem::ItemTrait(..) => ("ItemTrait", LABELS_TRAIT),
// `impl Trait for .. {}`
- HirItem::ItemDefaultImpl(..) => ("ItemDefaultImpl", LABELS_IMPL),
+ HirItem::ItemAutoImpl(..) => ("ItemAutoImpl", LABELS_IMPL),
// An implementation, eg `impl<A> Trait for Foo { .. }`
HirItem::ItemImpl(..) => ("ItemImpl", LABELS_IMPL),
#[derive(PartialEq)]
pub enum MethodLateContext {
- TraitDefaultImpl,
+ TraitAutoImpl,
TraitImpl,
PlainImpl,
}
let def_id = cx.tcx.hir.local_def_id(id);
let item = cx.tcx.associated_item(def_id);
match item.container {
- ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
+ ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
ty::ImplContainer(cid) => {
match cx.tcx.impl_trait_ref(cid) {
Some(_) => MethodLateContext::TraitImpl,
MethodLateContext::PlainImpl => {
self.check_snake_case(cx, "method", &name.as_str(), Some(span))
}
- MethodLateContext::TraitDefaultImpl => {
+ MethodLateContext::TraitAutoImpl => {
self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
}
_ => (),
// hardwired lints from librustc
pub use lint::builtin::*;
+declare_lint! {
+ pub AUTO_IMPL,
+ Deny,
+ "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`"
+}
+
+#[derive(Copy, Clone)]
+pub struct AutoImpl;
+
+impl LintPass for AutoImpl {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(AUTO_IMPL)
+ }
+}
+
+impl EarlyLintPass for AutoImpl {
+ fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
+ let msg = "The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`";
+ match item.node {
+ ast::ItemKind::AutoImpl(..) => cx.span_lint(AUTO_IMPL, item.span, msg),
+ _ => ()
+ }
+ }
+}
+
declare_lint! {
WHILE_TRUE,
Warn,
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
- hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
+ hir::ItemTrait(_, hir::Unsafety::Unsafe, ..) => {
self.report_unsafe(cx, it.span, "declaration of an `unsafe` trait")
}
}
}
}
+
+/// Lint for items marked `pub` that aren't reachable from other crates
+pub struct UnreachablePub;
+
+declare_lint! {
+ UNREACHABLE_PUB,
+ Allow,
+ "`pub` items not reachable from crate root"
+}
+
+impl LintPass for UnreachablePub {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNREACHABLE_PUB)
+ }
+}
+
+impl UnreachablePub {
+ fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
+ vis: &hir::Visibility, span: Span, exportable: bool) {
+ if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public {
+ let def_span = cx.tcx.sess.codemap().def_span(span);
+ let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
+ &format!("unreachable `pub` {}", what));
+ // 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 {
+ "crate"
+ } else {
+ "pub(crate)"
+ }.to_owned();
+ err.span_suggestion(pub_span, "consider restricting its visibility", replacement);
+ if exportable {
+ err.help("or consider exporting it for use by other crates");
+ }
+ err.emit();
+ }
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
+ self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+ }
+
+ fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) {
+ self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true);
+ }
+
+ fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
+ self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
+ self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+ }
+}
AnonymousParameters,
IllegalFloatLiteralPattern,
UnusedDocComment,
+ AutoImpl,
);
add_early_builtin_with_new!(sess,
PluginAsLibrary,
MutableTransmutes,
UnionsWithDropFields,
+ UnreachablePub,
);
add_builtin_with_new!(sess,
// - Eventually, remove lint
store.register_future_incompatible(sess,
vec![
+ FutureIncompatibleInfo {
+ id: LintId::of(AUTO_IMPL),
+ reference: "issue #13231 <https://github.com/rust-lang/rust/issues/13231>",
+ },
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
is_const_fn => { cdata.is_const_fn(def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
- is_default_impl => { cdata.is_default_impl(def_id.index) }
+ is_auto_impl => { cdata.is_auto_impl(def_id.index) }
describe_def => { cdata.get_def(def_id.index) }
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
lookup_stability => {
use std::u32;
use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
+use rustc_data_structures::indexed_vec::Idx;
use syntax::attr;
use syntax::ast::{self, Ident};
use syntax::codemap;
EntryKind::ForeignMod |
EntryKind::Impl(_) |
- EntryKind::DefaultImpl(_) |
+ EntryKind::AutoImpl(_) |
EntryKind::Field |
EntryKind::Generator(_) |
EntryKind::Closure(_) => return None,
ty::TraitDef::new(self.local_def_id(item_id),
data.unsafety,
data.paren_sugar,
- data.has_default_impl,
+ data.has_auto_impl,
self.def_path_table.def_path_hash(item_id))
}
continue;
}
EntryKind::Impl(_) |
- EntryKind::DefaultImpl(_) => continue,
+ EntryKind::AutoImpl(_) => continue,
_ => {}
}
self.dllimport_foreign_items.contains(&id)
}
- pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
+ pub fn is_auto_impl(&self, impl_id: DefIndex) -> bool {
match self.entry(impl_id).kind {
- EntryKind::DefaultImpl(_) => true,
+ EntryKind::AutoImpl(_) => true,
_ => false,
}
}
end_pos,
lines,
multibyte_chars,
+ non_narrow_chars,
.. } = filemap_to_import;
let source_length = (end_pos - start_pos).to_usize();
for mbc in &mut multibyte_chars {
mbc.pos = mbc.pos - start_pos;
}
+ let mut non_narrow_chars = non_narrow_chars.into_inner();
+ for swc in &mut non_narrow_chars {
+ *swc = *swc - start_pos;
+ }
let local_version = local_codemap.new_imported_filemap(name,
name_was_remapped,
src_hash,
source_length,
lines,
- multibyte_chars);
+ multibyte_chars,
+ non_narrow_chars);
debug!("CrateMetaData::imported_filemaps alloc \
filemap {:?} original (start_pos {:?} end_pos {:?}) \
translated (start_pos {:?} end_pos {:?})",
fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> {
debug!("IsolatedEncoder::encode_struct_ctor({:?})", def_id);
let tcx = self.tcx;
- let variant = tcx.adt_def(adt_def_id).struct_variant();
+ let adt_def = tcx.adt_def(adt_def_id);
+ let variant = adt_def.struct_variant();
let data = VariantData {
ctor_kind: variant.ctor_kind,
}
}
+ // If the structure is marked as non_exhaustive then lower the visibility
+ // to within the crate.
+ if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+ ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+ }
+
let repr_options = get_repr_options(&tcx, adt_def_id);
Entry {
ctor_sig: None,
}), repr_options)
}
- hir::ItemDefaultImpl(..) => {
+ hir::ItemAutoImpl(..) => {
let data = ImplData {
polarity: hir::ImplPolarity::Positive,
defaultness: hir::Defaultness::Final,
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
};
- EntryKind::DefaultImpl(self.lazy(&data))
+ EntryKind::AutoImpl(self.lazy(&data))
}
hir::ItemImpl(_, polarity, defaultness, ..) => {
let trait_ref = tcx.impl_trait_ref(def_id);
let data = TraitData {
unsafety: trait_def.unsafety,
paren_sugar: trait_def.paren_sugar,
- has_default_impl: tcx.trait_has_default_impl(def_id),
+ has_auto_impl: tcx.trait_is_auto(def_id),
super_predicates: self.lazy(&tcx.super_predicates_of(def_id)),
};
hir::ItemGlobalAsm(..) |
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
- hir::ItemDefaultImpl(..) |
+ hir::ItemAutoImpl(..) |
hir::ItemTy(..) => {
// no sub-item recording needed in these cases
}
Generator(Lazy<GeneratorData<'tcx>>),
Trait(Lazy<TraitData<'tcx>>),
Impl(Lazy<ImplData<'tcx>>),
- DefaultImpl(Lazy<ImplData<'tcx>>),
+ AutoImpl(Lazy<ImplData<'tcx>>),
Method(Lazy<MethodData<'tcx>>),
AssociatedType(AssociatedContainer),
AssociatedConst(AssociatedContainer, u8),
EntryKind::Trait(ref trait_data) => {
trait_data.hash_stable(hcx, hasher);
}
- EntryKind::DefaultImpl(ref impl_data) |
+ EntryKind::AutoImpl(ref impl_data) |
EntryKind::Impl(ref impl_data) => {
impl_data.hash_stable(hcx, hasher);
}
pub struct TraitData<'tcx> {
pub unsafety: hir::Unsafety,
pub paren_sugar: bool,
- pub has_default_impl: bool,
+ pub has_auto_impl: bool,
pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
}
impl_stable_hash_for!(struct TraitData<'tcx> {
unsafety,
paren_sugar,
- has_default_impl,
+ has_auto_impl,
super_predicates
});
TerminatorKind::Resume |
TerminatorKind::Return |
TerminatorKind::GeneratorDrop |
- TerminatorKind::Unreachable => {
+ TerminatorKind::Unreachable |
+ TerminatorKind::FalseEdges { .. } => {
// no data used, thus irrelevant to borrowck
}
}
use rustc::hir;
use hair::*;
use syntax::ast::{Name, NodeId};
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::Span;
// helper functions, broken out by category:
mod simplify;
(body, scope.unwrap_or(self.visibility_scope))
}).collect();
+ // create binding start block for link them by false edges
+ let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len());
+ let pre_binding_blocks: Vec<_> = (0..candidate_count + 1)
+ .map(|_| self.cfg.start_new_block()).collect();
+
// assemble a list of candidates: there is one candidate per
// pattern, which means there may be more than one candidate
// *per arm*. These candidates are kept sorted such that the
// highest priority candidate comes first in the list.
// (i.e. same order as in source)
+
let candidates: Vec<_> =
arms.iter()
.enumerate()
arm.patterns.iter()
.map(move |pat| (arm_index, pat, arm.guard.clone()))
})
- .map(|(arm_index, pattern, guard)| {
+ .zip(pre_binding_blocks.iter().zip(pre_binding_blocks.iter().skip(1)))
+ .map(|((arm_index, pattern, guard),
+ (pre_binding_block, next_candidate_pre_binding_block))| {
Candidate {
span: pattern.span,
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard,
arm_index,
+ pre_binding_block: *pre_binding_block,
+ next_candidate_pre_binding_block: *next_candidate_pre_binding_block,
}
})
.collect();
+ let outer_source_info = self.source_info(span);
+ self.cfg.terminate(*pre_binding_blocks.last().unwrap(),
+ outer_source_info, TerminatorKind::Unreachable);
+
// this will generate code to test discriminant_lvalue and
// branch to the appropriate arm block
let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block);
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
bindings: vec![],
guard: None,
- arm_index: 0, // since we don't call `match_candidates`, this field is unused
+
+ // since we don't call `match_candidates`, next fields is unused
+ arm_index: 0,
+ pre_binding_block: block,
+ next_candidate_pre_binding_block: block
};
// Simplify the candidate. Since the pattern is irrefutable, this should
// ...and then we branch to arm with this index.
arm_index: usize,
+
+ // ...and the blocks for add false edges between candidates
+ pre_binding_block: BasicBlock,
+ next_candidate_pre_binding_block: BasicBlock,
}
#[derive(Clone, Debug)]
candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
debug!("match_candidates: {:?} candidates fully matched", fully_matched);
let mut unmatched_candidates = candidates.split_off(fully_matched);
- for (index, candidate) in candidates.into_iter().enumerate() {
+
+ let fully_matched_with_guard =
+ candidates.iter().take_while(|c| c.guard.is_some()).count();
+
+ let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() {
+ candidates.split_off(fully_matched_with_guard + 1)
+ } else {
+ vec![]
+ };
+
+ for candidate in candidates {
// If so, apply any bindings, test the guard (if any), and
// branch to the arm.
- let is_last = index == fully_matched - 1;
- if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks,
- candidate, is_last) {
+ if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
block = b;
} else {
// if None is returned, then any remaining candidates
// are unreachable (at least not through this path).
- return vec![];
+ // Link them with false edges.
+ debug!("match_candidates: add false edges for unreachable {:?} and unmatched {:?}",
+ unreachable_candidates, unmatched_candidates);
+ for candidate in unreachable_candidates {
+ let source_info = self.source_info(candidate.span);
+ let target = self.cfg.start_new_block();
+ if let Some(otherwise) = self.bind_and_guard_matched_candidate(target,
+ arm_blocks,
+ candidate) {
+ self.cfg.terminate(otherwise, source_info, TerminatorKind::Unreachable);
+ }
+ }
+
+ if unmatched_candidates.is_empty() {
+ return vec![]
+ } else {
+ let target = self.cfg.start_new_block();
+ return self.match_candidates(span, arm_blocks, unmatched_candidates, target);
+ }
}
}
self.test_candidates(span, arm_blocks, &unmatched_candidates, block);
// If the target candidates were exhaustive, then we are done.
- if otherwise.is_empty() {
- return vec![];
- }
+ // But for borrowck continue build decision tree.
// If all candidates were sorted into `target_candidates` somewhere, then
// the initial set was inexhaustive.
fn bind_and_guard_matched_candidate<'pat>(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
- candidate: Candidate<'pat, 'tcx>,
- is_last_arm: bool)
+ candidate: Candidate<'pat, 'tcx>)
-> Option<BasicBlock> {
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
block, candidate);
debug_assert!(candidate.match_pairs.is_empty());
- self.bind_matched_candidate(block, candidate.bindings);
-
let arm_block = arm_blocks.blocks[candidate.arm_index];
+ let candidate_source_info = self.source_info(candidate.span);
+
+ self.cfg.terminate(block, candidate_source_info,
+ TerminatorKind::Goto { target: candidate.pre_binding_block });
+
+ block = self.cfg.start_new_block();
+ self.cfg.terminate(candidate.pre_binding_block, candidate_source_info,
+ TerminatorKind::FalseEdges {
+ real_target: block,
+ imaginary_targets:
+ vec![candidate.next_candidate_pre_binding_block]});
+
+ self.bind_matched_candidate(block, candidate.bindings);
if let Some(guard) = candidate.guard {
// the block to branch to if the guard fails; if there is no
let guard = self.hir.mirror(guard);
let source_info = self.source_info(guard.span);
let cond = unpack!(block = self.as_local_operand(block, guard));
- let otherwise = self.cfg.start_new_block();
+
+ let false_edge_block = self.cfg.start_new_block();
self.cfg.terminate(block, source_info,
- TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
- Some(otherwise)
- } else if !is_last_arm {
- // Add always true guard in case of more than one arm
- // it creates false edges and allow MIR borrowck detects errors
- // FIXME(#45184) -- permit "false edges"
- let source_info = self.source_info(candidate.span);
- let true_expr = Expr {
- temp_lifetime: None,
- ty: self.hir.tcx().types.bool,
- span: DUMMY_SP,
- kind: ExprKind::Literal{literal: self.hir.true_literal()},
- };
- let cond = unpack!(block = self.as_local_operand(block, true_expr));
+ TerminatorKind::if_(self.hir.tcx(), cond, arm_block,
+ false_edge_block));
+
let otherwise = self.cfg.start_new_block();
- self.cfg.terminate(block, source_info,
- TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
+ self.cfg.terminate(false_edge_block, source_info,
+ TerminatorKind::FalseEdges {
+ real_target: otherwise,
+ imaginary_targets:
+ vec![candidate.next_candidate_pre_binding_block] });
Some(otherwise)
} else {
- let source_info = self.source_info(candidate.span);
- self.cfg.terminate(block, source_info,
- TerminatorKind::Goto { target: arm_block });
+ self.cfg.terminate(block, candidate_source_info,
+ TerminatorKind::Goto { target: arm_block });
None
}
}
bindings: candidate.bindings.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
+ pre_binding_block: candidate.pre_binding_block,
+ next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
}
}
bindings: candidate.bindings.clone(),
guard: candidate.guard.clone(),
arm_index: candidate.arm_index,
+ pre_binding_block: candidate.pre_binding_block,
+ next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
}
}
self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb);
}
}
+ mir::TerminatorKind::FalseEdges { ref real_target, ref imaginary_targets } => {
+ self.propagate_bits_into_entry_set_for(in_out, changed, real_target);
+ for target in imaginary_targets {
+ self.propagate_bits_into_entry_set_for(in_out, changed, target);
+ }
+ }
}
}
TerminatorKind::Goto { target: _ } |
TerminatorKind::Resume |
TerminatorKind::GeneratorDrop |
+ TerminatorKind::FalseEdges { .. } |
TerminatorKind::Unreachable => { }
TerminatorKind::Return => {
TerminatorKind::GeneratorDrop |
TerminatorKind::Resume |
TerminatorKind::Return |
- TerminatorKind::Unreachable => {
+ TerminatorKind::Unreachable |
+ TerminatorKind::FalseEdges { .. } => {
// safe (at least as emitted during MIR construction)
}
}
}
TerminatorKind::Unreachable => { }
+ TerminatorKind::FalseEdges { ref mut real_target, ref mut imaginary_targets } => {
+ *real_target = self.update_target(*real_target);
+ for target in imaginary_targets {
+ *target = self.update_target(*target);
+ }
+ }
}
}
TerminatorKind::Unreachable |
TerminatorKind::GeneratorDrop |
TerminatorKind::Yield { .. } |
- TerminatorKind::SwitchInt { .. } => {
+ TerminatorKind::SwitchInt { .. } |
+ TerminatorKind::FalseEdges { .. } => {
/* nothing to do */
},
TerminatorKind::Call { cleanup: ref mut unwind, .. } |
TerminatorKind::Resume |
TerminatorKind::GeneratorDrop |
TerminatorKind::Yield { .. } |
- TerminatorKind::Unreachable => None,
+ TerminatorKind::Unreachable |
+ TerminatorKind::FalseEdges { .. } => None,
TerminatorKind::Return => {
// Check for unused values. This usually means
}), expected, .. } if cond == expected => {
TerminatorKind::Goto { target: target }
},
+ TerminatorKind::FalseEdges { real_target, .. } => {
+ TerminatorKind::Goto { target: real_target }
+ },
_ => continue
};
}
TerminatorKind::Return |
TerminatorKind::GeneratorDrop |
TerminatorKind::Unreachable |
- TerminatorKind::Drop { .. } => {
+ TerminatorKind::Drop { .. } |
+ TerminatorKind::FalseEdges { .. } => {
// no checks needed for these
}
self.assert_iscleanup(mir, block, cleanup, true);
}
}
+ TerminatorKind::FalseEdges { real_target, ref imaginary_targets } => {
+ self.assert_iscleanup(mir, block, real_target, is_cleanup);
+ for target in imaginary_targets {
+ self.assert_iscleanup(mir, block, *target, is_cleanup);
+ }
+ }
}
}
// except according to those terms.
use rustc::ty::{self, TyCtxt};
-use rustc_errors::DiagnosticBuilder;
+use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use syntax_pos::{MultiSpan, Span};
use std::fmt;
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a>;
fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str,
- code: &str)
+ code: DiagnosticId)
-> DiagnosticBuilder<'a>
{
self.sess.struct_span_err_with_code(sp, msg, code)
}
}
+ fn invalid_non_exhaustive_attribute(&self, variant: &Variant) {
+ let has_non_exhaustive = variant.node.attrs.iter()
+ .any(|attr| attr.check_name("non_exhaustive"));
+ if has_non_exhaustive {
+ self.err_handler().span_err(variant.span,
+ "#[non_exhaustive] is not yet supported on variants");
+ }
+ }
+
fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
if vis != &Visibility::Inherited {
let mut err = struct_span_err!(self.session,
item.span,
Some("place qualifiers on individual impl items instead"));
}
- ItemKind::DefaultImpl(..) => {
+ ItemKind::AutoImpl(..) => {
self.invalid_visibility(&item.vis, item.span, None);
}
ItemKind::ForeignMod(..) => {
}
ItemKind::Enum(ref def, _) => {
for variant in &def.variants {
+ self.invalid_non_exhaustive_attribute(variant);
for field in variant.node.data.fields() {
self.invalid_visibility(&field.vis, field.span, None);
}
}
}
- ItemKind::Trait(.., ref bounds, ref trait_items) => {
+ ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
+ if is_auto == IsAuto::Yes {
+ // Auto traits cannot have generics, super traits nor contain items.
+ if !generics.ty_params.is_empty() {
+ self.err_handler().span_err(item.span,
+ "auto traits cannot have generics");
+ }
+ if !bounds.is_empty() {
+ self.err_handler().span_err(item.span,
+ "auto traits cannot have super traits");
+ }
+ if !trait_items.is_empty() {
+ self.err_handler().span_err(item.span,
+ "auto traits cannot contain items");
+ }
+ }
self.no_questions_in_bounds(bounds, "supertraits", true);
for trait_item in trait_items {
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop",
TerminatorKind::Yield { .. } => "TerminatorKind::Yield",
+ TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges",
}, kind);
self.super_terminator_kind(block, kind, location);
}
let def_id = self.tcx.hir.local_def_id(item.id);
cmp::min(self.item_ty_level(def_id), self.impl_trait_level(def_id))
}
- hir::ItemDefaultImpl(..) => {
+ hir::ItemAutoImpl(..) => {
let def_id = self.tcx.hir.local_def_id(item.id);
self.impl_trait_level(def_id)
}
}
hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) |
- hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {}
+ hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemAutoImpl(..) => {}
}
// Mark all items in interfaces of reachable items as reachable
// Reexports are handled in visit_mod
hir::ItemUse(..) => {}
// The interface is empty
- hir::ItemDefaultImpl(..) => {}
+ hir::ItemAutoImpl(..) => {}
// The interface is empty
hir::ItemGlobalAsm(..) => {}
// Visit everything
ctor_vis = field_vis;
}
}
+
+ // If the structure is marked as non_exhaustive then lower the
+ // visibility to within the crate.
+ let struct_def_id = self.tcx.hir.get_parent_did(node_id);
+ let adt_def = self.tcx.adt_def(struct_def_id);
+ if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+ ctor_vis = ty::Visibility::Restricted(
+ DefId::local(CRATE_DEF_INDEX));
+ }
+
return ctor_vis;
}
node => bug!("unexpected node kind: {:?}", node)
}
}
// The interface is empty
- hir::ItemDefaultImpl(..) => {}
+ hir::ItemAutoImpl(..) => {}
// An inherent impl is public when its type is public
// Subitems of inherent impls have their own publicity
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
arena = { path = "../libarena" }
rustc_errors = { path = "../librustc_errors" }
syntax_pos = { path = "../libsyntax_pos" }
+rustc_data_structures = { path = "../librustc_data_structures" }
// These items live in both the type and value namespaces.
ItemKind::Struct(ref struct_def, _) => {
// Define a name in the type namespace.
- let def = Def::Struct(self.definitions.local_def_id(item.id));
+ let def_id = self.definitions.local_def_id(item.id);
+ let def = Def::Struct(def_id);
self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
- // Record field names for error reporting.
let mut ctor_vis = vis;
+
+ let has_non_exhaustive = item.attrs.iter()
+ .any(|item| item.check_name("non_exhaustive"));
+
+ // If the structure is marked as non_exhaustive then lower the visibility
+ // to within the crate.
+ if has_non_exhaustive && vis == ty::Visibility::Public {
+ ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+ }
+
+ // Record field names for error reporting.
let field_names = struct_def.fields().iter().filter_map(|field| {
let field_vis = self.resolve_visibility(&field.vis);
if ctor_vis.is_at_least(field_vis, &*self) {
self.insert_field_names(item_def_id, field_names);
}
- ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => {}
+ ItemKind::AutoImpl(..) | ItemKind::Impl(..) => {}
ItemKind::Trait(..) => {
let def_id = self.definitions.local_def_id(item.id);
// value namespace, they are reserved for possible future use.
let ctor_kind = CtorKind::from_ast(&variant.node.data);
let ctor_def = Def::VariantCtor(def_id, ctor_kind);
+
self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion));
}
extern crate arena;
#[macro_use]
extern crate rustc;
+extern crate rustc_data_structures;
use self::Namespace::*;
use self::TypeParameters::*;
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticId};
use std::cell::{Cell, RefCell};
use std::cmp;
let target_sp = binding_error.target.iter().map(|x| *x).collect::<Vec<_>>();
let msp = MultiSpan::from_spans(target_sp.clone());
let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
- let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
+ let mut err = resolver.session.struct_span_err_with_code(
+ msp,
+ &msg,
+ DiagnosticId::Error("E0408".into()),
+ );
for sp in target_sp {
err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
}
|this| visit::walk_item(this, item));
}
- ItemKind::DefaultImpl(_, ref trait_ref) => {
+ ItemKind::AutoImpl(_, ref trait_ref) => {
self.with_optional_trait_ref(Some(trait_ref), |this, _| {
// Resolve type arguments in trait path
visit::walk_trait_ref(this, trait_ref);
item.id,
impl_items),
- ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => {
+ ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
// Create a new rib for the trait-wide type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
let local_def_id = this.definitions.local_def_id(item.id);
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
format!("not found in {}", mod_str), item_span)
};
+ let code = DiagnosticId::Error(code.into());
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
// Emit special messages for unresolved `Self` and `self`.
if is_self_type(path, ns) {
__diagnostic_used!(E0411);
- err.code("E0411".into());
+ err.code(DiagnosticId::Error("E0411".into()));
err.span_label(span, "`Self` is only available in traits and impls");
return (err, Vec::new());
}
if is_self_value(path, ns) {
__diagnostic_used!(E0424);
- err.code("E0424".into());
+ err.code(DiagnosticId::Error("E0424".into()));
err.span_label(span, format!("`self` value is only available in \
methods with `self` parameter"));
return (err, Vec::new());
use Namespace::{self, MacroNS};
use build_reduced_graph::BuildReducedGraphVisitor;
use resolve_imports::ImportResolver;
+use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
use rustc::hir::def::{Def, Export};
use rustc::hir::map::{self, DefCollector};
let mut collector = PathCollector::new();
collector.visit_pat(&arg.pat);
let span_utils = self.span.clone();
- for &(id, ref p, ..) in &collector.collected_paths {
+
+ for (id, i, sp, ..) in collector.collected_idents {
let hir_id = self.tcx.hir.node_to_hir_id(id);
let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) {
Some(s) => s.to_string(),
None => continue,
};
- // get the span only for the name of the variable (I hope the path is only ever a
- // variable name, but who knows?)
- let sub_span = span_utils.span_for_last_ident(p.span);
- if !self.span.filter_generated(sub_span, p.span) {
+ let sub_span = span_utils.span_for_last_ident(sp);
+ if !self.span.filter_generated(sub_span, sp) {
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for variable"));
kind: DefKind::Local,
id,
span,
- name: path_to_string(p),
- qualname: format!("{}::{}", qualname, path_to_string(p)),
+ name: i.to_string(),
+ qualname: format!("{}::{}", qualname, i.to_string()),
value: typ,
parent: None,
children: vec![],
}
}
- fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) {
- let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref);
- if let Some(trait_ref_data) = trait_ref_data {
- self.dumper.dump_ref(trait_ref_data);
- }
- self.process_path(trait_ref.ref_id, &trait_ref.path);
- }
-
fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
let field_data = self.save_ctxt.get_field_data(field, parent_id);
if let Some(field_data) = field_data {
item: &'l ast::Item,
def: &'l ast::VariantData,
ty_params: &'l ast::Generics) {
+ debug!("process_struct {:?} {:?}", item, item.span);
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
- let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
- let (value, fields) =
- if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node
- {
- let include_priv_fields = !self.save_ctxt.config.pub_only;
- let fields_str = fields
- .iter()
- .enumerate()
- .filter_map(|(i, f)| {
- if include_priv_fields || f.vis == ast::Visibility::Public {
- f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string()))
- } else {
- None
- }
- })
- .collect::<Vec<_>>()
- .join(", ");
- let value = format!("{} {{ {} }}", name, fields_str);
- (value, fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect())
- } else {
- (String::new(), vec![])
+ let (kind, keyword) = match item.node {
+ ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct),
+ ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union),
+ _ => unreachable!(),
+ };
+
+ let sub_span = self.span.sub_span_after_keyword(item.span, keyword);
+ let (value, fields) = match item.node {
+ ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
+ ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
+ let include_priv_fields = !self.save_ctxt.config.pub_only;
+ let fields_str = fields
+ .iter()
+ .enumerate()
+ .filter_map(|(i, f)| {
+ if include_priv_fields || f.vis == ast::Visibility::Public {
+ f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string()))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>()
+ .join(", ");
+ let value = format!("{} {{ {} }}", name, fields_str);
+ (value, fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect())
+ }
+ _ => (String::new(), vec![])
};
if !self.span.filter_generated(sub_span, item.span) {
let span = self.span_from_span(sub_span.expect("No span found for struct"));
self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
- kind: DefKind::Struct,
+ kind,
id: ::id_from_node_id(item.id, &self.save_ctxt),
span,
name,
}
}
- fn process_path(&mut self, id: NodeId, path: &ast::Path) {
+ fn process_path(&mut self, id: NodeId, path: &'l ast::Path) {
+ debug!("process_path {:?}", path);
let path_data = self.save_ctxt.get_path_data(id, path);
if generated_code(path.span) && path_data.is_none() {
return;
self.dumper.dump_ref(path_data);
+ // Type parameters
+ for seg in &path.segments {
+ if let Some(ref params) = seg.parameters {
+ match **params {
+ ast::PathParameters::AngleBracketed(ref data) => {
+ for t in &data.types {
+ self.visit_ty(t);
+ }
+ }
+ ast::PathParameters::Parenthesized(ref data) => {
+ for t in &data.inputs {
+ self.visit_ty(t);
+ }
+ if let Some(ref t) = data.output {
+ self.visit_ty(t);
+ }
+ }
+ }
+ }
+ }
+
// Modules or types in the path prefix.
match self.save_ctxt.get_path_def(id) {
HirDef::Method(did) => {
walk_list!(self, visit_expr, base);
}
- fn process_method_call(&mut self, ex: &'l ast::Expr, args: &'l [P<ast::Expr>]) {
+ fn process_method_call(&mut self,
+ ex: &'l ast::Expr,
+ seg: &'l ast::PathSegment,
+ args: &'l [P<ast::Expr>]) {
+ debug!("process_method_call {:?} {:?}", ex, ex.span);
if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
down_cast_data!(mcd, RefData, ex.span);
if !generated_code(ex.span) {
}
}
+ // Explicit types in the turbo-fish.
+ if let Some(ref params) = seg.parameters {
+ if let ast::PathParameters::AngleBracketed(ref data) = **params {
+ for t in &data.types {
+ self.visit_ty(t);
+ }
+ }
+ }
+
// walk receiver and args
walk_list!(self, visit_expr, args);
}
collector.visit_pat(&p);
self.visit_pat(&p);
- for &(id, ref p, immut) in &collector.collected_paths {
+ for (id, i, sp, immut) in collector.collected_idents {
let mut value = match immut {
ast::Mutability::Immutable => value.to_string(),
_ => String::new(),
// Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?).
- let sub_span = self.span.span_for_last_ident(p.span);
+ let sub_span = self.span.span_for_last_ident(sp);
// Rust uses the id of the pattern for var lookups, so we'll use it too.
- if !self.span.filter_generated(sub_span, p.span) {
- let qualname = format!("{}${}", path_to_string(p), id);
+ if !self.span.filter_generated(sub_span, sp) {
+ let qualname = format!("{}${}", i.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for variable"));
kind: DefKind::Local,
id,
span,
- name: path_to_string(p),
+ name: i.to_string(),
qualname,
value: typ,
parent: None,
self.process_static_or_const_item(item, typ, expr),
Const(ref typ, ref expr) =>
self.process_static_or_const_item(item, &typ, &expr),
- Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
+ Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
+ self.process_struct(item, def, ty_params)
+ }
Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
Impl(..,
ref ty_params,
ref impl_items) => {
self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
}
- Trait(_, ref generics, ref trait_refs, ref methods) =>
+ Trait(_, _, ref generics, ref trait_refs, ref methods) =>
self.process_trait(item, generics, trait_refs, methods),
Mod(ref m) => {
self.process_mod(item);
for param in generics.ty_params.iter() {
for bound in param.bounds.iter() {
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
- self.process_trait_ref(&trait_ref.trait_ref);
+ self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
}
}
if let Some(ref ty) = param.default {
let def = self.save_ctxt.get_path_def(hir_expr.id);
self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
}
- ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args),
+ ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
ast::ExprKind::Field(ref sub_ex, _) => {
self.visit_expr(&sub_ex);
let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value);
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
- visit::walk_expr(self, subexpression);
+ self.visit_expr(subexpression);
visit::walk_block(self, block);
}
ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value);
- visit::walk_expr(self, subexpression);
+ self.visit_expr(subexpression);
visit::walk_block(self, block);
- opt_else.as_ref().map(|el| visit::walk_expr(self, el));
+ opt_else.as_ref().map(|el| self.visit_expr(el));
}
ast::ExprKind::Repeat(ref element, ref count) => {
self.visit_expr(element);
self.visit_pat(&pattern);
}
- // This is to get around borrow checking, because we need mut self to call process_path.
- let mut paths_to_process = vec![];
-
// process collected paths
- for &(id, ref p, immut) in &collector.collected_paths {
+ for (id, i, sp, immut) in collector.collected_idents {
match self.save_ctxt.get_path_def(id) {
HirDef::Local(id) => {
let mut value = if immut == ast::Mutability::Immutable {
- self.span.snippet(p.span).to_string()
+ self.span.snippet(sp).to_string()
} else {
"<mutable>".to_string()
};
value.push_str(": ");
value.push_str(&typ);
- assert!(p.segments.len() == 1,
- "qualified path for local variable def in arm");
- if !self.span.filter_generated(Some(p.span), p.span) {
- let qualname = format!("{}${}", path_to_string(p), id);
+ if !self.span.filter_generated(Some(sp), sp) {
+ let qualname = format!("{}${}", i.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
- let span = self.span_from_span(p.span);
+ let span = self.span_from_span(sp);
self.dumper.dump_def(false, Def {
kind: DefKind::Local,
id,
span,
- name: path_to_string(p),
+ name: i.to_string(),
qualname,
value: typ,
parent: None,
});
}
}
- HirDef::StructCtor(..) | HirDef::VariantCtor(..) |
- HirDef::Const(..) | HirDef::AssociatedConst(..) |
- HirDef::Struct(..) | HirDef::Variant(..) |
- HirDef::TyAlias(..) | HirDef::AssociatedTy(..) |
- HirDef::SelfTy(..) => {
- paths_to_process.push((id, p.clone()))
- }
- def => error!("unexpected definition kind when processing collected paths: {:?}",
+ def => error!("unexpected definition kind when processing collected idents: {:?}",
def),
}
}
- for &(id, ref path) in &paths_to_process {
+ for (id, ref path) in collector.collected_paths {
self.process_path(id, path);
}
walk_list!(self, visit_expr, &arm.guard);
}
}
}
- ast::ExprKind::MethodCall(..) => {
+ ast::ExprKind::MethodCall(ref seg, ..) => {
let expr_hir_id = self.tcx.hir.definitions().node_to_hir_id(expr.id);
let method_id = self.tables.type_dependent_defs()[expr_hir_id].def_id();
let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
ty::ImplContainer(_) => (Some(method_id), None),
ty::TraitContainer(_) => (None, Some(method_id)),
};
- let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
- filter!(self.span_utils, sub_span, expr.span, None);
- let span = self.span_from_span(sub_span.unwrap());
+ let sub_span = seg.span;
+ filter!(self.span_utils, Some(sub_span), expr.span, None);
+ let span = self.span_from_span(sub_span);
Some(Data::RefData(Ref {
kind: RefKind::Function,
span,
Node::NodeItem(&hir::Item { node: hir::ItemUse(ref path, _), .. }) |
Node::NodeVisibility(&hir::Visibility::Restricted { ref path, .. }) => path.def,
- Node::NodeExpr(&hir::Expr { node: hir::ExprPath(ref qpath), .. }) |
Node::NodeExpr(&hir::Expr { node: hir::ExprStruct(ref qpath, ..), .. }) |
+ Node::NodeExpr(&hir::Expr { node: hir::ExprPath(ref qpath), .. }) |
Node::NodePat(&hir::Pat { node: hir::PatKind::Path(ref qpath), .. }) |
Node::NodePat(&hir::Pat { node: hir::PatKind::Struct(ref qpath, ..), .. }) |
Node::NodePat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. }) => {
}
pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
+ // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
+ fn fn_type(path: &ast::Path) -> bool {
+ if path.segments.len() != 1 {
+ return false;
+ }
+ if let Some(ref params) = path.segments[0].parameters {
+ if let ast::PathParameters::Parenthesized(_) = **params {
+ return true;
+ }
+ }
+ false
+ }
+
+ if path.segments.is_empty() {
+ return None;
+ }
+
let def = self.get_path_def(id);
- let sub_span = self.span_utils.span_for_last_ident(path.span);
- filter!(self.span_utils, sub_span, path.span, None);
+ let last_seg = &path.segments[path.segments.len() - 1];
+ let sub_span = last_seg.span;
+ filter!(self.span_utils, Some(sub_span), path.span, None);
match def {
HirDef::Upvar(id, ..) |
HirDef::Local(id) => {
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
HirDef::Static(..) |
HirDef::Const(..) |
HirDef::AssociatedConst(..) |
- HirDef::StructCtor(..) |
HirDef::VariantCtor(..) => {
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
ref_id: id_from_def_id(def.def_id()),
})
}
+ HirDef::Trait(def_id) if fn_type(path) => {
+ // Function type bounds are desugared in the parser, so we have to
+ // special case them here.
+ let fn_span = self.span_utils.span_for_first_ident(path.span);
+ fn_span.map(|span| Ref {
+ kind: RefKind::Type,
+ span: self.span_from_span(span),
+ ref_id: id_from_def_id(def_id),
+ })
+ }
HirDef::Struct(def_id) |
HirDef::Variant(def_id, ..) |
HirDef::Union(def_id) |
HirDef::AssociatedTy(def_id) |
HirDef::Trait(def_id) |
HirDef::TyParam(def_id) => {
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Type,
span,
ref_id: id_from_def_id(def_id),
})
}
+ HirDef::StructCtor(def_id, _) => {
+ // This is a reference to a tuple struct where the def_id points
+ // to an invisible constructor function. That is not a very useful
+ // def, so adjust to point to the tuple struct itself.
+ let span = self.span_from_span(sub_span);
+ let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
+ Some(Ref {
+ kind: RefKind::Type,
+ span,
+ ref_id: id_from_def_id(parent_def_id),
+ })
+ }
HirDef::Method(decl_id) => {
- let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
- filter!(self.span_utils, sub_span, path.span, None);
let def_id = if decl_id.is_local() {
let ti = self.tcx.associated_item(decl_id);
self.tcx.associated_items(ti.container.id())
} else {
None
};
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
})
}
HirDef::Fn(def_id) => {
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
})
}
HirDef::Mod(def_id) => {
- let span = self.span_from_span(sub_span.unwrap());
+ let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Mod,
span,
sig
}
-// An AST visitor for collecting paths from patterns.
-struct PathCollector {
- // The Row field identifies the kind of pattern.
- collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>,
+// An AST visitor for collecting paths (e.g., the names of structs) and formal
+// variables (idents) from patterns.
+struct PathCollector<'l> {
+ collected_paths: Vec<(NodeId, &'l ast::Path)>,
+ collected_idents: Vec<(NodeId, ast::Ident, Span, ast::Mutability)>,
}
-impl PathCollector {
- fn new() -> PathCollector {
- PathCollector { collected_paths: vec![] }
+impl<'l> PathCollector<'l> {
+ fn new() -> PathCollector<'l> {
+ PathCollector {
+ collected_paths: vec![],
+ collected_idents: vec![],
+ }
}
}
-impl<'a> Visitor<'a> for PathCollector {
- fn visit_pat(&mut self, p: &ast::Pat) {
+impl<'l, 'a: 'l> Visitor<'a> for PathCollector<'l> {
+ fn visit_pat(&mut self, p: &'a ast::Pat) {
match p.node {
PatKind::Struct(ref path, ..) => {
- self.collected_paths.push((p.id, path.clone(),
- ast::Mutability::Mutable));
+ self.collected_paths.push((p.id, path));
}
PatKind::TupleStruct(ref path, ..) |
PatKind::Path(_, ref path) => {
- self.collected_paths.push((p.id, path.clone(),
- ast::Mutability::Mutable));
+ self.collected_paths.push((p.id, path));
}
PatKind::Ident(bm, ref path1, _) => {
debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
ast::BindingMode::ByRef(_) => ast::Mutability::Immutable,
ast::BindingMode::ByValue(mt) => mt,
};
- // collect path for either visit_local or visit_arm
- let path = ast::Path::from_ident(path1.span, path1.node);
- self.collected_paths.push((p.id, path, immut));
+ self.collected_idents.push((p.id, path1.node, path1.span, immut));
}
_ => {}
}
sig.text.push_str(" {}");
Ok(sig)
}
- ast::ItemKind::Trait(unsafety, ref generics, ref bounds, _) => {
+ ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
let mut text = String::new();
+
+ if is_auto == ast::IsAuto::Yes {
+ text.push_str("auto ");
+ }
+
if unsafety == ast::Unsafety::Unsafe {
text.push_str("unsafe ");
}
Ok(sig)
}
- ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+ ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => {
let mut text = String::new();
if unsafety == ast::Unsafety::Unsafe {
text.push_str("unsafe ");
}
}
- // Return the span for the last ident before a `(` or `<` or '::<' and outside any
- // any brackets, or the last span.
- pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
- let mut toks = self.retokenise_span(span);
- let mut prev = toks.real_token();
- let mut result = None;
- let mut bracket_count = 0;
- let mut prev_span = None;
- while prev.tok != token::Eof {
- prev_span = None;
- let mut next = toks.real_token();
-
- if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) &&
- bracket_count == 0 && prev.tok.is_ident() {
- result = Some(prev.sp);
- }
-
- if bracket_count == 0 && next.tok == token::ModSep {
- let old = prev;
- prev = next;
- next = toks.real_token();
- if next.tok == token::Lt && old.tok.is_ident() {
- result = Some(old.sp);
- }
- }
-
- bracket_count += match prev.tok {
- token::OpenDelim(token::Paren) | token::Lt => 1,
- token::CloseDelim(token::Paren) | token::Gt => -1,
- token::BinOp(token::Shr) => -2,
- _ => 0,
- };
-
- if prev.tok.is_ident() && bracket_count == 0 {
- prev_span = Some(prev.sp);
- }
- prev = next;
- }
- result.or(prev_span)
- }
-
// Return the span for the last ident before a `<` and outside any
// angle brackets, or the last span.
pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
}
macro_rules! filter {
- ($util: expr, $span: ident, $parent: expr, None) => {
+ ($util: expr, $span: expr, $parent: expr, None) => {
if $util.filter_generated($span, $parent) {
return None;
}
let canonical = f.replace("-", "_");
let canonical_name = name.replace("-", "_");
- // Look for `.rust-cgu.o` at the end of the filename to conclude
+ // Look for `.rcgu.o` at the end of the filename to conclude
// that this is a Rust-related object file.
fn looks_like_rust(s: &str) -> bool {
let path = Path::new(s);
use rustc::ty::maps::Providers;
use rustc::util::nodemap::FxHashMap;
use rustc_allocator::ALLOCATOR_METHODS;
+use syntax::attr;
pub type ExportedSymbols = FxHashMap<
CrateNum,
}
fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
- if tcx.contains_extern_indicator(sym_def_id) {
+ // 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
+ // core/std/allocators/etc. For example symbols used to hook up allocation
+ // are not considered for export
+ let is_extern = tcx.contains_extern_indicator(sym_def_id);
+ let std_internal = attr::contains_name(&tcx.get_attrs(sym_def_id),
+ "rustc_std_internal_symbol");
+ if is_extern && !std_internal {
SymbolExportLevel::C
} else {
SymbolExportLevel::Rust
use rustc::ty::TyCtxt;
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
-use errors::{self, Handler, Level, DiagnosticBuilder, FatalError};
+use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
use errors::emitter::{Emitter};
use syntax::attr;
use syntax::ext::hygiene::Mark;
struct Diagnostic {
msg: String,
- code: Option<String>,
+ code: Option<DiagnosticId>,
lvl: Level,
}
Some(ref code) => {
handler.emit_with_code(&MultiSpan::new(),
&diag.msg,
- &code,
+ code.clone(),
diag.lvl);
}
None => {
TerminatorKind::GeneratorDrop |
TerminatorKind::Unreachable |
TerminatorKind::SwitchInt { .. } |
- TerminatorKind::Yield { .. } => {
+ TerminatorKind::Yield { .. } |
+ TerminatorKind::FalseEdges { .. } => {
/* nothing to do */
}
TerminatorKind::Call { cleanup: unwind, .. } |
cleanup);
}
mir::TerminatorKind::GeneratorDrop |
- mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"),
+ mir::TerminatorKind::Yield { .. } |
+ mir::TerminatorKind::FalseEdges { .. } => bug!("generator ops in trans"),
}
}
mir::TerminatorKind::Unreachable |
mir::TerminatorKind::Assert { .. } => {}
mir::TerminatorKind::GeneratorDrop |
- mir::TerminatorKind::Yield { .. } => bug!(),
+ mir::TerminatorKind::Yield { .. } |
+ mir::TerminatorKind::FalseEdges { .. } => bug!(),
}
self.super_terminator_kind(block, kind, location);
hir::ItemUse(..) |
hir::ItemForeignMod(..) |
hir::ItemTy(..) |
- hir::ItemDefaultImpl(..) |
+ hir::ItemAutoImpl(..) |
hir::ItemTrait(..) |
hir::ItemMod(..) => {
// Nothing to do, just keep recursing...
## Type collection
-Type "collection" is the process of convering the types found in the
+Type "collection" is the process of converting the types found in the
HIR (`hir::Ty`), which represent the syntactic things that the user
wrote, into the **internal representation** used by the compiler
(`Ty<'tcx>`) -- we also do similar conversions for where-clauses and
bare_fn_ty
}
- pub fn ty_of_closure(&self,
- unsafety: hir::Unsafety,
- decl: &hir::FnDecl,
- abi: abi::Abi,
- expected_sig: Option<ty::FnSig<'tcx>>)
- -> ty::PolyFnSig<'tcx>
- {
- debug!("ty_of_closure(expected_sig={:?})",
- expected_sig);
-
- let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| {
- let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
- // no guarantee that the correct number of expected args
- // were supplied
- if i < e.inputs().len() {
- Some(e.inputs()[i])
- } else {
- None
- }
- });
- self.ty_of_arg(a, expected_arg_ty)
- });
-
- let expected_ret_ty = expected_sig.as_ref().map(|e| e.output());
-
- let output_ty = match decl.output {
- hir::Return(ref output) => {
- if let (&hir::TyInfer, Some(expected_ret_ty)) = (&output.node, expected_ret_ty) {
- self.record_ty(output.hir_id, expected_ret_ty, output.span);
- expected_ret_ty
- } else {
- self.ast_ty_to_ty(&output)
- }
- }
- hir::DefaultReturn(span) => {
- if let Some(expected_ret_ty) = expected_ret_ty {
- expected_ret_ty
- } else {
- self.ty_infer(span)
- }
- }
- };
-
- debug!("ty_of_closure: output_ty={:?}", output_ty);
-
- ty::Binder(self.tcx().mk_fn_sig(
- input_tys,
- output_ty,
- decl.variadic,
- unsafety,
- abi
- ))
- }
-
/// Given the bounds on an object, determines what single region bound (if any) we can
/// use to summarize this type. The basic idea is that we will use the bound the user
/// provided, if they provided one, and otherwise search the supertypes of trait bounds
use std::cmp;
use syntax::ast;
use syntax::codemap::Spanned;
+use syntax::feature_gate;
use syntax::ptr::P;
use syntax_pos::Span;
PatKind::Binding(..) |
PatKind::Ref(..) => false,
};
- if is_non_ref_pat && tcx.sess.features.borrow().match_default_bindings {
+ if is_non_ref_pat {
debug!("pattern is non reference pattern");
let mut exp_ty = self.resolve_type_vars_with_obligations(&expected);
}
};
if pat_adjustments.len() > 0 {
- debug!("default binding mode is now {:?}", def_bm);
- self.inh.tables.borrow_mut()
- .pat_adjustments_mut()
- .insert(pat.hir_id, pat_adjustments);
+ if tcx.sess.features.borrow().match_default_bindings {
+ debug!("default binding mode is now {:?}", def_bm);
+ self.inh.tables.borrow_mut()
+ .pat_adjustments_mut()
+ .insert(pat.hir_id, pat_adjustments);
+ } else {
+ let mut err = feature_gate::feature_err(
+ &tcx.sess.parse_sess,
+ "match_default_bindings",
+ pat.span,
+ feature_gate::GateIssue::Language,
+ "non-reference pattern used to match a reference",
+ );
+ if let Ok(snippet) = tcx.sess.codemap().span_to_snippet(pat.span) {
+ err.span_suggestion(pat.span, "consider using", format!("&{}", &snippet));
+ }
+ err.emit();
+ }
}
}
if let Some(mut err) = err {
if is_arg {
if let PatKind::Binding(..) = inner.node {
- if let Ok(snippet) = self.sess().codemap()
- .span_to_snippet(pat.span)
+ if let Ok(snippet) = tcx.sess.codemap()
+ .span_to_snippet(pat.span)
{
err.help(&format!("did you mean `{}: &{}`?",
&snippet[1..],
def_bm: ty::BindingMode) {
let tcx = self.tcx;
- let (substs, kind_name) = match adt_ty.sty {
- ty::TyAdt(adt, substs) => (substs, adt.variant_descr()),
+ let (substs, adt) = match adt_ty.sty {
+ ty::TyAdt(adt, substs) => (substs, adt),
_ => span_bug!(span, "struct pattern is not an ADT")
};
+ let kind_name = adt.variant_descr();
// Index the struct fields' types.
let field_map = variant.fields
self.check_pat_walk(&field.pat, field_ty, def_bm, true);
}
+ // Require `..` if struct has non_exhaustive attribute.
+ if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
+ span_err!(tcx.sess, span, E0638,
+ "`..` required with {} marked as non-exhaustive",
+ kind_name);
+ }
+
// Report an error if incorrect number of the fields were specified.
if kind_name == "union" {
if fields.len() != 1 {
use super::{check_fn, Expectation, FnCtxt};
use astconv::AstConv;
+use rustc::hir::def_id::DefId;
+use rustc::infer::{InferOk, InferResult};
+use rustc::infer::LateBoundRegionConversionTime;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::ty::{self, ToPolyTraitRef, Ty};
use rustc::ty::subst::Substs;
+use rustc::ty::TypeFoldable;
use std::cmp;
use std::iter;
use syntax::abi::Abi;
use rustc::hir;
+struct ClosureSignatures<'tcx> {
+ bound_sig: ty::PolyFnSig<'tcx>,
+ liberated_sig: ty::FnSig<'tcx>,
+}
+
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn check_expr_closure(&self,
- expr: &hir::Expr,
- _capture: hir::CaptureClause,
- decl: &'gcx hir::FnDecl,
- body_id: hir::BodyId,
- expected: Expectation<'tcx>)
- -> Ty<'tcx> {
- debug!("check_expr_closure(expr={:?},expected={:?})",
- expr,
- expected);
+ pub fn check_expr_closure(
+ &self,
+ expr: &hir::Expr,
+ _capture: hir::CaptureClause,
+ decl: &'gcx hir::FnDecl,
+ body_id: hir::BodyId,
+ expected: Expectation<'tcx>,
+ ) -> Ty<'tcx> {
+ debug!(
+ "check_expr_closure(expr={:?},expected={:?})",
+ expr,
+ expected
+ );
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
self.check_closure(expr, expected_kind, decl, body, expected_sig)
}
- fn check_closure(&self,
- expr: &hir::Expr,
- opt_kind: Option<ty::ClosureKind>,
- decl: &'gcx hir::FnDecl,
- body: &'gcx hir::Body,
- expected_sig: Option<ty::FnSig<'tcx>>)
- -> Ty<'tcx> {
- debug!("check_closure opt_kind={:?} expected_sig={:?}",
- opt_kind,
- expected_sig);
+ fn check_closure(
+ &self,
+ expr: &hir::Expr,
+ opt_kind: Option<ty::ClosureKind>,
+ decl: &'gcx hir::FnDecl,
+ body: &'gcx hir::Body,
+ expected_sig: Option<ty::FnSig<'tcx>>,
+ ) -> Ty<'tcx> {
+ debug!(
+ "check_closure(opt_kind={:?}, expected_sig={:?})",
+ opt_kind,
+ expected_sig
+ );
let expr_def_id = self.tcx.hir.local_def_id(expr.id);
- let sig = AstConv::ty_of_closure(self,
- hir::Unsafety::Normal,
- decl,
- Abi::RustCall,
- expected_sig);
- // `deduce_expectations_from_expected_type` introduces late-bound
- // lifetimes defined elsewhere, which we need to anonymize away.
- let sig = self.tcx.anonymize_late_bound_regions(&sig);
+
+ let ClosureSignatures {
+ bound_sig,
+ liberated_sig,
+ } = self.sig_of_closure(expr_def_id, decl, body, expected_sig);
+
+ debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
+
+ let interior = check_fn(
+ self,
+ self.param_env,
+ liberated_sig,
+ decl,
+ expr.id,
+ body,
+ true,
+ ).1;
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
// inference phase (`upvar.rs`).
- let base_substs = Substs::identity_for_item(self.tcx,
- self.tcx.closure_base_def_id(expr_def_id));
- let substs = base_substs.extend_to(self.tcx, expr_def_id,
- |_, _| span_bug!(expr.span, "closure has region param"),
- |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
+ let base_substs =
+ Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
+ let substs = base_substs.extend_to(
+ self.tcx,
+ expr_def_id,
+ |_, _| span_bug!(expr.span, "closure has region param"),
+ |_, _| {
+ self.infcx
+ .next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
+ },
);
-
- let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
- let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
- body.value.id,
- self.param_env,
- &fn_sig);
-
- let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1;
+ let closure_type = self.tcx.mk_closure(expr_def_id, substs);
if let Some(interior) = interior {
- let closure_substs = ty::ClosureSubsts {
- substs: substs,
- };
+ let closure_substs = ty::ClosureSubsts { substs: substs };
return self.tcx.mk_generator(expr_def_id, closure_substs, interior);
}
- let closure_type = self.tcx.mk_closure(expr_def_id, substs);
-
- debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
+ debug!(
+ "check_closure: expr.id={:?} closure_type={:?}",
+ expr.id,
+ closure_type
+ );
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
- let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
- iter::once(self.tcx.intern_tup(sig.inputs(), false)),
- sig.output(),
- sig.variadic,
- sig.unsafety,
- sig.abi
- ));
-
- debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
- expr_def_id,
- sig,
- opt_kind);
+ let sig = bound_sig.map_bound(|sig| {
+ self.tcx.mk_fn_sig(
+ iter::once(self.tcx.intern_tup(sig.inputs(), false)),
+ sig.output(),
+ sig.variadic,
+ sig.unsafety,
+ sig.abi,
+ )
+ });
+
+ debug!(
+ "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}",
+ expr_def_id,
+ sig,
+ opt_kind
+ );
{
let mut tables = self.tables.borrow_mut();
closure_type
}
- fn deduce_expectations_from_expected_type
- (&self,
- expected_ty: Ty<'tcx>)
- -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
- debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
- expected_ty);
+ fn deduce_expectations_from_expected_type(
+ &self,
+ expected_ty: Ty<'tcx>,
+ ) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
+ debug!(
+ "deduce_expectations_from_expected_type(expected_ty={:?})",
+ expected_ty
+ );
match expected_ty.sty {
ty::TyDynamic(ref object_type, ..) => {
- let sig = object_type.projection_bounds()
+ let sig = object_type
+ .projection_bounds()
.filter_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
self.deduce_sig_from_projection(&pb)
})
.next();
- let kind = object_type.principal()
+ let kind = object_type
+ .principal()
.and_then(|p| self.tcx.lang_items().fn_trait_kind(p.def_id()));
(sig, kind)
}
}
}
- fn deduce_expectations_from_obligations
- (&self,
- expected_vid: ty::TyVid)
- -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
+ fn deduce_expectations_from_obligations(
+ &self,
+ expected_vid: ty::TyVid,
+ ) -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
let fulfillment_cx = self.fulfillment_cx.borrow();
// Here `expected_ty` is known to be a type inference variable.
- let expected_sig = fulfillment_cx.pending_obligations()
+ let expected_sig = fulfillment_cx
+ .pending_obligations()
.iter()
.map(|obligation| &obligation.obligation)
.filter_map(|obligation| {
- debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
- obligation.predicate);
+ debug!(
+ "deduce_expectations_from_obligations: obligation.predicate={:?}",
+ obligation.predicate
+ );
match obligation.predicate {
// Given a Projection predicate, we can potentially infer
// infer the kind. This can occur if there is a trait-reference
// like `F : Fn<A>`. Note that due to subtyping we could encounter
// many viable options, so pick the most restrictive.
- let expected_kind = fulfillment_cx.pending_obligations()
+ let expected_kind = fulfillment_cx
+ .pending_obligations()
.iter()
.map(|obligation| &obligation.obligation)
.filter_map(|obligation| {
// inference variable.
ty::Predicate::ClosureKind(..) => None,
};
- opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
+ opt_trait_ref
+ .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
.and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
})
- .fold(None,
- |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ .fold(None, |best, cur| {
+ Some(best.map_or(cur, |best| cmp::min(best, cur)))
+ });
(expected_sig, expected_kind)
}
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
/// everything we need to know about a closure.
- fn deduce_sig_from_projection(&self,
- projection: &ty::PolyProjectionPredicate<'tcx>)
- -> Option<ty::FnSig<'tcx>> {
+ fn deduce_sig_from_projection(
+ &self,
+ projection: &ty::PolyProjectionPredicate<'tcx>,
+ ) -> Option<ty::FnSig<'tcx>> {
let tcx = self.tcx;
debug!("deduce_sig_from_projection({:?})", projection);
let arg_param_ty = trait_ref.substs().type_at(1);
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
- debug!("deduce_sig_from_projection: arg_param_ty {:?}",
- arg_param_ty);
+ debug!(
+ "deduce_sig_from_projection: arg_param_ty {:?}",
+ arg_param_ty
+ );
let input_tys = match arg_param_ty.sty {
ty::TyTuple(tys, _) => tys.into_iter(),
let ret_param_ty = projection.0.ty;
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
- debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
+ debug!(
+ "deduce_sig_from_projection: ret_param_ty {:?}",
+ ret_param_ty
+ );
let fn_sig = self.tcx.mk_fn_sig(
input_tys.cloned(),
ret_param_ty,
false,
hir::Unsafety::Normal,
- Abi::Rust
+ Abi::Rust,
);
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
Some(fn_sig)
}
- fn self_type_matches_expected_vid(&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
- expected_vid: ty::TyVid)
- -> Option<ty::PolyTraitRef<'tcx>> {
+ fn self_type_matches_expected_vid(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ expected_vid: ty::TyVid,
+ ) -> Option<ty::PolyTraitRef<'tcx>> {
let self_ty = self.shallow_resolve(trait_ref.self_ty());
- debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
- trait_ref,
- self_ty);
+ debug!(
+ "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
+ trait_ref,
+ self_ty
+ );
match self_ty.sty {
ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
_ => None,
}
}
+
+ fn sig_of_closure(
+ &self,
+ expr_def_id: DefId,
+ decl: &hir::FnDecl,
+ body: &hir::Body,
+ expected_sig: Option<ty::FnSig<'tcx>>,
+ ) -> ClosureSignatures<'tcx> {
+ if let Some(e) = expected_sig {
+ self.sig_of_closure_with_expectation(expr_def_id, decl, body, e)
+ } else {
+ self.sig_of_closure_no_expectation(expr_def_id, decl, body)
+ }
+ }
+
+ /// If there is no expected signature, then we will convert the
+ /// types that the user gave into a signature.
+ fn sig_of_closure_no_expectation(
+ &self,
+ expr_def_id: DefId,
+ decl: &hir::FnDecl,
+ body: &hir::Body,
+ ) -> ClosureSignatures<'tcx> {
+ debug!("sig_of_closure_no_expectation()");
+
+ let bound_sig = self.supplied_sig_of_closure(decl);
+
+ self.closure_sigs(expr_def_id, body, bound_sig)
+ }
+
+ /// Invoked to compute the signature of a closure expression. This
+ /// combines any user-provided type annotations (e.g., `|x: u32|
+ /// -> u32 { .. }`) with the expected signature.
+ ///
+ /// The approach is as follows:
+ ///
+ /// - Let `S` be the (higher-ranked) signature that we derive from the user's annotations.
+ /// - Let `E` be the (higher-ranked) signature that we derive from the expectations, if any.
+ /// - If we have no expectation `E`, then the signature of the closure is `S`.
+ /// - Otherwise, the signature of the closure is E. Moreover:
+ /// - Skolemize the late-bound regions in `E`, yielding `E'`.
+ /// - Instantiate all the late-bound regions bound in the closure within `S`
+ /// with fresh (existential) variables, yielding `S'`
+ /// - Require that `E' = S'`
+ /// - We could use some kind of subtyping relationship here,
+ /// I imagine, but equality is easier and works fine for
+ /// our purposes.
+ ///
+ /// The key intuition here is that the user's types must be valid
+ /// from "the inside" of the closure, but the expectation
+ /// ultimately drives the overall signature.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// fn with_closure<F>(_: F)
+ /// where F: Fn(&u32) -> &u32 { .. }
+ ///
+ /// with_closure(|x: &u32| { ... })
+ /// ```
+ ///
+ /// Here:
+ /// - E would be `fn(&u32) -> &u32`.
+ /// - S would be `fn(&u32) ->
+ /// - E' is `&'!0 u32 -> &'!0 u32`
+ /// - S' is `&'?0 u32 -> ?T`
+ ///
+ /// S' can be unified with E' with `['?0 = '!0, ?T = &'!10 u32]`.
+ ///
+ /// # Arguments
+ ///
+ /// - `expr_def_id`: the def-id of the closure expression
+ /// - `decl`: the HIR declaration of the closure
+ /// - `body`: the body of the closure
+ /// - `expected_sig`: the expected signature (if any). Note that
+ /// this is missing a binder: that is, there may be late-bound
+ /// regions with depth 1, which are bound then by the closure.
+ fn sig_of_closure_with_expectation(
+ &self,
+ expr_def_id: DefId,
+ decl: &hir::FnDecl,
+ body: &hir::Body,
+ expected_sig: ty::FnSig<'tcx>,
+ ) -> ClosureSignatures<'tcx> {
+ debug!(
+ "sig_of_closure_with_expectation(expected_sig={:?})",
+ expected_sig
+ );
+
+ // Watch out for some surprises and just ignore the
+ // expectation if things don't see to match up with what we
+ // expect.
+ if expected_sig.variadic != decl.variadic {
+ return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
+ } else if expected_sig.inputs_and_output.len() != decl.inputs.len() + 1 {
+ // we could probably handle this case more gracefully
+ return self.sig_of_closure_no_expectation(expr_def_id, decl, body);
+ }
+
+ // Create a `PolyFnSig`. Note the oddity that late bound
+ // regions appearing free in `expected_sig` are now bound up
+ // in this binder we are creating.
+ assert!(!expected_sig.has_regions_escaping_depth(1));
+ let bound_sig = ty::Binder(self.tcx.mk_fn_sig(
+ expected_sig.inputs().iter().cloned(),
+ expected_sig.output(),
+ decl.variadic,
+ hir::Unsafety::Normal,
+ Abi::RustCall,
+ ));
+
+ // `deduce_expectations_from_expected_type` introduces
+ // late-bound lifetimes defined elsewhere, which we now
+ // anonymize away, so as not to confuse the user.
+ let bound_sig = self.tcx.anonymize_late_bound_regions(&bound_sig);
+
+ let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig);
+
+ // Up till this point, we have ignored the annotations that the user
+ // gave. This function will check that they unify successfully.
+ // Along the way, it also writes out entries for types that the user
+ // wrote into our tables, which are then later used by the privacy
+ // check.
+ match self.check_supplied_sig_against_expectation(decl, &closure_sigs) {
+ Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
+ Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body),
+ }
+
+ closure_sigs
+ }
+
+ /// Enforce the user's types against the expectation. See
+ /// `sig_of_closure_with_expectation` for details on the overall
+ /// strategy.
+ fn check_supplied_sig_against_expectation(
+ &self,
+ decl: &hir::FnDecl,
+ expected_sigs: &ClosureSignatures<'tcx>,
+ ) -> InferResult<'tcx, ()> {
+ // Get the signature S that the user gave.
+ //
+ // (See comment on `sig_of_closure_with_expectation` for the
+ // meaning of these letters.)
+ let supplied_sig = self.supplied_sig_of_closure(decl);
+
+ debug!(
+ "check_supplied_sig_against_expectation: supplied_sig={:?}",
+ supplied_sig
+ );
+
+ // FIXME(#45727): As discussed in [this comment][c1], naively
+ // forcing equality here actually results in suboptimal error
+ // messages in some cases. For now, if there would have been
+ // an obvious error, we fallback to declaring the type of the
+ // closure to be the one the user gave, which allows other
+ // error message code to trigger.
+ //
+ // However, I think [there is potential to do even better
+ // here][c2], since in *this* code we have the precise span of
+ // the type parameter in question in hand when we report the
+ // error.
+ //
+ // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706
+ // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
+ self.infcx.commit_if_ok(|_| {
+ let mut all_obligations = vec![];
+
+ // The liberated version of this signature should be be a subtype
+ // of the liberated form of the expectation.
+ for ((hir_ty, &supplied_ty), expected_ty) in decl.inputs.iter()
+ .zip(*supplied_sig.inputs().skip_binder()) // binder moved to (*) below
+ .zip(expected_sigs.liberated_sig.inputs())
+ // `liberated_sig` is E'.
+ {
+ // Instantiate (this part of..) S to S', i.e., with fresh variables.
+ let (supplied_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var(
+ hir_ty.span,
+ LateBoundRegionConversionTime::FnCall,
+ &ty::Binder(supplied_ty),
+ ); // recreated from (*) above
+
+ // Check that E' = S'.
+ let cause = &self.misc(hir_ty.span);
+ let InferOk {
+ value: (),
+ obligations,
+ } = self.at(cause, self.param_env)
+ .eq(*expected_ty, supplied_ty)?;
+ all_obligations.extend(obligations);
+ }
+
+ let (supplied_output_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var(
+ decl.output.span(),
+ LateBoundRegionConversionTime::FnCall,
+ &supplied_sig.output(),
+ );
+ let cause = &self.misc(decl.output.span());
+ let InferOk {
+ value: (),
+ obligations,
+ } = self.at(cause, self.param_env)
+ .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?;
+ all_obligations.extend(obligations);
+
+ Ok(InferOk {
+ value: (),
+ obligations: all_obligations,
+ })
+ })
+ }
+
+ /// If there is no expected signature, then we will convert the
+ /// types that the user gave into a signature.
+ fn supplied_sig_of_closure(&self, decl: &hir::FnDecl) -> ty::PolyFnSig<'tcx> {
+ let astconv: &AstConv = self;
+
+ // First, convert the types that the user supplied (if any).
+ let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
+ let supplied_return = match decl.output {
+ hir::Return(ref output) => astconv.ast_ty_to_ty(&output),
+ hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()),
+ };
+
+ let result = ty::Binder(self.tcx.mk_fn_sig(
+ supplied_arguments,
+ supplied_return,
+ decl.variadic,
+ hir::Unsafety::Normal,
+ Abi::RustCall,
+ ));
+
+ debug!("supplied_sig_of_closure: result={:?}", result);
+
+ result
+ }
+
+ fn closure_sigs(
+ &self,
+ expr_def_id: DefId,
+ body: &hir::Body,
+ bound_sig: ty::PolyFnSig<'tcx>,
+ ) -> ClosureSignatures<'tcx> {
+ let liberated_sig = self.liberate_late_bound_regions(expr_def_id, &bound_sig);
+ let liberated_sig = self.inh.normalize_associated_types_in(
+ body.value.span,
+ body.value.id,
+ self.param_env,
+ &liberated_sig,
+ );
+ ClosureSignatures {
+ bound_sig,
+ liberated_sig,
+ }
+ }
}
ty::TySlice(_) => {
let lang_def_id = lang_items.slice_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.slice_u8_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
let lang_def_id = lang_items.const_ptr_impl();
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
use session::{CompileIncomplete, Session};
use TypeAndSubsts;
if expected_count == 1 {""} else {"s"},
arg_count,
if arg_count == 1 {" was"} else {"s were"}),
- error_code);
+ DiagnosticId::Error(error_code.to_owned()));
if let Some(def_s) = def_span {
err.span_label(def_s, "defined here");
hir::QPath::TypeRelative(ref qself, _) => qself.span
};
+ // Prohibit struct expressions when non exhaustive flag is set.
+ if let ty::TyAdt(adt, _) = struct_ty.sty {
+ if !adt.did.is_local() && adt.is_non_exhaustive() {
+ span_err!(self.tcx.sess, expr.span, E0639,
+ "cannot create non-exhaustive {} using struct expression",
+ adt.variant_descr());
+ }
+ }
+
self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields,
base_expr.is_none());
if let &Some(ref base_expr) = base_expr {
// FIXME(#27579) what amount of WF checking do we need for neg impls?
let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();
- if !tcx.trait_has_default_impl(trait_ref.def_id) {
+ if !tcx.trait_is_auto(trait_ref.def_id) {
error_192(tcx, item.span);
}
}
fn check_trait(&mut self, item: &hir::Item) {
let trait_def_id = self.tcx.hir.local_def_id(item.id);
- if self.tcx.trait_has_default_impl(trait_def_id) {
+ if self.tcx.trait_is_auto(trait_def_id) {
self.check_auto_trait(trait_def_id, item.span);
}
"str",
item.span);
}
+ ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => {
+ self.check_primitive_impl(def_id,
+ lang_items.slice_u8_impl(),
+ "slice_u8",
+ "[u8]",
+ item.span);
+ }
ty::TySlice(_) => {
self.check_primitive_impl(def_id,
lang_items.slice_impl(),
unsafety::check(tcx);
orphan::check(tcx);
- overlap::check_default_impls(tcx);
+ overlap::check_auto_impls(tcx);
// these queries are executed for side-effects (error reporting):
tcx.crate_inherent_impls(LOCAL_CRATE);
// This final impl is legal according to the orpan
// rules, but it invalidates the reasoning from
// `two_foos` above.
- debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
+ debug!("trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
trait_ref,
trait_def_id,
- self.tcx.trait_has_default_impl(trait_def_id));
- if self.tcx.trait_has_default_impl(trait_def_id) &&
+ self.tcx.trait_is_auto(trait_def_id));
+ if self.tcx.trait_is_auto(trait_def_id) &&
!trait_def_id.is_local() {
let self_ty = trait_ref.self_ty();
let opt_self_def_id = match self_ty.sty {
}
}
}
- hir::ItemDefaultImpl(_, ref item_trait_ref) => {
+ hir::ItemAutoImpl(_, ref item_trait_ref) => {
// "Trait" impl
debug!("coherence2::orphan check: default trait impl {}",
self.tcx.hir.node_to_string(item.id));
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
-pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn check_auto_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut overlap = OverlapChecker { tcx };
// this secondary walk specifically checks for some other cases,
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
- hir::ItemDefaultImpl(..) => {
- // look for another default impl; note that due to the
+ hir::ItemAutoImpl(..) => {
+ // look for another auto impl; note that due to the
// general orphan/coherence rules, it must always be
// in this crate.
let impl_def_id = self.tcx.hir.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
- let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
+ let prev_id = self.tcx.hir.trait_auto_impl(trait_ref.def_id).unwrap();
if prev_id != item.id {
let mut err = struct_span_err!(self.tcx.sess,
self.tcx.span_of_impl(impl_def_id).unwrap(),
E0521,
- "redundant default implementations of trait \
+ "redundant auto implementations of trait \
`{}`:",
trait_ref);
err.span_note(self.tcx
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
- hir::ItemDefaultImpl(unsafety, _) => {
+ hir::ItemAutoImpl(unsafety, _) => {
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
}
hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => {
impl_trait_ref,
impl_polarity,
is_foreign_item,
- is_default_impl,
+ is_auto_impl,
..*providers
};
}
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) => generics,
- ItemTrait(_, ref generics, ..) => {
+ ItemTrait(_, _, ref generics, ..) => {
// Implied `Self: Trait` and supertrait bounds.
if param_id == item_node_id {
result.predicates.push(ty::TraitRef {
tcx.predicates_of(def_id);
convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
},
- hir::ItemDefaultImpl(..) => {
+ hir::ItemAutoImpl(..) => {
tcx.impl_trait_ref(def_id);
}
hir::ItemImpl(..) => {
};
let (generics, bounds) = match item.node {
- hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
+ hir::ItemTrait(.., ref generics, ref supertraits, _) => (generics, supertraits),
_ => span_bug!(item.span,
"super_predicates invoked on non-trait"),
};
let item = tcx.hir.expect_item(node_id);
let unsafety = match item.node {
- hir::ItemTrait(unsafety, ..) => unsafety,
+ hir::ItemTrait(_, unsafety, ..) => unsafety,
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};
}
let def_path_hash = tcx.def_path_hash(def_id);
- let has_default_impl = tcx.hir.trait_is_auto(def_id);
+ let is_auto = match item.node {
+ hir::ItemTrait(hir::IsAuto::Yes, ..) => true,
+ _ => tcx.hir.trait_is_auto(def_id),
+ };
let def = ty::TraitDef::new(def_id,
unsafety,
paren_sugar,
- has_default_impl,
+ is_auto,
def_path_hash);
tcx.alloc_trait_def(def)
}
generics
}
- ItemTrait(_, ref generics, ..) => {
+ ItemTrait(_, _, ref generics, ..) => {
// Add in the self type parameter.
//
// Something of a hack: use the node id for the trait, also as
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
- ItemDefaultImpl(..) |
+ ItemAutoImpl(..) |
ItemTrait(..) |
ItemMod(..) |
ItemForeignMod(..) |
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
match tcx.hir.expect_item(node_id).node {
- hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
+ hir::ItemAutoImpl(_, ref ast_trait_ref) => {
Some(AstConv::instantiate_mono_trait_ref(&icx,
ast_trait_ref,
tcx.mk_self_type()))
generics
}
- ItemTrait(_, ref generics, .., ref items) => {
+ ItemTrait(_, _, ref generics, .., ref items) => {
is_trait = Some((ty::TraitRef {
def_id,
substs: Substs::identity_for_item(tcx, def_id)
}
}
-fn is_default_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> bool {
match tcx.hir.get_if_local(def_id) {
- Some(hir_map::NodeItem(&hir::Item { node: hir::ItemDefaultImpl(..), .. }))
+ Some(hir_map::NodeItem(&hir::Item { node: hir::ItemAutoImpl(..), .. }))
=> true,
Some(_) => false,
- _ => bug!("is_default_impl applied to non-local def-id {:?}", def_id)
+ _ => bug!("is_auto_impl applied to non-local def-id {:?}", def_id)
}
}
This will compile:
-```
+```ignore (ignore auto_trait future compatibility warning)
#![feature(optin_builtin_traits)]
struct Foo;
```
"##,
+E0638: r##"
+This error indicates that the struct or enum must be matched non-exhaustively
+as it has been marked as `non_exhaustive`.
+
+When applied within a crate, downstream users of the crate will need to use the
+`_` pattern when matching enums and use the `..` pattern when matching structs.
+
+For example, in the below example, since the enum is marked as
+`non_exhaustive`, it is required that downstream crates match non-exhaustively
+on it.
+
+```rust,ignore (pseudo-Rust)
+use std::error::Error as StdError;
+
+#[non_exhaustive] pub enum Error {
+ Message(String),
+ Other,
+}
+
+impl StdError for Error {
+ fn description(&self) -> &str {
+ // This will not error, despite being marked as non_exhaustive, as this
+ // enum is defined within the current crate, it can be matched
+ // exhaustively.
+ match *self {
+ Message(ref s) => s,
+ Other => "other or unknown error",
+ }
+ }
+}
+```
+
+An example of matching non-exhaustively on the above enum is provided below:
+
+```rust,ignore (pseudo-Rust)
+use mycrate::Error;
+
+// This will not error as the non_exhaustive Error enum has been matched with a
+// wildcard.
+match error {
+ Message(ref s) => ...,
+ Other => ...,
+ _ => ...,
+}
+```
+
+Similarly, for structs, match with `..` to avoid this error.
+"##,
+
+E0639: r##"
+This error indicates that the struct or enum cannot be instantiated from
+outside of the defining crate as it has been marked as `non_exhaustive` and as
+such more fields/variants may be added in future that could cause adverse side
+effects for this code.
+
+It is recommended that you look for a `new` function or equivalent in the
+crate's documentation.
+"##,
+
}
register_diagnostics! {
// E0372, // coherence not object safe
E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
// between structures with the same definition
- E0521, // redundant default implementations of trait
+ E0521, // redundant auto implementations of trait
E0533, // `{}` does not name a unit variant, unit struct or a constant
// E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15
E0564, // only named lifetimes are allowed in `impl Trait`,
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
+#![feature(match_default_bindings)]
#![feature(never_type)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
use std::mem;
use std::fmt::{self, Write};
use std::ops;
+#[cfg(stage0)]
use std::ascii::AsciiExt;
use syntax::symbol::Symbol;
}
}
- // If this is a defaulted impl, then bail out early here
- if tcx.is_default_impl(did) {
+ // If this is an auto impl, then bail out early here
+ if tcx.is_auto_impl(did) {
return ret.push(clean::Item {
- inner: clean::DefaultImplItem(clean::DefaultImpl {
+ inner: clean::AutoImplItem(clean::AutoImpl {
// FIXME: this should be decoded
unsafety: hir::Unsafety::Normal,
trait_: match associated_trait.as_ref().unwrap().clean(cx) {
PrimitiveItem(PrimitiveType),
AssociatedConstItem(Type, Option<String>),
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
- DefaultImplItem(DefaultImpl),
+ AutoImplItem(AutoImpl),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>),
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct DefaultImpl {
+pub struct AutoImpl {
pub unsafety: hir::Unsafety,
pub trait_: Type,
}
-impl Clean<Item> for doctree::DefaultImpl {
+impl Clean<Item> for doctree::AutoImpl {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: None,
visibility: Some(Public),
stability: None,
deprecation: None,
- inner: DefaultImplItem(DefaultImpl {
+ inner: AutoImplItem(AutoImpl {
unsafety: self.unsafety,
trait_: self.trait_.clean(cx),
}),
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
pub impls: Vec<Impl>,
- pub def_traits: Vec<DefaultImpl>,
+ pub def_traits: Vec<AutoImpl>,
pub foreigns: Vec<hir::ForeignMod>,
pub macros: Vec<Macro>,
pub is_crate: bool,
pub id: ast::NodeId,
}
-pub struct DefaultImpl {
+pub struct AutoImpl {
pub unsafety: hir::Unsafety,
pub trait_: hir::TraitRef,
pub id: ast::NodeId,
clean::PrimitiveItem(..) => ItemType::Primitive,
clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
- clean::DefaultImplItem(..) => ItemType::Impl,
+ clean::AutoImplItem(..) => ItemType::Impl,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::StrippedItem(..) => unreachable!(),
}
use libc;
use std::slice;
-use std::ascii::AsciiExt;
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::default::Default;
//! both occur before the crate is rendered.
pub use self::ExternalLocation::*;
+#[cfg(stage0)]
use std::ascii::AsciiExt;
use std::cell::RefCell;
use std::cmp::Ordering;
document(w, cx, item)?;
let mut indices = (0..items.len()).filter(|i| {
- if let clean::DefaultImplItem(..) = items[*i].inner {
+ if let clean::AutoImplItem(..) = items[*i].inner {
return false;
}
!items[*i].is_stripped()
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
if items.iter().any(|it| {
- if let clean::DefaultImplItem(..) = it.inner {
+ if let clean::AutoImplItem(..) = it.inner {
false
} else {
!it.is_stripped() && it.type_() == myty
var valLower = query.query.toLowerCase(),
val = valLower,
typeFilter = itemTypeFromName(query.type),
- results = [],
+ results = {},
split = valLower.split("::");
// remove empty keywords
}
}
+ function min(a, b) {
+ if (a < b) {
+ return a;
+ }
+ return b;
+ }
+
+ function nbElements(obj) {
+ var size = 0, key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ size += 1;
+ }
+ }
+ return size;
+ }
+
function findArg(obj, val) {
+ var lev_distance = MAX_LEV_DISTANCE + 1;
if (obj && obj.type && obj.type.inputs.length > 0) {
for (var i = 0; i < obj.type.inputs.length; i++) {
if (obj.type.inputs[i].name === val) {
- return true;
+ // No need to check anything else: we found it. Let's just move on.
+ return 0;
+ }
+ lev_distance = min(levenshtein(obj.type.inputs[i].name, val), lev_distance);
+ if (lev_distance === 0) {
+ return 0;
}
}
}
- return false;
+ return lev_distance;
+ }
+
+ function checkReturned(obj, val) {
+ var lev_distance = MAX_LEV_DISTANCE + 1;
+ if (obj && obj.type && obj.type.output) {
+ if (obj.type.output.name.toLowerCase() === val) {
+ return 0;
+ }
+ lev_distance = min(levenshtein(obj.type.output.name, val));
+ if (lev_distance === 0) {
+ return 0;
+ }
+ }
+ return lev_distance;
}
function typePassesFilter(filter, type) {
if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
val.charAt(val.length - 1) === val.charAt(0))
{
- val = val.substr(1, val.length - 2);
+ val = val.substr(1, val.length - 2).toLowerCase();
for (var i = 0; i < nSearchWords; ++i) {
+ var ty = searchIndex[i];
if (searchWords[i] === val) {
// filter type: ... queries
if (typePassesFilter(typeFilter, searchIndex[i].ty)) {
- results.push({id: i, index: -1});
+ results[ty.path + ty.name] = {id: i, index: -1};
}
- } else if (findArg(searchIndex[i], val.toLowerCase()) ||
- (searchIndex[i].type &&
- searchIndex[i].type.output &&
- searchIndex[i].type.output.name === val.toLowerCase())) {
+ } else if (findArg(searchIndex[i], val) ||
+ (ty.type &&
+ ty.type.output &&
+ ty.type.output.name === val)) {
if (typePassesFilter(typeFilter, searchIndex[i].ty)) {
- results.push({id: i, index: -1, dontValidate: true});
+ results[ty.path + ty.name] = {
+ id: i,
+ index: -1,
+ dontValidate: true,
+ };
}
}
- if (results.length === max) {
+ if (nbElements(results) === max) {
break;
}
}
for (var i = 0; i < nSearchWords; ++i) {
var type = searchIndex[i].type;
+ var ty = searchIndex[i];
if (!type) {
continue;
}
var typeOutput = type.output ? type.output.name : "";
if (output === "*" || output == typeOutput) {
if (input === "*") {
- results.push({id: i, index: -1, dontValidate: true});
+ results[ty.path + ty.name] = {id: i, index: -1, dontValidate: true};
} else {
var allFound = true;
for (var it = 0; allFound === true && it < inputs.length; it++) {
allFound = found;
}
if (allFound === true) {
- results.push({id: i, index: -1, dontValidate: true});
+ results[ty.path + ty.name] = {
+ id: i,
+ index: -1,
+ dontValidate: true,
+ };
}
}
}
for (var i = 0; i < split.length; ++i) {
for (var j = 0; j < nSearchWords; ++j) {
var lev_distance;
+ var ty = searchIndex[j];
+ if (!ty) {
+ continue;
+ }
if (searchWords[j].indexOf(split[i]) > -1 ||
searchWords[j].indexOf(val) > -1 ||
searchWords[j].replace(/_/g, "").indexOf(val) > -1)
{
// filter type: ... queries
if (typePassesFilter(typeFilter, searchIndex[j].ty)) {
- results.push({
+ results[ty.path + ty.name] = {
id: j,
index: searchWords[j].replace(/_/g, "").indexOf(val),
lev: 0,
- });
+ };
}
} else if (
- (lev_distance = levenshtein(searchWords[j], val)) <=
- MAX_LEV_DISTANCE) {
+ (lev_distance = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
if (typePassesFilter(typeFilter, searchIndex[j].ty)) {
- results.push({
- id: j,
- index: 0,
- // we want lev results to go lower than others
- lev: lev_distance,
- });
+ if (results[ty.path + ty.name] === undefined ||
+ results[ty.path + ty.name].lev > lev_distance) {
+ results[ty.path + ty.name] = {
+ id: j,
+ index: 0,
+ // we want lev results to go lower than others
+ lev: lev_distance,
+ };
+ }
}
- } else if (findArg(searchIndex[j], val)) {
+ } else if (
+ (lev_distance = findArg(searchIndex[j], val)) <= MAX_LEV_DISTANCE) {
if (typePassesFilter(typeFilter, searchIndex[j].ty)) {
- results.push({
- id: j,
- index: 0,
- // we want lev results to go lower than others
- lev: lev_distance,
- });
+ if (results[ty.path + ty.name] === undefined ||
+ results[ty.path + ty.name].lev > lev_distance) {
+ results[ty.path + ty.name] = {
+ id: j,
+ index: 0,
+ // we want lev results to go lower than others
+ lev: lev_distance,
+ };
+ }
+ }
+ } else if (
+ (lev_distance = checkReturned(searchIndex[j], val)) <=
+ MAX_LEV_DISTANCE) {
+ if (typePassesFilter(typeFilter, searchIndex[j].ty)) {
+ if (results[ty.path + ty.name] === undefined ||
+ results[ty.path + ty.name].lev > lev_distance) {
+ results[ty.path + ty.name] = {
+ id: j,
+ index: 0,
+ // we want lev results to go lower than others
+ lev: lev_distance,
+ };
+ }
}
}
- if (results.length === max) {
+ if (nbElements(results) === max) {
break;
}
}
}
}
+ var ar = [];
+ for (var entry in results) {
+ if (results.hasOwnProperty(entry)) {
+ ar.push(results[entry]);
+ }
+ }
+ results = ar;
var nresults = results.length;
for (var i = 0; i < nresults; ++i) {
results[i].word = searchWords[results[i].id];
return 0;
});
- // remove duplicates, according to the data provided
- for (var i = results.length - 1; i > 0; i -= 1) {
- if (results[i].word === results[i - 1].word &&
- results[i].item.ty === results[i - 1].item.ty &&
- results[i].item.path === results[i - 1].item.path &&
- (results[i].item.parent || {}).name === (results[i - 1].item.parent || {}).name)
- {
- results[i].id = -1;
- }
- }
for (var i = 0; i < results.length; ++i) {
var result = results[i],
name = result.item.name.toLowerCase(),
elems[0].onclick = function() { printTab(0); };
elems[1].onclick = function() { printTab(1); };
elems[2].onclick = function() { printTab(2); };
+ printTab(currentTab);
}
function search(e) {
}
}
if (results['others'].length < maxResults &&
- ((query.search && obj.name.indexOf(query.search)) || added === false)) {
+ ((query.search && obj.name.indexOf(query.search) !== -1) ||
+ added === false)) {
results['others'].push(obj);
}
}
html_playground_url = "https://play.rust-lang.org/")]
#![deny(warnings)]
+#![feature(ascii_ctype)]
#![feature(rustc_private)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(test)]
#![feature(unicode)]
#![feature(vec_remove_item)]
-#![feature(ascii_ctype)]
extern crate arena;
extern crate getopts;
// handled in the `strip-priv-imports` pass
clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
- clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
+ clean::AutoImplItem(..) | clean::ImplItem(..) => {}
// tymethods/macros have no control over privacy
clean::MacroItem(..) | clean::TyMethodItem(..) => {}
};
om.constants.push(s);
},
- hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => {
+ hir::ItemTrait(_, unsafety, ref gen, ref b, ref item_ids) => {
let items = item_ids.iter()
.map(|ti| self.cx.tcx.hir.trait_item(ti.id).clone())
.collect();
om.impls.push(i);
}
},
- hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
+ hir::ItemAutoImpl(unsafety, ref trait_ref) => {
// See comment above about ItemImpl.
if !self.inlining {
- let i = DefaultImpl {
+ let i = AutoImpl {
unsafety,
trait_: trait_ref.clone(),
id: item.id,
name = "std"
version = "0.0.0"
build = "build.rs"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rust-lang/rust.git"
+description = "The Rust Standard Library"
[lib]
name = "std"
/// ```
/// use std::ascii::AsciiExt;
///
-/// assert_eq!("café".to_ascii_uppercase(), "CAFÉ");
-/// assert_eq!("café".to_ascii_uppercase(), "CAFé");
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFÉ");
+/// assert_eq!(AsciiExt::to_ascii_uppercase("café"), "CAFé");
/// ```
///
/// In the first example, the lowercased string is represented `"cafe\u{301}"`
/// Checks if the value is within the ASCII range.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let ascii = 'a';
- /// let non_ascii = '❤';
- /// let int_ascii = 97;
- ///
- /// assert!(ascii.is_ascii());
- /// assert!(!non_ascii.is_ascii());
- /// assert!(int_ascii.is_ascii());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[stable(feature = "rust1", since = "1.0.0")]
fn is_ascii(&self) -> bool;
/// To uppercase ASCII characters in addition to non-ASCII characters, use
/// [`str::to_uppercase`].
///
- /// # Examples
- ///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let ascii = 'a';
- /// let non_ascii = '❤';
- /// let int_ascii = 97;
+ /// # Note
///
- /// assert_eq!('A', ascii.to_ascii_uppercase());
- /// assert_eq!('❤', non_ascii.to_ascii_uppercase());
- /// assert_eq!(65, int_ascii.to_ascii_uppercase());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
/// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase
/// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase
/// To lowercase ASCII characters in addition to non-ASCII characters, use
/// [`str::to_lowercase`].
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let ascii = 'A';
- /// let non_ascii = '❤';
- /// let int_ascii = 65;
- ///
- /// assert_eq!('a', ascii.to_ascii_lowercase());
- /// assert_eq!('❤', non_ascii.to_ascii_lowercase());
- /// assert_eq!(97, int_ascii.to_ascii_lowercase());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
/// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase
/// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
/// but without allocating and copying temporaries.
///
- /// # Examples
- ///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let ascii1 = 'A';
- /// let ascii2 = 'a';
- /// let ascii3 = 'A';
- /// let ascii4 = 'z';
+ /// # Note
///
- /// assert!(ascii1.eq_ignore_ascii_case(&ascii2));
- /// assert!(ascii1.eq_ignore_ascii_case(&ascii3));
- /// assert!(!ascii1.eq_ignore_ascii_case(&ascii4));
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[stable(feature = "rust1", since = "1.0.0")]
fn eq_ignore_ascii_case(&self, other: &Self) -> bool;
/// To return a new uppercased value without modifying the existing one, use
/// [`to_ascii_uppercase`].
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// use std::ascii::AsciiExt;
- ///
- /// let mut ascii = 'a';
- ///
- /// ascii.make_ascii_uppercase();
- ///
- /// assert_eq!('A', ascii);
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
/// [`to_ascii_uppercase`]: #tymethod.to_ascii_uppercase
#[stable(feature = "ascii", since = "1.9.0")]
/// To return a new lowercased value without modifying the existing one, use
/// [`to_ascii_lowercase`].
///
- /// # Examples
- ///
- /// ```
- /// use std::ascii::AsciiExt;
+ /// # Note
///
- /// let mut ascii = 'A';
- ///
- /// ascii.make_ascii_lowercase();
- ///
- /// assert_eq!('a', ascii);
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
///
/// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
#[stable(feature = "ascii", since = "1.9.0")]
/// For strings, true if all characters in the string are
/// ASCII alphabetic.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
- ///
- /// assert!(A.is_ascii_alphabetic());
- /// assert!(G.is_ascii_alphabetic());
- /// assert!(a.is_ascii_alphabetic());
- /// assert!(g.is_ascii_alphabetic());
- /// assert!(!zero.is_ascii_alphabetic());
- /// assert!(!percent.is_ascii_alphabetic());
- /// assert!(!space.is_ascii_alphabetic());
- /// assert!(!lf.is_ascii_alphabetic());
- /// assert!(!esc.is_ascii_alphabetic());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII uppercase.
///
- /// # Examples
- ///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
+ /// # Note
///
- /// assert!(A.is_ascii_uppercase());
- /// assert!(G.is_ascii_uppercase());
- /// assert!(!a.is_ascii_uppercase());
- /// assert!(!g.is_ascii_uppercase());
- /// assert!(!zero.is_ascii_uppercase());
- /// assert!(!percent.is_ascii_uppercase());
- /// assert!(!space.is_ascii_uppercase());
- /// assert!(!lf.is_ascii_uppercase());
- /// assert!(!esc.is_ascii_uppercase());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII lowercase.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
- ///
- /// assert!(!A.is_ascii_lowercase());
- /// assert!(!G.is_ascii_lowercase());
- /// assert!(a.is_ascii_lowercase());
- /// assert!(g.is_ascii_lowercase());
- /// assert!(!zero.is_ascii_lowercase());
- /// assert!(!percent.is_ascii_lowercase());
- /// assert!(!space.is_ascii_lowercase());
- /// assert!(!lf.is_ascii_lowercase());
- /// assert!(!esc.is_ascii_lowercase());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII alphanumeric.
///
- /// # Examples
- ///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
+ /// # Note
///
- /// assert!(A.is_ascii_alphanumeric());
- /// assert!(G.is_ascii_alphanumeric());
- /// assert!(a.is_ascii_alphanumeric());
- /// assert!(g.is_ascii_alphanumeric());
- /// assert!(zero.is_ascii_alphanumeric());
- /// assert!(!percent.is_ascii_alphanumeric());
- /// assert!(!space.is_ascii_alphanumeric());
- /// assert!(!lf.is_ascii_alphanumeric());
- /// assert!(!esc.is_ascii_alphanumeric());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII digits.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
- ///
- /// assert!(!A.is_ascii_digit());
- /// assert!(!G.is_ascii_digit());
- /// assert!(!a.is_ascii_digit());
- /// assert!(!g.is_ascii_digit());
- /// assert!(zero.is_ascii_digit());
- /// assert!(!percent.is_ascii_digit());
- /// assert!(!space.is_ascii_digit());
- /// assert!(!lf.is_ascii_digit());
- /// assert!(!esc.is_ascii_digit());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_digit(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII hex digits.
///
- /// # Examples
- ///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
+ /// # Note
///
- /// assert!(A.is_ascii_hexdigit());
- /// assert!(!G.is_ascii_hexdigit());
- /// assert!(a.is_ascii_hexdigit());
- /// assert!(!g.is_ascii_hexdigit());
- /// assert!(zero.is_ascii_hexdigit());
- /// assert!(!percent.is_ascii_hexdigit());
- /// assert!(!space.is_ascii_hexdigit());
- /// assert!(!lf.is_ascii_hexdigit());
- /// assert!(!esc.is_ascii_hexdigit());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII punctuation.
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
- ///
- /// assert!(!A.is_ascii_punctuation());
- /// assert!(!G.is_ascii_punctuation());
- /// assert!(!a.is_ascii_punctuation());
- /// assert!(!g.is_ascii_punctuation());
- /// assert!(!zero.is_ascii_punctuation());
- /// assert!(percent.is_ascii_punctuation());
- /// assert!(!space.is_ascii_punctuation());
- /// assert!(!lf.is_ascii_punctuation());
- /// assert!(!esc.is_ascii_punctuation());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
/// For strings, true if all characters in the string are
/// ASCII punctuation.
///
- /// # Examples
- ///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
+ /// # Note
///
- /// assert!(A.is_ascii_graphic());
- /// assert!(G.is_ascii_graphic());
- /// assert!(a.is_ascii_graphic());
- /// assert!(g.is_ascii_graphic());
- /// assert!(zero.is_ascii_graphic());
- /// assert!(percent.is_ascii_graphic());
- /// assert!(!space.is_ascii_graphic());
- /// assert!(!lf.is_ascii_graphic());
- /// assert!(!esc.is_ascii_graphic());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
/// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
/// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
///
- /// # Examples
+ /// # Note
///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
- ///
- /// assert!(!A.is_ascii_whitespace());
- /// assert!(!G.is_ascii_whitespace());
- /// assert!(!a.is_ascii_whitespace());
- /// assert!(!g.is_ascii_whitespace());
- /// assert!(!zero.is_ascii_whitespace());
- /// assert!(!percent.is_ascii_whitespace());
- /// assert!(space.is_ascii_whitespace());
- /// assert!(lf.is_ascii_whitespace());
- /// assert!(!esc.is_ascii_whitespace());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
/// Note that most ASCII whitespace characters are control
/// characters, but SPACE is not.
///
- /// # Examples
- ///
- /// ```
- /// #![feature(ascii_ctype)]
- /// # #![allow(non_snake_case)]
- /// use std::ascii::AsciiExt;
- /// let A = 'A';
- /// let G = 'G';
- /// let a = 'a';
- /// let g = 'g';
- /// let zero = '0';
- /// let percent = '%';
- /// let space = ' ';
- /// let lf = '\n';
- /// let esc = '\u{001b}';
+ /// # Note
///
- /// assert!(!A.is_ascii_control());
- /// assert!(!G.is_ascii_control());
- /// assert!(!a.is_ascii_control());
- /// assert!(!g.is_ascii_control());
- /// assert!(!zero.is_ascii_control());
- /// assert!(!percent.is_ascii_control());
- /// assert!(!space.is_ascii_control());
- /// assert!(lf.is_ascii_control());
- /// assert!(esc.is_ascii_control());
- /// ```
+ /// This method will be deprecated in favor of the identically-named
+ /// inherent methods on `u8`, `char`, `[u8]` and `str`.
#[unstable(feature = "ascii_ctype", issue = "39658")]
fn is_ascii_control(&self) -> bool { unimplemented!(); }
}
+// FIXME(LukasKalbertodt): this impl block can be removed in the future. This is
+// possible once the stage0 compiler is new enough to contain the inherent
+// ascii methods for `[str]`. See FIXME comment further down.
+#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsciiExt for str {
type Owned = String;
}
}
+// FIXME(LukasKalbertodt): this impl block can be removed in the future. This is
+// possible once the stage0 compiler is new enough to contain the inherent
+// ascii methods for `[u8]`. See FIXME comment further down.
+#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
impl AsciiExt for [u8] {
type Owned = Vec<u8>;
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for u8 {
- type Owned = u8;
- #[inline]
- fn is_ascii(&self) -> bool { *self & 128 == 0 }
- #[inline]
- fn to_ascii_uppercase(&self) -> u8 { ASCII_UPPERCASE_MAP[*self as usize] }
- #[inline]
- fn to_ascii_lowercase(&self) -> u8 { ASCII_LOWERCASE_MAP[*self as usize] }
- #[inline]
- fn eq_ignore_ascii_case(&self, other: &u8) -> bool {
- self.to_ascii_lowercase() == other.to_ascii_lowercase()
- }
- #[inline]
- fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
- #[inline]
- fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
+macro_rules! impl_by_delegating {
+ ($ty:ty, $owned:ty) => {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl AsciiExt for $ty {
+ type Owned = $owned;
- #[inline]
- fn is_ascii_alphabetic(&self) -> bool {
- if *self >= 0x80 { return false; }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- L|Lx|U|Ux => true,
- _ => false
- }
- }
+ #[inline]
+ fn is_ascii(&self) -> bool { self.is_ascii() }
- #[inline]
- fn is_ascii_uppercase(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- U|Ux => true,
- _ => false
- }
- }
+ #[inline]
+ fn to_ascii_uppercase(&self) -> Self::Owned { self.to_ascii_uppercase() }
- #[inline]
- fn is_ascii_lowercase(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- L|Lx => true,
- _ => false
- }
- }
+ #[inline]
+ fn to_ascii_lowercase(&self) -> Self::Owned { self.to_ascii_lowercase() }
- #[inline]
- fn is_ascii_alphanumeric(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- D|L|Lx|U|Ux => true,
- _ => false
- }
- }
+ #[inline]
+ fn eq_ignore_ascii_case(&self, o: &Self) -> bool { self.eq_ignore_ascii_case(o) }
- #[inline]
- fn is_ascii_digit(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- D => true,
- _ => false
- }
- }
+ #[inline]
+ fn make_ascii_uppercase(&mut self) { self.make_ascii_uppercase(); }
- #[inline]
- fn is_ascii_hexdigit(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- D|Lx|Ux => true,
- _ => false
- }
- }
+ #[inline]
+ fn make_ascii_lowercase(&mut self) { self.make_ascii_lowercase(); }
- #[inline]
- fn is_ascii_punctuation(&self) -> bool {
- if *self >= 0x80 { return false }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- P => true,
- _ => false
- }
- }
+ #[inline]
+ fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() }
- #[inline]
- fn is_ascii_graphic(&self) -> bool {
- if *self >= 0x80 { return false; }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- Ux|U|Lx|L|D|P => true,
- _ => false
- }
- }
+ #[inline]
+ fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() }
- #[inline]
- fn is_ascii_whitespace(&self) -> bool {
- if *self >= 0x80 { return false; }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- Cw|W => true,
- _ => false
- }
- }
-
- #[inline]
- fn is_ascii_control(&self) -> bool {
- if *self >= 0x80 { return false; }
- match ASCII_CHARACTER_CLASS[*self as usize] {
- C|Cw => true,
- _ => false
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsciiExt for char {
- type Owned = char;
- #[inline]
- fn is_ascii(&self) -> bool {
- *self as u32 <= 0x7F
- }
+ #[inline]
+ fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() }
- #[inline]
- fn to_ascii_uppercase(&self) -> char {
- if self.is_ascii() {
- (*self as u8).to_ascii_uppercase() as char
- } else {
- *self
- }
- }
+ #[inline]
+ fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() }
- #[inline]
- fn to_ascii_lowercase(&self) -> char {
- if self.is_ascii() {
- (*self as u8).to_ascii_lowercase() as char
- } else {
- *self
- }
- }
+ #[inline]
+ fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() }
- #[inline]
- fn eq_ignore_ascii_case(&self, other: &char) -> bool {
- self.to_ascii_lowercase() == other.to_ascii_lowercase()
- }
+ #[inline]
+ fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() }
- #[inline]
- fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
- #[inline]
- fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
+ #[inline]
+ fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() }
- #[inline]
- fn is_ascii_alphabetic(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphabetic()
- }
+ #[inline]
+ fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() }
- #[inline]
- fn is_ascii_uppercase(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_uppercase()
- }
+ #[inline]
+ fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() }
- #[inline]
- fn is_ascii_lowercase(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_lowercase()
- }
-
- #[inline]
- fn is_ascii_alphanumeric(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphanumeric()
- }
-
- #[inline]
- fn is_ascii_digit(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_digit()
- }
-
- #[inline]
- fn is_ascii_hexdigit(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_hexdigit()
- }
-
- #[inline]
- fn is_ascii_punctuation(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_punctuation()
+ #[inline]
+ fn is_ascii_control(&self) -> bool { self.is_ascii_control() }
+ }
}
+}
- #[inline]
- fn is_ascii_graphic(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_graphic()
- }
+impl_by_delegating!(u8, u8);
+impl_by_delegating!(char, char);
- #[inline]
- fn is_ascii_whitespace(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_whitespace()
- }
+// FIXME(LukasKalbertodt): the macro invocation should replace the impl block
+// for `[u8]` above. But this is not possible until the stage0 compiler is new
+// enough to contain the inherent ascii methods for `[u8]`.
+#[cfg(not(stage0))]
+impl_by_delegating!([u8], Vec<u8>);
- #[inline]
- fn is_ascii_control(&self) -> bool {
- (*self as u32 <= 0x7f) && (*self as u8).is_ascii_control()
- }
-}
+// FIXME(LukasKalbertodt): the macro invocation should replace the impl block
+// for `str` above. But this is not possible until the stage0 compiler is new
+// enough to contain the inherent ascii methods for `str`.
+#[cfg(not(stage0))]
+impl_by_delegating!(str, String);
/// An iterator over the escaped version of a byte.
///
}
-static ASCII_LOWERCASE_MAP: [u8; 256] = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
- b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
- b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
- b'@',
-
- b'a', b'b', b'c', b'd', b'e', b'f', b'g',
- b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
- b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
- b'x', b'y', b'z',
-
- b'[', b'\\', b']', b'^', b'_',
- b'`', b'a', b'b', b'c', b'd', b'e', b'f', b'g',
- b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o',
- b'p', b'q', b'r', b's', b't', b'u', b'v', b'w',
- b'x', b'y', b'z', b'{', b'|', b'}', b'~', 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
-
-static ASCII_UPPERCASE_MAP: [u8; 256] = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
- b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
- b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
- b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
- b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
- b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
- b'`',
-
- b'A', b'B', b'C', b'D', b'E', b'F', b'G',
- b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
- b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
- b'X', b'Y', b'Z',
-
- b'{', b'|', b'}', b'~', 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
- 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
- 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
-];
-
-enum AsciiCharacterClass {
- C, // control
- Cw, // control whitespace
- W, // whitespace
- D, // digit
- L, // lowercase
- Lx, // lowercase hex digit
- U, // uppercase
- Ux, // uppercase hex digit
- P, // punctuation
-}
-use self::AsciiCharacterClass::*;
-
-static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [
-// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
- C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
- C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
- W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
- D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
- P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
- U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
- P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
- L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
-];
-
#[cfg(test)]
mod tests {
- use super::*;
+ //! Note that most of these tests are not testing `AsciiExt` methods, but
+ //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is
+ //! just using those methods, though.
use char::from_u32;
#[test]
#[cfg(not(test))]
#[doc(hidden)]
+#[allow(unused_attributes)]
pub mod __default_lib_allocator {
use super::{System, Layout, Alloc, AllocErr};
use ptr;
// ABI
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom(err: *const u8) -> ! {
System.oom((*(err as *const AllocErr)).clone())
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize,
align: usize) {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize) {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
old_size: usize,
old_align: usize,
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize,
align: usize,
err: *mut u8) -> *mut u8 {
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
}
#[no_mangle]
+ #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+ /// Returns `true` if there are no bytes in the internal buffer.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(bufreader_is_empty)]
+ /// use std::io::BufReader;
+ /// use std::io::BufRead;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let mut reader = BufReader::new(f1);
+ /// assert!(reader.is_empty());
+ ///
+ /// if reader.fill_buf()?.len() > 0 {
+ /// assert!(!reader.is_empty());
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
+ pub fn is_empty(&self) -> bool {
+ self.pos == self.cap
+ }
+
/// Unwraps this `BufReader`, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
#![feature(allow_internal_unstable)]
#![feature(align_offset)]
#![feature(array_error_internals)]
+#![feature(ascii_ctype)]
#![feature(asm)]
#![feature(attr_literals)]
#![feature(box_syntax)]
// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe
// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
impl UnwindSafe for .. {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {}
// only thing which doesn't implement it (which then transitively applies to
// everything else).
#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
impl RefUnwindSafe for .. {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
#![stable(feature = "rust1", since = "1.0.0")]
-use ascii::*;
use borrow::{Borrow, Cow};
use cmp;
use error::Error;
}
}
-#[cfg(target_env = "gnu")]
+#[cfg(all(target_env = "gnu", feature = "backtrace"))]
mod gnu {
use super::*;
}
}
-#[cfg(target_env = "gnu")]
+#[cfg(all(target_env = "gnu", feature = "backtrace"))]
pub use self::gnu::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ascii::*;
-
use path::Prefix;
use ffi::OsStr;
use mem;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ascii::*;
+use ascii::AsciiExt;
use collections::HashMap;
use collections;
use env::split_paths;
pub fn to_uppercase(self) -> ToUppercase {
ToUppercase(CaseMappingIter::new(conversions::to_upper(self)))
}
+
+ /// Checks if the value is within the ASCII range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = 'a';
+ /// let non_ascii = '❤';
+ ///
+ /// assert!(ascii.is_ascii());
+ /// assert!(!non_ascii.is_ascii());
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ *self as u32 <= 0x7F
+ }
+
+ /// Makes a copy of the value in its ASCII upper case equivalent.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To uppercase the value in-place, use [`make_ascii_uppercase`].
+ ///
+ /// To uppercase ASCII characters in addition to non-ASCII characters, use
+ /// [`to_uppercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = 'a';
+ /// let non_ascii = '❤';
+ ///
+ /// assert_eq!('A', ascii.to_ascii_uppercase());
+ /// assert_eq!('❤', non_ascii.to_ascii_uppercase());
+ /// ```
+ ///
+ /// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
+ /// [`to_uppercase`]: #method.to_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_uppercase(&self) -> char {
+ if self.is_ascii() {
+ (*self as u8).to_ascii_uppercase() as char
+ } else {
+ *self
+ }
+ }
+
+ /// Makes a copy of the value in its ASCII lower case equivalent.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To lowercase the value in-place, use [`make_ascii_lowercase`].
+ ///
+ /// To lowercase ASCII characters in addition to non-ASCII characters, use
+ /// [`to_lowercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = 'A';
+ /// let non_ascii = '❤';
+ ///
+ /// assert_eq!('a', ascii.to_ascii_lowercase());
+ /// assert_eq!('❤', non_ascii.to_ascii_lowercase());
+ /// ```
+ ///
+ /// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
+ /// [`to_lowercase`]: #method.to_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn to_ascii_lowercase(&self) -> char {
+ if self.is_ascii() {
+ (*self as u8).to_ascii_lowercase() as char
+ } else {
+ *self
+ }
+ }
+
+ /// Checks that two values are an ASCII case-insensitive match.
+ ///
+ /// Equivalent to `to_ascii_lowercase(a) == to_ascii_lowercase(b)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let upper_a = 'A';
+ /// let lower_a = 'a';
+ /// let lower_z = 'z';
+ ///
+ /// assert!(upper_a.eq_ignore_ascii_case(&lower_a));
+ /// assert!(upper_a.eq_ignore_ascii_case(&upper_a));
+ /// assert!(!upper_a.eq_ignore_ascii_case(&lower_z));
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &char) -> bool {
+ self.to_ascii_lowercase() == other.to_ascii_lowercase()
+ }
+
+ /// Converts this type to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut ascii = 'a';
+ ///
+ /// ascii.make_ascii_uppercase();
+ ///
+ /// assert_eq!('A', ascii);
+ /// ```
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ *self = self.to_ascii_uppercase();
+ }
+
+ /// Converts this type to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut ascii = 'A';
+ ///
+ /// ascii.make_ascii_lowercase();
+ ///
+ /// assert_eq!('a', ascii);
+ /// ```
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.21.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ *self = self.to_ascii_lowercase();
+ }
+
+ /// Checks if the value is an ASCII alphabetic character:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(uppercase_a.is_ascii_alphabetic());
+ /// assert!(uppercase_g.is_ascii_alphabetic());
+ /// assert!(a.is_ascii_alphabetic());
+ /// assert!(g.is_ascii_alphabetic());
+ /// assert!(!zero.is_ascii_alphabetic());
+ /// assert!(!percent.is_ascii_alphabetic());
+ /// assert!(!space.is_ascii_alphabetic());
+ /// assert!(!lf.is_ascii_alphabetic());
+ /// assert!(!esc.is_ascii_alphabetic());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphabetic(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_alphabetic()
+ }
+
+ /// Checks if the value is an ASCII uppercase character:
+ /// U+0041 'A' ... U+005A 'Z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(uppercase_a.is_ascii_uppercase());
+ /// assert!(uppercase_g.is_ascii_uppercase());
+ /// assert!(!a.is_ascii_uppercase());
+ /// assert!(!g.is_ascii_uppercase());
+ /// assert!(!zero.is_ascii_uppercase());
+ /// assert!(!percent.is_ascii_uppercase());
+ /// assert!(!space.is_ascii_uppercase());
+ /// assert!(!lf.is_ascii_uppercase());
+ /// assert!(!esc.is_ascii_uppercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_uppercase(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_uppercase()
+ }
+
+ /// Checks if the value is an ASCII lowercase character:
+ /// U+0061 'a' ... U+007A 'z'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(!uppercase_a.is_ascii_lowercase());
+ /// assert!(!uppercase_g.is_ascii_lowercase());
+ /// assert!(a.is_ascii_lowercase());
+ /// assert!(g.is_ascii_lowercase());
+ /// assert!(!zero.is_ascii_lowercase());
+ /// assert!(!percent.is_ascii_lowercase());
+ /// assert!(!space.is_ascii_lowercase());
+ /// assert!(!lf.is_ascii_lowercase());
+ /// assert!(!esc.is_ascii_lowercase());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_lowercase(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_lowercase()
+ }
+
+ /// Checks if the value is an ASCII alphanumeric character:
+ ///
+ /// - U+0041 'A' ... U+005A 'Z', or
+ /// - U+0061 'a' ... U+007A 'z', or
+ /// - U+0030 '0' ... U+0039 '9'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(uppercase_a.is_ascii_alphanumeric());
+ /// assert!(uppercase_g.is_ascii_alphanumeric());
+ /// assert!(a.is_ascii_alphanumeric());
+ /// assert!(g.is_ascii_alphanumeric());
+ /// assert!(zero.is_ascii_alphanumeric());
+ /// assert!(!percent.is_ascii_alphanumeric());
+ /// assert!(!space.is_ascii_alphanumeric());
+ /// assert!(!lf.is_ascii_alphanumeric());
+ /// assert!(!esc.is_ascii_alphanumeric());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_alphanumeric(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_alphanumeric()
+ }
+
+ /// Checks if the value is an ASCII decimal digit:
+ /// U+0030 '0' ... U+0039 '9'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(!uppercase_a.is_ascii_digit());
+ /// assert!(!uppercase_g.is_ascii_digit());
+ /// assert!(!a.is_ascii_digit());
+ /// assert!(!g.is_ascii_digit());
+ /// assert!(zero.is_ascii_digit());
+ /// assert!(!percent.is_ascii_digit());
+ /// assert!(!space.is_ascii_digit());
+ /// assert!(!lf.is_ascii_digit());
+ /// assert!(!esc.is_ascii_digit());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_digit(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_digit()
+ }
+
+ /// Checks if the value is an ASCII hexadecimal digit:
+ ///
+ /// - U+0030 '0' ... U+0039 '9', or
+ /// - U+0041 'A' ... U+0046 'F', or
+ /// - U+0061 'a' ... U+0066 'f'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(uppercase_a.is_ascii_hexdigit());
+ /// assert!(!uppercase_g.is_ascii_hexdigit());
+ /// assert!(a.is_ascii_hexdigit());
+ /// assert!(!g.is_ascii_hexdigit());
+ /// assert!(zero.is_ascii_hexdigit());
+ /// assert!(!percent.is_ascii_hexdigit());
+ /// assert!(!space.is_ascii_hexdigit());
+ /// assert!(!lf.is_ascii_hexdigit());
+ /// assert!(!esc.is_ascii_hexdigit());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_hexdigit(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_hexdigit()
+ }
+
+ /// Checks if the value is an ASCII punctuation character:
+ ///
+ /// - U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`, or
+ /// - U+003A ... U+0040 `: ; < = > ? @`, or
+ /// - U+005B ... U+0060 `[ \\ ] ^ _ \``, or
+ /// - U+007B ... U+007E `{ | } ~`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(!uppercase_a.is_ascii_punctuation());
+ /// assert!(!uppercase_g.is_ascii_punctuation());
+ /// assert!(!a.is_ascii_punctuation());
+ /// assert!(!g.is_ascii_punctuation());
+ /// assert!(!zero.is_ascii_punctuation());
+ /// assert!(percent.is_ascii_punctuation());
+ /// assert!(!space.is_ascii_punctuation());
+ /// assert!(!lf.is_ascii_punctuation());
+ /// assert!(!esc.is_ascii_punctuation());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_punctuation(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_punctuation()
+ }
+
+ /// Checks if the value is an ASCII graphic character:
+ /// U+0021 '@' ... U+007E '~'.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(uppercase_a.is_ascii_graphic());
+ /// assert!(uppercase_g.is_ascii_graphic());
+ /// assert!(a.is_ascii_graphic());
+ /// assert!(g.is_ascii_graphic());
+ /// assert!(zero.is_ascii_graphic());
+ /// assert!(percent.is_ascii_graphic());
+ /// assert!(!space.is_ascii_graphic());
+ /// assert!(!lf.is_ascii_graphic());
+ /// assert!(!esc.is_ascii_graphic());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_graphic(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_graphic()
+ }
+
+ /// Checks if the value is an ASCII whitespace character:
+ /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+ /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+ ///
+ /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+ /// whitespace][infra-aw]. There are several other definitions in
+ /// wide use. For instance, [the POSIX locale][pct] includes
+ /// U+000B VERTICAL TAB as well as all the above characters,
+ /// but—from the very same specification—[the default rule for
+ /// "field splitting" in the Bourne shell][bfs] considers *only*
+ /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+ ///
+ /// If you are writing a program that will process an existing
+ /// file format, check what that format's definition of whitespace is
+ /// before using this function.
+ ///
+ /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+ /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+ /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(!uppercase_a.is_ascii_whitespace());
+ /// assert!(!uppercase_g.is_ascii_whitespace());
+ /// assert!(!a.is_ascii_whitespace());
+ /// assert!(!g.is_ascii_whitespace());
+ /// assert!(!zero.is_ascii_whitespace());
+ /// assert!(!percent.is_ascii_whitespace());
+ /// assert!(space.is_ascii_whitespace());
+ /// assert!(lf.is_ascii_whitespace());
+ /// assert!(!esc.is_ascii_whitespace());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_whitespace(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_whitespace()
+ }
+
+ /// Checks if the value is an ASCII control character:
+ /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
+ /// Note that most ASCII whitespace characters are control
+ /// characters, but SPACE is not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ascii_ctype)]
+ ///
+ /// let uppercase_a = 'A';
+ /// let uppercase_g = 'G';
+ /// let a = 'a';
+ /// let g = 'g';
+ /// let zero = '0';
+ /// let percent = '%';
+ /// let space = ' ';
+ /// let lf = '\n';
+ /// let esc: char = 0x1b_u8.into();
+ ///
+ /// assert!(!uppercase_a.is_ascii_control());
+ /// assert!(!uppercase_g.is_ascii_control());
+ /// assert!(!a.is_ascii_control());
+ /// assert!(!g.is_ascii_control());
+ /// assert!(!zero.is_ascii_control());
+ /// assert!(!percent.is_ascii_control());
+ /// assert!(!space.is_ascii_control());
+ /// assert!(lf.is_ascii_control());
+ /// assert!(esc.is_ascii_control());
+ /// ```
+ #[unstable(feature = "ascii_ctype", issue = "39658")]
+ #[inline]
+ pub fn is_ascii_control(&self) -> bool {
+ self.is_ascii() && (*self as u8).is_ascii_control()
+ }
}
/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
#![deny(warnings)]
#![no_std]
+#![feature(ascii_ctype)]
#![feature(core_char_ext)]
#![feature(str_internals)]
#![feature(decode_utf8)]
}
}
+/// Is the trait definition an auto trait?
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum IsAuto {
+ Yes,
+ No
+}
+
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
Union(VariantData, Generics),
/// A Trait declaration (`trait` or `pub trait`).
///
- /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
- Trait(Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
+ /// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`
+ Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
/// Auto trait implementation.
///
/// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}`
- DefaultImpl(Unsafety, TraitRef),
+ AutoImpl(Unsafety, TraitRef),
/// An implementation.
///
/// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`
ItemKind::Mac(..) |
ItemKind::MacroDef(..) |
ItemKind::Impl(..) |
- ItemKind::DefaultImpl(..) => "item"
+ ItemKind::AutoImpl(..) => "item"
}
}
}
src_hash: u128,
source_len: usize,
mut file_local_lines: Vec<BytePos>,
- mut file_local_multibyte_chars: Vec<MultiByteChar>)
+ mut file_local_multibyte_chars: Vec<MultiByteChar>,
+ mut file_local_non_narrow_chars: Vec<NonNarrowChar>)
-> Rc<FileMap> {
let start_pos = self.next_start_pos();
let mut files = self.files.borrow_mut();
mbc.pos = mbc.pos + start_pos;
}
+ for swc in &mut file_local_non_narrow_chars {
+ *swc = *swc + start_pos;
+ }
+
let filemap = Rc::new(FileMap {
name: filename,
name_was_remapped,
end_pos,
lines: RefCell::new(file_local_lines),
multibyte_chars: RefCell::new(file_local_multibyte_chars),
+ non_narrow_chars: RefCell::new(file_local_non_narrow_chars),
});
files.push(filemap.clone());
let line = a + 1; // Line numbers start at 1
let linebpos = (*f.lines.borrow())[a];
let linechpos = self.bytepos_to_file_charpos(linebpos);
+ let col = chpos - linechpos;
+
+ let col_display = {
+ let non_narrow_chars = f.non_narrow_chars.borrow();
+ let start_width_idx = non_narrow_chars
+ .binary_search_by_key(&linebpos, |x| x.pos())
+ .unwrap_or_else(|x| x);
+ let end_width_idx = non_narrow_chars
+ .binary_search_by_key(&pos, |x| x.pos())
+ .unwrap_or_else(|x| x);
+ let special_chars = end_width_idx - start_width_idx;
+ let non_narrow: usize =
+ non_narrow_chars[start_width_idx..end_width_idx]
+ .into_iter()
+ .map(|x| x.width())
+ .sum();
+ col.0 - special_chars + non_narrow
+ };
debug!("byte pos {:?} is on the line at byte pos {:?}",
pos, linebpos);
debug!("char pos {:?} is on the line at char pos {:?}",
Loc {
file: f,
line,
- col: chpos - linechpos,
+ col,
+ col_display,
}
}
Err(f) => {
+ let col_display = {
+ let non_narrow_chars = f.non_narrow_chars.borrow();
+ let end_width_idx = non_narrow_chars
+ .binary_search_by_key(&pos, |x| x.pos())
+ .unwrap_or_else(|x| x);
+ let non_narrow: usize =
+ non_narrow_chars[0..end_width_idx]
+ .into_iter()
+ .map(|x| x.width())
+ .sum();
+ chpos.0 - end_width_idx + non_narrow
+ };
Loc {
file: f,
line: 0,
col: chpos,
+ col_display,
}
}
}
macro_rules! span_fatal {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.span_fatal_with_code($span, &format!($($message)*), stringify!($code))
+ $session.span_fatal_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
macro_rules! span_err {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.span_err_with_code($span, &format!($($message)*), stringify!($code))
+ $session.span_err_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
macro_rules! span_warn {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
+ $session.span_warn_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
macro_rules! struct_err {
($session:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.struct_err_with_code(&format!($($message)*), stringify!($code))
+ $session.struct_err_with_code(
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
if $is_warning {
- $session.span_warn_with_code($span, &format!($($message)*), stringify!($code))
+ $session.span_warn_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
} else {
- $session.span_err_with_code($span, &format!($($message)*), stringify!($code))
+ $session.span_err_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
}
})
}
macro_rules! struct_span_fatal {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.struct_span_fatal_with_code($span, &format!($($message)*), stringify!($code))
+ $session.struct_span_fatal_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
macro_rules! struct_span_err {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code))
+ $session.struct_span_err_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
macro_rules! struct_span_warn {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
- $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code))
+ $session.struct_span_warn_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
})
}
($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
if $is_warning {
- $session.struct_span_warn_with_code($span, &format!($($message)*), stringify!($code))
+ $session.struct_span_warn_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
} else {
- $session.struct_span_err_with_code($span, &format!($($message)*), stringify!($code))
+ $session.struct_span_err_with_code(
+ $span,
+ &format!($($message)*),
+ $crate::errors::DiagnosticId::Error(stringify!($code).to_owned()),
+ )
}
})
}
use parse::ParseSess;
use symbol::Symbol;
-use std::ascii::AsciiExt;
use std::env;
macro_rules! set {
// allow '|' at beginning of match arms (RFC 1925)
(active, match_beginning_vert, "1.21.0", Some(44101)),
+ // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
+ (active, non_exhaustive, "1.22.0", Some(44109)),
+
// Copy/Clone closures (RFC 2132)
(active, clone_closures, "1.22.0", Some(44490)),
(active, copy_closures, "1.22.0", Some(44490)),
not yet settled",
cfg_fn!(structural_match))),
+ // RFC #2008
+ ("non_exhaustive", Whitelisted, Gated(Stability::Unstable,
+ "non_exhaustive",
+ "non exhaustive is an experimental feature",
+ cfg_fn!(non_exhaustive))),
+
("plugin", CrateLevel, Gated(Stability::Unstable,
"plugin",
"compiler plugins are experimental \
"allow_fail attribute is currently unstable",
cfg_fn!(allow_fail))),
+ ("rustc_std_internal_symbol", Whitelisted, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "this is an internal attribute that will \
+ never be stable",
+ cfg_fn!(rustc_attrs))),
+
// Crate level attributes
("crate_name", CrateLevel, Ungated),
("crate_type", CrateLevel, Ungated),
}
}
- ast::ItemKind::DefaultImpl(..) => {
+ ast::ItemKind::AutoImpl(..) => {
gate_feature_post!(&self, optin_builtin_traits,
i.span,
- "default trait implementations are experimental \
+ "auto trait implementations are experimental \
and possibly buggy");
}
}
}
+ ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
+ gate_feature_post!(&self, optin_builtin_traits,
+ i.span,
+ "auto traits are experimental and possibly buggy");
+ }
+
ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
let msg = "`macro` is experimental";
gate_feature_post!(&self, decl_macro, i.span, msg);
let generics = folder.fold_generics(generics);
ItemKind::Union(folder.fold_variant_data(struct_def), generics)
}
- ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
- ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
+ ItemKind::AutoImpl(unsafety, ref trait_ref) => {
+ ItemKind::AutoImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
}
ItemKind::Impl(unsafety,
polarity,
folder.fold_ty(ty),
impl_items.move_flat_map(|item| folder.fold_impl_item(item)),
),
- ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait(
+ ItemKind::Trait(is_auto, unsafety, generics, bounds, items) => ItemKind::Trait(
+ is_auto,
unsafety,
folder.fold_generics(generics),
folder.fold_bounds(bounds),
use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
use errors::registry::Registry;
use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::DiagnosticId;
use errors::emitter::Emitter;
use std::rc::Rc;
use std::io::{self, Write};
use std::vec;
-use rustc_serialize::json::as_json;
+use rustc_serialize::json::{as_json, as_pretty_json};
pub struct JsonEmitter {
dst: Box<Write + Send>,
registry: Option<Registry>,
cm: Rc<CodeMapper + 'static>,
+ pretty: bool,
}
impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
- code_map: Rc<CodeMap>) -> JsonEmitter {
+ code_map: Rc<CodeMap>,
+ pretty: bool) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
cm: code_map,
+ pretty,
}
}
- pub fn basic() -> JsonEmitter {
+ pub fn basic(pretty: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
- JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)))
+ JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
}
pub fn new(dst: Box<Write + Send>,
registry: Option<Registry>,
- code_map: Rc<CodeMap>) -> JsonEmitter {
+ code_map: Rc<CodeMap>,
+ pretty: bool) -> JsonEmitter {
JsonEmitter {
dst,
registry,
cm: code_map,
+ pretty,
}
}
}
impl Emitter for JsonEmitter {
fn emit(&mut self, db: &DiagnosticBuilder) {
let data = Diagnostic::from_diagnostic_builder(db, self);
- if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+ let result = if self.pretty {
+ writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+ } else {
+ writeln!(&mut self.dst, "{}", as_json(&data))
+ };
+ if let Err(e) = result {
panic!("failed to print diagnostics: {:?}", e);
}
}
spans: Vec<DiagnosticSpan>,
/// Associated diagnostic messages.
children: Vec<Diagnostic>,
- /// The message as rustc would render it. Currently this is only
- /// `Some` for "suggestions", but eventually it will include all
- /// snippets.
+ /// The message as rustc would render it. Currently this is always `None`
rendered: Option<String>,
}
/// Label that should be placed at this location (if any)
label: Option<String>,
/// If we are suggesting a replacement, this will contain text
- /// that should be sliced in atop this span. You may prefer to
- /// load the fully rendered version from the parent `Diagnostic`,
- /// however.
+ /// that should be sliced in atop this span.
suggested_replacement: Option<String>,
/// Macro invocations that created the code at this span, if any.
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}
impl DiagnosticCode {
- fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
+ fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<DiagnosticCode> {
s.map(|s| {
-
+ let s = match s {
+ DiagnosticId::Error(s) => s,
+ DiagnosticId::Lint(s) => s,
+ };
let explanation = je.registry
.as_ref()
.and_then(|registry| registry.find_description(&s));
self.filemap.record_multibyte_char(self.pos, new_ch_len);
}
}
+ self.filemap.record_width(self.pos, new_ch);
} else {
self.ch = None;
self.pos = new_pos;
use ast::{Expr, ExprKind, RangeLimits};
use ast::{Field, FnDecl};
use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
-use ast::{Ident, ImplItem, Item, ItemKind};
+use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy};
use ast::Local;
use ast::MacStmtStyle;
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
let pat = self.parse_pat()?;
- self.expect_keyword(keywords::In)?;
+ if !self.eat_keyword(keywords::In) {
+ let in_span = self.prev_span.between(self.span);
+ let mut err = self.sess.span_diagnostic
+ .struct_span_err(in_span, "missing `in` in `for` loop");
+ err.span_suggestion_short(in_span, "try adding `in` here", " in ".into());
+ err.emit();
+ }
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
}
+ fn eat_auto_trait(&mut self) -> bool {
+ if self.token.is_keyword(keywords::Auto)
+ && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
+ {
+ self.eat_keyword(keywords::Auto) && self.eat_keyword(keywords::Trait)
+ } else {
+ false
+ }
+ }
+
fn is_defaultness(&self) -> bool {
// `pub` is included for better error messages
self.token.is_keyword(keywords::Default) &&
}
/// Parse trait Foo { ... }
- fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
+ fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let mut tps = self.parse_generics()?;
}
}
}
- Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None))
+ Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
}
/// Parses items implementations variants
if opt_trait.is_some() && self.eat(&token::DotDot) {
if generics.is_parameterized() {
- self.span_err(impl_span, "default trait implementations are not \
+ self.span_err(impl_span, "auto trait implementations are not \
allowed to have generics");
}
if let ast::Defaultness::Default = defaultness {
self.span_err(impl_span, "`default impl` is not allowed for \
- default trait implementations");
+ auto trait implementations");
}
self.expect(&token::OpenDelim(token::Brace))?;
self.expect(&token::CloseDelim(token::Brace))?;
Ok((keywords::Invalid.ident(),
- ItemKind::DefaultImpl(unsafety, opt_trait.unwrap()), None))
+ ItemKind::AutoImpl(unsafety, opt_trait.unwrap()), None))
} else {
if opt_trait.is_some() {
ty = self.parse_ty()?;
return Ok(Some(item));
}
if self.check_keyword(keywords::Unsafe) &&
- self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
+ (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) ||
+ self.look_ahead(1, |t| t.is_keyword(keywords::Auto)))
{
// UNSAFE TRAIT ITEM
self.expect_keyword(keywords::Unsafe)?;
- self.expect_keyword(keywords::Trait)?;
+ let is_auto = if self.eat_keyword(keywords::Trait) {
+ IsAuto::No
+ } else {
+ self.eat_auto_trait();
+ IsAuto::Yes
+ };
let (ident, item_, extra_attrs) =
- self.parse_item_trait(ast::Unsafety::Unsafe)?;
+ self.parse_item_trait(is_auto, ast::Unsafety::Unsafe)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
maybe_append(attrs, extra_attrs));
return Ok(Some(item));
}
- if self.eat_keyword(keywords::Trait) {
+ if self.check_keyword(keywords::Trait)
+ || (self.check_keyword(keywords::Auto)
+ && self.look_ahead(1, |t| t.is_keyword(keywords::Trait)))
+ {
+ let is_auto = if self.eat_keyword(keywords::Trait) {
+ IsAuto::No
+ } else {
+ self.eat_auto_trait();
+ IsAuto::Yes
+ };
// TRAIT ITEM
let (ident, item_, extra_attrs) =
- self.parse_item_trait(ast::Unsafety::Normal)?;
+ self.parse_item_trait(is_auto, ast::Unsafety::Normal)?;
let prev_span = self.prev_span;
let item = self.mk_item(lo.to(prev_span),
ident,
self.head(&visibility_qualified(&item.vis, "union"))?;
self.print_struct(struct_def, generics, item.ident, item.span, true)?;
}
- ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+ ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_unsafety(unsafety)?;
}
self.bclose(item.span)?;
}
- ast::ItemKind::Trait(unsafety, ref generics, ref bounds, ref trait_items) => {
+ ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
self.head("")?;
self.print_visibility(&item.vis)?;
self.print_unsafety(unsafety)?;
+ self.print_is_auto(is_auto)?;
self.word_nbsp("trait")?;
self.print_ident(item.ident)?;
self.print_generics(generics)?;
ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
}
}
+
+ pub fn print_is_auto(&mut self, s: ast::IsAuto) -> io::Result<()> {
+ match s {
+ ast::IsAuto::Yes => self.word_nbsp("auto"),
+ ast::IsAuto::No => Ok(()),
+ }
+ }
}
fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
visitor.visit_generics(type_parameters);
visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
}
- ItemKind::DefaultImpl(_, ref trait_ref) => {
+ ItemKind::AutoImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemKind::Impl(_, _, _,
visitor.visit_variant_data(struct_definition, item.ident,
generics, item.id, item.span);
}
- ItemKind::Trait(_, ref generics, ref bounds, ref methods) => {
+ ItemKind::Trait(.., ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_trait_item, methods);
[dependencies]
serialize = { path = "../libserialize" }
rustc_data_structures = { path = "../librustc_data_structures" }
+unicode-width = "0.1.4"
extern crate serialize;
extern crate serialize as rustc_serialize; // used by deriving
+extern crate unicode_width;
+
pub mod hygiene;
pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind};
pub bytes: usize,
}
+/// Identifies an offset of a non-narrow character in a FileMap
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
+pub enum NonNarrowChar {
+ /// Represents a zero-width character
+ ZeroWidth(BytePos),
+ /// Represents a wide (fullwidth) character
+ Wide(BytePos),
+}
+
+impl NonNarrowChar {
+ fn new(pos: BytePos, width: usize) -> Self {
+ match width {
+ 0 => NonNarrowChar::ZeroWidth(pos),
+ 2 => NonNarrowChar::Wide(pos),
+ _ => panic!("width {} given for non-narrow character", width),
+ }
+ }
+
+ /// Returns the absolute offset of the character in the CodeMap
+ pub fn pos(&self) -> BytePos {
+ match *self {
+ NonNarrowChar::ZeroWidth(p) |
+ NonNarrowChar::Wide(p) => p,
+ }
+ }
+
+ /// Returns the width of the character, 0 (zero-width) or 2 (wide)
+ pub fn width(&self) -> usize {
+ match *self {
+ NonNarrowChar::ZeroWidth(_) => 0,
+ NonNarrowChar::Wide(_) => 2,
+ }
+ }
+}
+
+impl Add<BytePos> for NonNarrowChar {
+ type Output = Self;
+
+ fn add(self, rhs: BytePos) -> Self {
+ match self {
+ NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
+ NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
+ }
+ }
+}
+
+impl Sub<BytePos> for NonNarrowChar {
+ type Output = Self;
+
+ fn sub(self, rhs: BytePos) -> Self {
+ match self {
+ NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
+ NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
+ }
+ }
+}
+
/// The state of the lazy external source loading mechanism of a FileMap.
#[derive(PartialEq, Eq, Clone)]
pub enum ExternalSource {
pub lines: RefCell<Vec<BytePos>>,
/// Locations of multi-byte characters in the source code
pub multibyte_chars: RefCell<Vec<MultiByteChar>>,
+ /// Width of characters that are not narrow in the source code
+ pub non_narrow_chars: RefCell<Vec<NonNarrowChar>>,
}
impl Encodable for FileMap {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct("FileMap", 7, |s| {
+ s.emit_struct("FileMap", 8, |s| {
s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?;
})?;
s.emit_struct_field("multibyte_chars", 5, |s| {
(*self.multibyte_chars.borrow()).encode(s)
+ })?;
+ s.emit_struct_field("non_narrow_chars", 7, |s| {
+ (*self.non_narrow_chars.borrow()).encode(s)
})
})
}
impl Decodable for FileMap {
fn decode<D: Decoder>(d: &mut D) -> Result<FileMap, D::Error> {
- d.read_struct("FileMap", 6, |d| {
+ d.read_struct("FileMap", 8, |d| {
let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
let name_was_remapped: bool =
d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
})?;
let multibyte_chars: Vec<MultiByteChar> =
d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
+ let non_narrow_chars: Vec<NonNarrowChar> =
+ d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
Ok(FileMap {
name,
name_was_remapped,
src_hash,
external_src: RefCell::new(ExternalSource::AbsentOk),
lines: RefCell::new(lines),
- multibyte_chars: RefCell::new(multibyte_chars)
+ multibyte_chars: RefCell::new(multibyte_chars),
+ non_narrow_chars: RefCell::new(non_narrow_chars)
})
})
}
end_pos: Pos::from_usize(end_pos),
lines: RefCell::new(Vec::new()),
multibyte_chars: RefCell::new(Vec::new()),
+ non_narrow_chars: RefCell::new(Vec::new()),
}
}
self.multibyte_chars.borrow_mut().push(mbc);
}
+ pub fn record_width(&self, pos: BytePos, ch: char) {
+ let width = match ch {
+ '\t' | '\n' =>
+ // Tabs will consume one column.
+ // Make newlines take one column so that displayed spans can point them.
+ 1,
+ ch =>
+ // Assume control characters are zero width.
+ // FIXME: How can we decide between `width` and `width_cjk`?
+ unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0),
+ };
+ // Only record non-narrow characters.
+ if width != 1 {
+ self.non_narrow_chars.borrow_mut().push(NonNarrowChar::new(pos, width));
+ }
+ }
+
pub fn is_real_file(&self) -> bool {
!(self.name.starts_with("<") &&
self.name.ends_with(">"))
/// The (1-based) line number
pub line: usize,
/// The (0-based) column offset
- pub col: CharPos
+ pub col: CharPos,
+ /// The (0-based) column offset when displayed
+ pub col_display: usize,
}
/// A source code location used as the result of lookup_char_pos_adj
const CTXT_INDEX: usize = 2;
// Tag = 0, inline format.
-// -----------------------------------
-// | base 31:8 | len 7:1 | tag 0:0 |
-// -----------------------------------
+// -------------------------------------------------------------
+// | base 31:8 | len 7:1 | ctxt (currently 0 bits) | tag 0:0 |
+// -------------------------------------------------------------
+// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext
+// can be inline.
const INLINE_SIZES: [u32; 3] = [24, 7, 0];
const INLINE_OFFSETS: [u32; 3] = [8, 1, 1];
(54, Yield, "yield")
// Weak keywords, have special meaning only in specific contexts.
- (55, Catch, "catch")
- (56, Default, "default")
- (57, Dyn, "dyn")
- (58, StaticLifetime, "'static")
- (59, Union, "union")
+ (55, Auto, "auto")
+ (56, Catch, "catch")
+ (57, Default, "default")
+ (58, Dyn, "dyn")
+ (59, StaticLifetime, "'static")
+ (60, Union, "union")
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
// When an executable or dylib image is linked, all user code and libraries are
// "sandwiched" between these two object files, so code or data from rsbegin.o
// become first in the respective sections of the image, whereas code and data
-// from rsend.o become the last ones. This effect can be used to place symbols
+// from rsend.o become the last ones. This effect can be used to place symbols
// at the beginning or at the end of a section, as well as to insert any required
// headers or footers.
//
trait Sized {}
#[lang = "sync"]
trait Sync {}
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
impl Sync for .. {}
#[lang = "copy"]
trait Copy {}
#[lang = "freeze"]
trait Freeze {}
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
impl Freeze for .. {}
#[lang = "drop_in_place"]
trait Copy {}
#[lang = "freeze"]
trait Freeze {}
+#[allow(unknown_lints)]
+#[allow(auto_impl)]
impl Freeze for .. {}
#[lang = "drop_in_place"]
//~| NOTE ranges require char or numeric types
//~| NOTE start type: &'static str
//~| NOTE end type: &'static str
+ //~| ERROR non-reference pattern used to match a reference
_ => {}
}
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+trait Foo {}
+impl Foo for .. {}
+//~^ ERROR The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}`
+//~^^ WARN this was previously accepted by the compiler
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+auto trait Generic<T> {}
+//~^ ERROR auto traits cannot have generics
+//~^^ traits with auto impls (`e.g. impl Trait for ..`) can not have type parameters
+auto trait Bound : Copy {}
+//~^ ERROR auto traits cannot have super traits
+//~^^ traits with auto impls (`e.g. impl Trait for ..`) cannot have predicates
+auto trait MyTrait { fn foo() {} }
+//~^ ERROR auto traits cannot contain items
+//~^^ traits with default impls (`e.g. impl Trait for ..`) must have no methods or associated items
+fn main() {}
#![crate_type = "rlib"]
pub trait DefaultedTrait { }
+#[allow(auto_impl)]
impl DefaultedTrait for .. { }
pub struct Something<T> { t: T }
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+//compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn foo(_:String) {}
+
+fn main()
+{
+ let my_str = "hello".to_owned();
+ match Some(42) {
+ Some(_) if { drop(my_str); false } => {}
+ Some(_) => {}
+ None => { foo(my_str); } //~ ERROR (Mir) [E0381]
+ }
+}
// revisions: ast mir
//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+enum Foo {
+ A(i32),
+ B
+}
+
+fn match_enum() {
+ let mut foo = Foo::B;
+ let p = &mut foo;
+ let _ = match foo {
+ Foo::B => 1, //[mir]~ ERROR (Mir) [E0503]
+ _ => 2,
+ Foo::A(x) => x //[ast]~ ERROR [E0503]
+ //[mir]~^ ERROR (Ast) [E0503]
+ //[mir]~| ERROR (Mir) [E0503]
+ };
+}
+
+
fn main() {
let mut x = 1;
let _x = &mut x;
--- /dev/null
+See `src/test/run-pass/closure-expected-type`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// must-compile-successfully
+
+#![feature(underscore_lifetimes)]
+#![allow(warnings)]
+
+type Different<'a, 'b> = &'a mut (&'a (), &'b ());
+type Same<'a> = Different<'a, 'a>;
+
+fn with_closure_expecting_different<F>(_: F)
+ where F: for<'a, 'b> FnOnce(Different<'a, 'b>)
+{
+}
+
+fn with_closure_expecting_different_anon<F>(_: F)
+ where F: FnOnce(Different<'_, '_>)
+{
+}
+
+fn supplying_nothing_expecting_anon() {
+ with_closure_expecting_different_anon(|x: Different| {
+ })
+}
+
+fn supplying_nothing_expecting_named() {
+ with_closure_expecting_different(|x: Different| {
+ })
+}
+
+fn supplying_underscore_expecting_anon() {
+ with_closure_expecting_different_anon(|x: Different<'_, '_>| {
+ })
+}
+
+fn supplying_underscore_expecting_named() {
+ with_closure_expecting_different(|x: Different<'_, '_>| {
+ })
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(underscore_lifetimes)]
+
+fn with_closure_expecting_fn_with_free_region<F>(_: F)
+ where F: for<'a> FnOnce(fn(&'a u32), &i32)
+{
+}
+
+fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+ where F: FnOnce(fn(&u32), &i32)
+{
+}
+
+fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+ // Here, the type given for `'x` "obscures" a region from the
+ // expected signature that is bound at closure level.
+ with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+}
+
+fn expect_free_supply_free_from_closure() {
+ // A variant on the previous test. Here, the region `'a` will be
+ // bound at the closure level, just as is expected, so no error
+ // results.
+ type Foo<'a> = fn(&'a u32);
+ with_closure_expecting_fn_with_free_region(|_x: Foo<'_>, y| {});
+}
+
+fn expect_free_supply_bound() {
+ // Here, we are given a function whose region is bound at closure level,
+ // but we expect one bound in the argument. Error results.
+ with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+ //~^ ERROR type mismatch in closure arguments
+}
+
+fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
+ // Here, we are given a `fn(&u32)` but we expect a `fn(&'x
+ // u32)`. In principle, this could be ok, but we demand equality.
+ with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
+ //~^ ERROR type mismatch in closure arguments
+}
+
+fn expect_bound_supply_free_from_closure() {
+ // A variant on the previous test. Here, the region `'a` will be
+ // bound at the closure level, but we expect something bound at
+ // the argument level.
+ type Foo<'a> = fn(&'a u32);
+ with_closure_expecting_fn_with_bound_region(|_x: Foo<'_>, y| {});
+ //~^ ERROR type mismatch in closure arguments
+}
+
+fn expect_bound_supply_bound<'x>(x: &'x u32) {
+ // No error in this case. The supplied type supplies the bound
+ // regions, and hence we are able to figure out the type of `y`
+ // from the expected type
+ with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
+ });
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn with_closure<F, A>(_: F)
+ where F: FnOnce(A, A)
+{
+}
+
+fn a() {
+ with_closure(|x: u32, y| {
+ // We deduce type of `y` from `x`.
+ });
+}
+
+fn b() {
+ // Here we take the supplied types, resulting in an error later on.
+ with_closure(|x: u32, y: i32| {
+ //~^ ERROR type mismatch in closure arguments
+ });
+}
+
+fn c() {
+ with_closure(|x, y: i32| {
+ // We deduce type of `x` from `y`.
+ });
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// must-compile-successfully
+
+fn with_closure<F, A>(_: F)
+ where F: FnOnce(A, &u32)
+{
+}
+
+fn foo() {
+ // This version works; we infer `A` to be `u32`, and take the type
+ // of `y` to be `&u32`.
+ with_closure(|x: u32, y| {});
+}
+
+fn bar() {
+ // This version also works.
+ with_closure(|x: &u32, y| {});
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// must-compile-successfully
+
+fn with_closure<F, A>(_: F)
+ where F: FnOnce(A, &u32)
+{
+}
+
+fn foo() {
+ // This version works; we infer `A` to be `u32`, and take the type
+ // of `y` to be `&u32`.
+ with_closure(|x: u32, y| {});
+}
+
+fn bar<'x>(x: &'x u32) {
+ // Same.
+ with_closure(|x: &'x u32, y| {});
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(warnings)]
+
+fn closure_expecting_bound<F>(_: F)
+ where F: FnOnce(&u32)
+{
+}
+
+fn closure_expecting_free<'a, F>(_: F)
+ where F: FnOnce(&'a u32)
+{
+}
+
+fn expect_bound_supply_nothing() {
+ // Because `x` is inferred to have a bound region, we cannot allow
+ // it to escape into `f`:
+ let mut f: Option<&u32> = None;
+ closure_expecting_bound(|x| {
+ f = Some(x); //~ ERROR E0495
+ });
+}
+
+fn expect_bound_supply_bound() {
+ // Because `x` is inferred to have a bound region, we cannot allow
+ // it to escape into `f`, even with an explicit type annotation on
+ // closure:
+ let mut f: Option<&u32> = None;
+ closure_expecting_bound(|x: &u32| {
+ f = Some(x); //~ ERROR E0495
+ });
+}
+
+fn expect_bound_supply_named<'x>() {
+ let mut f: Option<&u32> = None;
+
+ // Here we give a type annotation that `x` should be free. We get
+ // an error because of that.
+ closure_expecting_bound(|x: &'x u32| {
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // And we still cannot let `x` escape into `f`.
+ f = Some(x);
+ //~^ ERROR cannot infer
+ });
+}
+
+fn expect_free_supply_nothing() {
+ let mut f: Option<&u32> = None;
+ closure_expecting_free(|x| f = Some(x)); // OK
+}
+
+fn expect_free_supply_bound() {
+ let mut f: Option<&u32> = None;
+
+ // Here, even though the annotation `&u32` could be seen as being
+ // bound in the closure, we permit it to be defined as a free
+ // region (which is inferred to something in the fn body).
+ closure_expecting_free(|x: &u32| f = Some(x)); // OK
+}
+
+fn expect_free_supply_named<'x>() {
+ let mut f: Option<&u32> = None;
+
+ // Here, even though the annotation `&u32` could be seen as being
+ // bound in the closure, we permit it to be defined as a free
+ // region (which is inferred to something in the fn body).
+ closure_expecting_free(|x: &'x u32| f = Some(x)); // OK
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn with_closure<F, A, B>(_: F)
+ where F: FnOnce(A, B)
+{
+}
+
+fn a() {
+ // Type of `y` is unconstrained.
+ with_closure(|x: u32, y| {}); //~ ERROR E0282
+}
+
+fn b() {
+ with_closure(|x: u32, y: u32| {}); // OK
+}
+
+fn c() {
+ with_closure(|x: u32, y: u32| {}); // OK
+}
+
+fn main() { }
trait MyTrait { fn foo() {} }
+#[allow(auto_impl)]
impl MyTrait for .. {}
-//~^ ERROR redundant default implementations of trait `MyTrait`
+//~^ ERROR redundant auto implementations of trait `MyTrait`
+#[allow(auto_impl)]
impl MyTrait for .. {}
trait MySafeTrait {}
+#[allow(auto_impl)]
unsafe impl MySafeTrait for .. {}
//~^ ERROR implementing the trait `MySafeTrait` is not unsafe
unsafe trait MyUnsafeTrait {}
+#[allow(auto_impl)]
impl MyUnsafeTrait for .. {}
//~^ ERROR the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
pub fn main() {
match &Some(3) {
- Some(n) => {}, //~ ERROR mismatched types [E0308]
+ Some(n) => {},
+ //~^ ERROR non-reference pattern used to match a reference
_ => panic!(),
}
}
--- /dev/null
+// Copyright 2015 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//#![feature(non_exhaustive)]
+
+#[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109)
+pub enum NonExhaustiveEnum {
+ Unit,
+ Tuple(u32),
+ Struct { field: u32 }
+}
+
+fn main() { }
fn dummy(&self) {}
}
+auto trait AutoDummyTrait {}
+//~^ ERROR auto traits are experimental and possibly buggy
+
+#[allow(auto_impl)]
impl DummyTrait for .. {}
-//~^ ERROR default trait implementations are experimental and possibly buggy
+//~^ ERROR auto trait implementations are experimental and possibly buggy
impl !DummyTrait for DummyStruct {}
//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
fn main() {
let Slice { data: data, len: len } = "foo";
//~^ ERROR mismatched types
- //~| expected type `&str`
//~| found type `Slice<_>`
- //~| expected &str, found struct `Slice`
+ //~| ERROR non-reference pattern used to match a reference
}
fn main() {
// NB: this (almost) typechecks when default binding modes are enabled.
- for (ref i,) in [].iter() { //~ ERROR mismatched types [E0308]
+ for (ref i,) in [].iter() {
+ //~^ ERROR non-reference pattern used to match a reference
i.clone();
}
}
type Output;
}
+#[allow(auto_impl)]
unsafe impl Trait for .. {}
fn call_method<T: Trait>(x: T) {}
}
}
+#[allow(auto_impl)]
unsafe impl Trait for .. {}
fn call_method<T: Trait>(x: T) {
// except according to those terms.
fn main() {
- let false = "foo"; //~ error: mismatched types
+ let false = 22; //~ error: mismatched types
}
// except according to those terms.
fn main() {
- let Self = "foo"; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope
+ let Self = 22; //~ ERROR cannot find unit struct/variant or constant `Self` in this scope
}
// except according to those terms.
fn main() {
- let super = "foo"; //~ ERROR failed to resolve. There are too many initial `super`s
+ let super = 22; //~ ERROR failed to resolve. There are too many initial `super`s
}
// except according to those terms.
fn main() {
- let true = "foo"; //~ error: mismatched types
+ let true = 22; //~ error: mismatched types
}
//~^^ ERROR only char and numeric types are allowed in range
//~| start type: &'static str
//~| end type: &'static str
+ //~| ERROR non-reference pattern used to match a reference
match "wow" {
10 ... "what" => ()
//~^^ ERROR only char and numeric types are allowed in range
//~| start type: {integer}
//~| end type: &'static str
+ //~| ERROR non-reference pattern used to match a reference
match 5 {
'c' ... 100 => { }
// Note that this one works with default binding modes.
match &[0, 1, 2] {
- [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` [E0529]
+ [..] => {} //~ ERROR non-reference pattern used to match a reference
};
match &[0, 1, 2] {
// OLD!
match x {
[a, b..] => {},
- //~^ ERROR expected an array or slice, found `&[u8]`
- //~| HELP the semantics of slice patterns changed recently; see issue #23121
+ //~^ ERROR non-reference pattern used to match a reference
+ //~| HELP add #![feature(match_default_bindings)] to the crate attributes to enable
+ //~| HELP consider using
_ => panic!(),
}
}
unsafe trait Zen {}
+#[allow(auto_impl)]
unsafe impl Zen for .. {}
unsafe impl<'a, T: 'a> Zen for &'a T where T: Sync {}
}
struct Ts(pub u8);
+#[allow(auto_impl)]
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
pub fn f() {} //~ ERROR unnecessary visibility qualifier
}
struct Ts(pub u8);
+ #[allow(auto_impl)]
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
pub fn f() {} //~ ERROR unnecessary visibility qualifier
}
struct Ts(pub u8);
+ #[allow(auto_impl)]
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
pub fn f() {} //~ ERROR unnecessary visibility qualifier
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+ Unit,
+ Tuple(u32),
+ Struct { field: u32 }
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+ pub first_field: u16,
+ pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct(pub u16, pub u16);
+
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct FunctionalRecord {
+ pub first_field: u16,
+ pub second_field: u16,
+ pub third_field: bool
+}
+
+impl Default for FunctionalRecord {
+ fn default() -> FunctionalRecord {
+ FunctionalRecord { first_field: 640, second_field: 480, third_field: false }
+ }
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+pub enum NonExhaustiveVariants {
+ #[non_exhaustive] Unit,
+ #[non_exhaustive] Tuple(u32),
+ #[non_exhaustive] Struct { field: u32 }
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:enums.rs
+extern crate enums;
+
+use enums::NonExhaustiveEnum;
+
+fn main() {
+ let enum_unit = NonExhaustiveEnum::Unit;
+
+ match enum_unit {
+ //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+ NonExhaustiveEnum::Unit => "first",
+ NonExhaustiveEnum::Tuple(_) => "second",
+ NonExhaustiveEnum::Struct { .. } => "third"
+ };
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:structs.rs
+extern crate structs;
+
+use structs::{NormalStruct, UnitStruct, TupleStruct, FunctionalRecord};
+
+fn main() {
+ let fr = FunctionalRecord {
+ //~^ ERROR cannot create non-exhaustive struct
+ first_field: 1920,
+ second_field: 1080,
+ ..FunctionalRecord::default()
+ };
+
+ let ns = NormalStruct { first_field: 640, second_field: 480 };
+ //~^ ERROR cannot create non-exhaustive struct
+
+ let NormalStruct { first_field, second_field } = ns;
+ //~^ ERROR `..` required with struct marked as non-exhaustive
+
+ let ts = TupleStruct(640, 480);
+ //~^ ERROR expected function, found struct `TupleStruct` [E0423]
+
+ let ts_explicit = structs::TupleStruct(640, 480);
+ //~^ ERROR tuple struct `TupleStruct` is private [E0603]
+
+ let TupleStruct { 0: first_field, 1: second_field } = ts;
+ //~^ ERROR `..` required with struct marked as non-exhaustive
+
+ let us = UnitStruct;
+ //~^ ERROR expected value, found struct `UnitStruct` [E0423]
+
+ let us_explicit = structs::UnitStruct;
+ //~^ ERROR unit struct `UnitStruct` is private [E0603]
+
+ let UnitStruct { } = us;
+ //~^ ERROR `..` required with struct marked as non-exhaustive
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:variants.rs
+extern crate variants;
+
+use variants::NonExhaustiveVariants;
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+fn main() {
+ let variant_struct = NonExhaustiveVariants::Struct { field: 640 };
+ //~^ ERROR cannot create non-exhaustive variant
+
+ let variant_tuple = NonExhaustiveVariants::Tuple { 0: 640 };
+ //~^ ERROR cannot create non-exhaustive variant
+
+ match variant_struct {
+ NonExhaustiveVariants::Unit => "",
+ NonExhaustiveVariants::Tuple(fe_tpl) => "",
+ //~^ ERROR `..` required with variant marked as non-exhaustive
+ NonExhaustiveVariants::Struct { field } => ""
+ //~^ ERROR `..` required with variant marked as non-exhaustive
+ };
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+
+pub enum NonExhaustiveVariants {
+ #[non_exhaustive] Unit,
+ //~^ ERROR #[non_exhaustive] is not yet supported on variants
+ #[non_exhaustive] Tuple(u32),
+ //~^ ERROR #[non_exhaustive] is not yet supported on variants
+ #[non_exhaustive] Struct { field: u32 }
+ //~^ ERROR #[non_exhaustive] is not yet supported on variants
+}
+
+fn main() { }
trait Foo {}
+#[allow(auto_impl)]
default impl Foo for .. {}
-//~^ ERROR `default impl` is not allowed for default trait implementations
+//~^ ERROR `default impl` is not allowed for auto trait implementations
fn main() {}
trait Foo {}
+#[allow(auto_impl)]
impl Foo for .. {}
impl<T> Foo for T {}
trait Bar {}
+#[allow(auto_impl)]
impl Bar for .. {}
impl<T> !Bar for T {}
#![feature(optin_builtin_traits)]
-trait MyDefaultImpl {}
+trait MyAutoImpl {}
-impl<T> MyDefaultImpl for .. {}
-//~^ ERROR default trait implementations are not allowed to have generics
+#[allow(auto_impl)]
+impl<T> MyAutoImpl for .. {}
+//~^ ERROR auto trait implementations are not allowed to have generics
fn main() {}
#![feature(optin_builtin_traits)]
trait Magic: Copy {} //~ ERROR E0568
+#[allow(auto_impl)]
impl Magic for .. {}
fn copy<T: Magic>(x: T) -> (T, T) { (x, x) }
#![feature(optin_builtin_traits)]
trait Magic : Sized where Option<Self> : Magic {} //~ ERROR E0568
+#[allow(auto_impl)]
impl Magic for .. {}
impl<T:Magic> Magic for T {}
#![feature(optin_builtin_traits)]
trait Magic: Copy {} //~ ERROR E0568
+#[allow(auto_impl)]
impl Magic for .. {}
impl<T:Magic> Magic for T {}
#![feature(optin_builtin_traits)]
trait Magic<T> {} //~ ERROR E0567
+#[allow(auto_impl)]
impl Magic<isize> for .. {}
trait MyTrait {}
+#[allow(auto_impl)]
impl MyTrait for .. {}
struct MyS;
trait MyTrait {}
+#[allow(auto_impl)]
impl MyTrait for .. {}
impl<T> !MyTrait for *mut T {}
trait MyTrait {}
+#[allow(auto_impl)]
impl MyTrait for .. {}
unsafe trait MyUnsafeTrait {}
+#[allow(auto_impl)]
unsafe impl MyUnsafeTrait for .. {}
struct ThisImplsTrait;
#![feature(optin_builtin_traits)]
+#[allow(auto_impl)]
impl Copy for .. {} //~ ERROR E0318
//~^ NOTE `Copy` trait not defined in this crate
fn main() {}
#![feature(optin_builtin_traits)]
trait Defaulted { }
+#[allow(auto_impl)]
impl Defaulted for .. { }
impl<'a,T:Signed> Defaulted for &'a T { }
impl<'a,T:Signed> Defaulted for &'a mut T { }
// Add default implementation to method -------------------------------------------
#[cfg(cfail1)]
-trait TraitAddMethodDefaultImplementation {
+trait TraitAddMethodAutoImplementation {
fn method();
}
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
-trait TraitAddMethodDefaultImplementation {
+trait TraitAddMethodAutoImplementation {
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn guard() -> bool {
+ false
+}
+
+fn guard2(_:i32) -> bool {
+ true
+}
+
+fn full_tested_match() {
+ let _ = match Some(42) {
+ Some(x) if guard() => (1, x),
+ Some(y) => (2, y),
+ None => (3, 3),
+ };
+}
+
+fn full_tested_match2() {
+ let _ = match Some(42) {
+ Some(x) if guard() => (1, x),
+ None => (3, 3),
+ Some(y) => (2, y),
+ };
+}
+
+fn main() {
+ let _ = match Some(1) {
+ Some(_w) if guard() => 1,
+ _x => 2,
+ Some(y) if guard2(y) => 3,
+ _z => 4,
+ };
+}
+
+// END RUST SOURCE
+//
+// START rustc.node17.SimplifyBranches-initial.before.mir
+// bb0: {
+// ...
+// _2 = std::option::Option<i32>::Some(const 42i32,);
+// _5 = discriminant(_2);
+// switchInt(_5) -> [0isize: bb5, otherwise: bb3];
+// }
+// bb1: { // arm1
+// StorageLive(_7);
+// _7 = _3;
+// _1 = (const 1i32, _7);
+// StorageDead(_7);
+// goto -> bb11;
+// }
+// bb2: { // binding3(empty) and arm3
+// _1 = (const 3i32, const 3i32);
+// goto -> bb11;
+// }
+// bb3: {
+// falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
+// }
+// bb4: {
+// falseEdges -> [real: bb10, imaginary: bb5]; //pre_binding2
+// }
+// bb5: {
+// falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
+// }
+// bb6: {
+// unreachable;
+// }
+// bb7: { // binding1 and guard
+// StorageLive(_3);
+// _3 = ((_2 as Some).0: i32);
+// StorageLive(_6);
+// _6 = const guard() -> bb8;
+// }
+// bb8: { // end of guard
+// switchInt(_6) -> [0u8: bb9, otherwise: bb1];
+// }
+// bb9: { // to pre_binding2
+// falseEdges -> [real: bb4, imaginary: bb4];
+// }
+// bb10: { // bindingNoLandingPads.before.mir2 and arm2
+// StorageLive(_4);
+// _4 = ((_2 as Some).0: i32);
+// StorageLive(_8);
+// _8 = _4;
+// _1 = (const 2i32, _8);
+// StorageDead(_8);
+// goto -> bb11;
+// }
+// bb11: {
+// ...
+// return;
+// }
+// END rustc.node17.SimplifyBranches-initial.before.mir
+//
+// START rustc.node42.SimplifyBranches-initial.before.mir
+// bb0: {
+// ...
+// _2 = std::option::Option<i32>::Some(const 42i32,);
+// _5 = discriminant(_2);
+// switchInt(_5) -> [0isize: bb4, otherwise: bb3];
+// }
+// bb1: { // arm1
+// StorageLive(_7);
+// _7 = _3;
+// _1 = (const 1i32, _7);
+// StorageDead(_7);
+// goto -> bb11;
+// }
+// bb2: { // binding3(empty) and arm3
+// _1 = (const 3i32, const 3i32);
+// goto -> bb11;
+// }
+// bb3: {
+// falseEdges -> [real: bb7, imaginary: bb4]; //pre_binding1
+// }
+// bb4: {
+// falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
+// }
+// bb5: {
+// falseEdges -> [real: bb10, imaginary: bb6]; //pre_binding3
+// }
+// bb6: {
+// unreachable;
+// }
+// bb7: { // binding1 and guard
+// StorageLive(_3);
+// _3 = ((_2 as Some).0: i32);
+// StorageLive(_6);
+// _6 = const guard() -> bb8;
+// }
+// bb8: { // end of guard
+// switchInt(_6) -> [0u8: bb9, otherwise: bb1];
+// }
+// bb9: { // to pre_binding2
+// falseEdges -> [real: bb5, imaginary: bb4];
+// }
+// bb10: { // binding2 and arm2
+// StorageLive(_4);
+// _4 = ((_2 as Some).0: i32);
+// StorageLive(_8);
+// _8 = _4;
+// _1 = (const 2i32, _8);
+// StorageDead(_8);
+// goto -> bb11;
+// }
+// bb11: {
+// ...
+// return;
+// }
+// END rustc.node42.SimplifyBranches-initial.before.mir
+//
+// START rustc.node67.SimplifyBranches-initial.before.mir
+// bb0: {
+// ...
+// _2 = std::option::Option<i32>::Some(const 1i32,);
+// _7 = discriminant(_2);
+// switchInt(_7) -> [1isize: bb3, otherwise: bb4];
+// }
+// bb1: { // arm1
+// _1 = const 1i32;
+// goto -> bb16;
+// }
+// bb2: { // arm3
+// _1 = const 3i32;
+// goto -> bb16;
+// }
+//
+// bb3: {
+// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
+// }
+// bb4: {
+// falseEdges -> [real: bb11, imaginary: bb5]; //pre_binding2
+// }
+// bb5: {
+// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
+// }
+// bb6: {
+// falseEdges -> [real: bb15, imaginary: bb7]; //pre_binding4
+// }
+// bb7: {
+// unreachable;
+// }
+// bb8: { // binding1: Some(w) if guard()
+// StorageLive(_3);
+// _3 = ((_2 as Some).0: i32);
+// StorageLive(_8);
+// _8 = const guard() -> bb9;
+// }
+// bb9: { //end of guard
+// switchInt(_8) -> [0u8: bb10, otherwise: bb1];
+// }
+// bb10: { // to pre_binding2
+// falseEdges -> [real: bb4, imaginary: bb4];
+// }
+// bb11: { // binding2 & arm2
+// StorageLive(_4);
+// _4 = _2;
+// _1 = const 2i32;
+// goto -> bb16;
+// }
+// bb12: { // binding3: Some(y) if guard2(y)
+// StorageLive(_5);
+// _5 = ((_2 as Some).0: i32);
+// StorageLive(_10);
+// StorageLive(_11);
+// _11 = _5;
+// _10 = const guard2(_11) -> bb13;
+// }
+// bb13: { // end of guard2
+// StorageDead(_11);
+// switchInt(_10) -> [0u8: bb14, otherwise: bb2];
+// }
+// bb14: { // to pre_binding4
+// falseEdges -> [real: bb6, imaginary: bb6];
+// }
+// bb15: { // binding4 & arm4
+// StorageLive(_6);
+// _6 = _2;
+// _1 = const 4i32;
+// goto -> bb16;
+// }
+// bb16: {
+// ...
+// return;
+// }
+// END rustc.node67.SimplifyBranches-initial.before.mir
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]);
// StorageLive(_3);
// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))), [(*_2): i32]);
// _3 = &ReErased (*_2);
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]);
// StorageLive(_3);
// ...
// _0 = const write_42(_3) -> bb1;
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[317d]::main[0]::{{closure}}[0] }, BrAnon(0)) mut i32]);
// StorageLive(_3);
// StorageLive(_4);
// Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]);
--- /dev/null
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+// pp-exact
+
+auto trait MyTrait { }
+
+unsafe auto trait UnsafeMyTrait { }
+
+pub fn main() { }
+++ /dev/null
-// Copyright 2014 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(optin_builtin_traits)]
-
-// pp-exact
-
-trait MyTrait { }
-
-impl MyTrait for .. { }
-
-pub fn main() { }
--- /dev/null
+# Test that allocator-related symbols don't show up as exported from a cdylib as
+# they're internal to Rust and not part of the public ABI.
+
+-include ../tools.mk
+
+ifdef IS_MSVC
+all:
+ true
+else
+all:
+ $(RUSTC) foo.rs
+ nm -g "$(call DYLIB,foo)"
+ nm -g "$(call DYLIB,foo)" | grep -vq __rdl_
+ nm -g "$(call DYLIB,foo)" | grep -vq __rde_
+ nm -g "$(call DYLIB,foo)" | grep -vq __rg_
+ nm -g "$(call DYLIB,foo)" | grep -vq __rust_
+endif
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "cdylib"]
+
+#[no_mangle]
+pub extern fn foo() -> u32 {
+ 3
+}
all:
$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
- rm $(TMPDIR)/foobar.foo0.rust-cgu.o
+ rm $(TMPDIR)/foobar.foo0.rcgu.o
rm $(TMPDIR)/$(call BIN,foobar)
print!("x is {}, y is {1}, name is {n}", x, y, n = name);
}
+
+union TestUnion {
+ f1: u32
+}
+
struct FrameBuffer;
struct SilenceGenerator;
#[lang = "freeze"]
trait Freeze {}
+#[allow(auto_impl)]
impl Freeze for .. {}
#[lang = "freeze"]
trait Freeze {}
+#[allow(auto_impl)]
impl Freeze for .. {}
#[lang="start"]
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! auto {
+ () => (struct S;)
+}
+
+auto!();
+
+fn auto() {}
+
+fn main() {
+ auto();
+ let auto = 10;
+ auto;
+ auto as u8;
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(optin_builtin_traits)]
+
+auto trait Auto {}
+// Redundant but accepted until we remove it.
+#[allow(auto_impl)]
+impl Auto for .. {}
+
+unsafe auto trait AutoUnsafe {}
+
+impl !Auto for bool {}
+impl !AutoUnsafe for bool {}
+
+struct AutoBool(bool);
+
+impl Auto for AutoBool {}
+unsafe impl AutoUnsafe for AutoBool {}
+
+fn take_auto<T: Auto>(_: T) {}
+fn take_auto_unsafe<T: AutoUnsafe>(_: T) {}
+
+fn main() {
+ take_auto(0);
+ take_auto(AutoBool(true));
+ take_auto_unsafe(0);
+ take_auto_unsafe(AutoBool(true));
+}
--- /dev/null
+Some tests targeted at how we deduce the types of closure arguments.
+This process is a result of some heuristics aimed at combining the
+*expected type* we have with the *actual types* that we get from
+inputs. This investigation was kicked off by #38714, which revealed
+some pretty deep flaws in the ad-hoc way that we were doing things
+before.
+
+See also `src/test/compile-fail/closure-expected-type`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn with_closure<A, F>(_: F)
+ where F: FnOnce(Vec<A>, A)
+{
+}
+
+fn expect_free_supply_free<'x>(x: &'x u32) {
+ with_closure(|mut x: Vec<_>, y| {
+ // Shows that the call to `x.push()` is influencing type of `y`...
+ x.push(22_u32);
+
+ // ...since we now know the type of `y` and can resolve the method call.
+ y.wrapping_add(1);
+ });
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct UsizeRef<'a> {
+ a: &'a usize
+}
+
+type RefTo = Box<for<'r> Fn(&'r Vec<usize>) -> UsizeRef<'r>>;
+
+fn ref_to<'a>(vec: &'a Vec<usize>) -> UsizeRef<'a> {
+ UsizeRef{ a: &vec[0]}
+}
+
+fn main() {
+ // Regression test: this was causing ICEs; it should compile.
+ let a: RefTo = Box::new(|vec: &Vec<usize>| {
+ UsizeRef{ a: &vec[0] }
+ });
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn with_closure<F, R>(f: F) -> Result<char, R>
+ where F: FnOnce(&char) -> Result<char, R>,
+{
+ f(&'a')
+}
+
+fn main() {
+ // Test that supplying the `-> Result<char, ()>` manually here
+ // (which is needed to constrain `R`) still allows us to figure
+ // out that the type of `x` is `&'a char` where `'a` is bound in
+ // the closure (if we didn't, we'd get a type-error because
+ // `with_closure` requires a bound region).
+ //
+ // This pattern was found in the wild.
+ let z = with_closure(|x| -> Result<char, ()> { Ok(*x) });
+ assert_eq!(z.unwrap(), 'a');
+
+ // It also works with `_`:
+ let z = with_closure(|x: _| -> Result<char, ()> { Ok(*x) });
+ assert_eq!(z.unwrap(), 'a');
+
+ // It also works with `&_`:
+ let z = with_closure(|x: &_| -> Result<char, ()> { Ok(*x) });
+ assert_eq!(z.unwrap(), 'a');
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn with_closure<F>(f: F) -> u32
+ where F: FnOnce(&u32, &u32) -> u32
+{
+ f(&22, &44)
+}
+
+fn main() {
+ let z = with_closure(|x, y| x + y).wrapping_add(1);
+ assert_eq!(z, 22 + 44 + 1);
+}
#![feature(optin_builtin_traits)]
trait NotSame {}
+#[allow(auto_impl)]
impl NotSame for .. {}
impl<A> !NotSame for (A, A) {}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Zmir-opt-level=2
+
+trait Array {
+ type Item;
+}
+
+fn foo<A: Array>() {
+ let _: *mut A::Item = std::ptr::null_mut();
+}
+
+struct Foo;
+impl Array for Foo { type Item = i32; }
+
+fn main() {
+ foo::<Foo>();
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C debug_assertions=yes
+
+#![feature(i128_type)]
+
+use std::panic;
+
+fn main() {
+ macro_rules! overflow_test {
+ ($t:ident) => (
+ let r = panic::catch_unwind(|| {
+ ($t::max_value()).next_power_of_two()
+ });
+ assert!(r.is_err());
+
+ let r = panic::catch_unwind(|| {
+ (($t::max_value() >> 1) + 2).next_power_of_two()
+ });
+ assert!(r.is_err());
+ )
+ }
+ overflow_test!(u8);
+ overflow_test!(u16);
+ overflow_test!(u32);
+ overflow_test!(u64);
+ overflow_test!(u128);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C debug_assertions=no
+
+#![feature(i128_type)]
+
+fn main() {
+ for i in 129..256 {
+ assert_eq!((i as u8).next_power_of_two(), 0);
+ }
+
+ assert_eq!(((1u16 << 15) + 1).next_power_of_two(), 0);
+ assert_eq!(((1u32 << 31) + 1).next_power_of_two(), 0);
+ assert_eq!(((1u64 << 63) + 1).next_power_of_two(), 0);
+ assert_eq!(((1u128 << 127) + 1).next_power_of_two(), 0);
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+ Unit,
+ Tuple(u32),
+ Struct { field: u32 }
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+ pub first_field: u16,
+ pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct (pub u16, pub u16);
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+#![feature(non_exhaustive)]
+
+pub enum NonExhaustiveVariants {
+ #[non_exhaustive] Unit,
+ #[non_exhaustive] Tuple(u32),
+ #[non_exhaustive] Struct { field: u32 }
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:enums.rs
+extern crate enums;
+
+// ignore-pretty issue #37199
+
+use enums::NonExhaustiveEnum;
+
+fn main() {
+ let enum_unit = NonExhaustiveEnum::Unit;
+
+ match enum_unit {
+ NonExhaustiveEnum::Unit => 1,
+ NonExhaustiveEnum::Tuple(_) => 2,
+ // This particular arm tests that a enum marked as non-exhaustive
+ // will not error if its variants are matched exhaustively.
+ NonExhaustiveEnum::Struct { field } => field,
+ _ => 0 // no error with wildcard
+ };
+
+ match enum_unit {
+ _ => "no error with only wildcard"
+ };
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+ Unit,
+ Tuple(u32),
+ Struct { field: u32 }
+}
+
+fn main() {
+ let enum_unit = NonExhaustiveEnum::Unit;
+
+ match enum_unit {
+ NonExhaustiveEnum::Unit => "first",
+ NonExhaustiveEnum::Tuple(_) => "second",
+ NonExhaustiveEnum::Struct { .. } => "third",
+ };
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:structs.rs
+extern crate structs;
+
+use structs::{NormalStruct, UnitStruct, TupleStruct};
+
+// We only test matching here as we cannot create non-exhaustive
+// structs from another crate. ie. they'll never pass in run-pass tests.
+
+fn match_structs(ns: NormalStruct, ts: TupleStruct, us: UnitStruct) {
+ let NormalStruct { first_field, second_field, .. } = ns;
+
+ let TupleStruct { 0: first, 1: second, .. } = ts;
+
+ let UnitStruct { .. } = us;
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub struct NormalStruct {
+ pub first_field: u16,
+ pub second_field: u16,
+}
+
+#[non_exhaustive]
+pub struct UnitStruct;
+
+#[non_exhaustive]
+pub struct TupleStruct (pub u16, pub u16);
+
+fn main() {
+ let ns = NormalStruct { first_field: 640, second_field: 480 };
+
+ let NormalStruct { first_field, second_field } = ns;
+
+ let ts = TupleStruct { 0: 340, 1: 480 };
+ let ts_constructor = TupleStruct(340, 480);
+
+ let TupleStruct { 0: first, 1: second } = ts;
+ let TupleStruct(first, second) = ts_constructor;
+
+ let us = UnitStruct {};
+ let us_constructor = UnitStruct;
+
+ let UnitStruct { } = us;
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:variants.rs
+extern crate variants;
+
+use variants::NonExhaustiveVariants;
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+fn main() {
+ let variant_tuple = NonExhaustiveVariants::Tuple { 0: 340 };
+ let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
+
+ match variant_struct {
+ NonExhaustiveVariants::Unit => "",
+ NonExhaustiveVariants::Struct { field, .. } => "",
+ NonExhaustiveVariants::Tuple(fe_tpl, ..) => ""
+ };
+}
--- /dev/null
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_exhaustive)]
+
+/*
+ * The initial implementation of #[non_exhaustive] (RFC 2008) does not include support for
+ * variants. See issue #44109 and PR 45394.
+ */
+// ignore-test
+
+pub enum NonExhaustiveVariants {
+ #[non_exhaustive] Unit,
+ #[non_exhaustive] Tuple(u32),
+ #[non_exhaustive] Struct { field: u32 }
+}
+
+fn main() {
+ let variant_tuple = NonExhaustiveVariants::Tuple(340);
+ let variant_struct = NonExhaustiveVariants::Struct { field: 340 };
+
+ match variant_tuple {
+ NonExhaustiveVariants::Unit => "",
+ NonExhaustiveVariants::Tuple(fe_tpl) => "",
+ NonExhaustiveVariants::Struct { field } => ""
+ };
+}
pub trait Bar {}
+ #[allow(auto_impl)]
impl Bar for .. {}
pub trait Foo {
pub trait AnOibit {}
+#[allow(auto_impl)]
impl AnOibit for .. {}
pub trait AnOibit {}
+#[allow(auto_impl)]
impl AnOibit for .. {}
pub struct Foo<T> { field: T }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="sidebar-links"]/a' 'super_long_name'
+// @has - '//*[@class="sidebar-links"]/a' 'Disp'
+pub struct Foo(usize);
+
+impl Foo {
+ pub fn super_long_name() {}
+}
+
+pub trait Disp {
+ fn disp_trait_method();
+}
+
+impl Disp for Foo {
+ fn disp_trait_method() {}
+}
--> $DIR/unicode.rs:11:8
|
11 | extern "路濫狼á́́" fn foo() {}
- | ^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(non_ascii_idents)]
+
+fn main() {
+ let _ = ("a̐éö̲", 0u7);
+ let _ = ("아あ", 1i42);
+ let _ = a̐é;
+}
--- /dev/null
+error: invalid width `7` for integer literal
+ --> $DIR/unicode_2.rs:14:25
+ |
+14 | let _ = ("a̐éö̲", 0u7);
+ | ^^^
+ |
+ = help: valid widths are 8, 16, 32, 64 and 128
+
+error: invalid width `42` for integer literal
+ --> $DIR/unicode_2.rs:15:20
+ |
+15 | let _ = ("아あ", 1i42);
+ | ^^^^
+ |
+ = help: valid widths are 8, 16, 32, 64 and 128
+
+error[E0425]: cannot find value `a̐é` in this scope
+ --> $DIR/unicode_2.rs:16:13
+ |
+16 | let _ = a̐é;
+ | ^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let s = "ZͨA͑ͦ͒͋ͤ͑̚L̄͑͋Ĝͨͥ̿͒̽̈́Oͥ͛ͭ!̏"; while true { break; }
+ println!("{}", s);
+}
--- /dev/null
+warning: denote infinite loops with `loop { ... }`
+ --> $DIR/unicode_3.rs:12:45
+ |
+12 | let s = "ZͨA͑ͦ͒͋ͤ͑̚L̄͑͋Ĝͨͥ̿͒̽̈́Oͥ͛ͭ!̏"; while true { break; }
+ | ----------^^^^^^^^^^^
+ | |
+ | help: use `loop`
+ |
+ = note: #[warn(while_true)] on by default
+
- .escape_debug()
- .escape_default()
- .escape_unicode()
- - .to_lowercase()
- - .to_uppercase()
+ - .to_ascii_lowercase()
+ - .to_ascii_uppercase()
error[E0308]: mismatched types
--> $DIR/deref-suggestion.rs:23:10
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo(u32);
+
+fn test() -> Foo { Foo }
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-35241.rs:13:20
+ |
+13 | fn test() -> Foo { Foo }
+ | --- ^^^
+ | | |
+ | | expected struct `Foo`, found fn item
+ | | did you mean `Foo(/* fields */)`?
+ | expected `Foo` because of return type
+ |
+ = note: expected type `Foo`
+ found type `fn(u32) -> Foo {Foo::{{constructor}}}`
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ for i 0..2 {
+ }
+}
+
--- /dev/null
+error: missing `in` in `for` loop
+ --> $DIR/issue-40782.rs:12:10
+ |
+12 | for i 0..2 {
+ | ^ help: try adding `in` here
+
+error: aborting due to previous error
+
--> $DIR/issue-44078.rs:12:8
|
12 | "😊"";
- | ________^
+ | _________^
13 | | }
| |__^
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is just like unreachable_pub.rs, but without the
+// `crate_visibility_modifier` feature (so that we can test the suggestions to
+// use `pub(crate)` that are given when that feature is off, as opposed to the
+// suggestions to use `crate` given when it is on). When that feature becomes
+// stable, this test can be deleted.
+
+#![feature(macro_vis_matcher)]
+
+#![allow(unused)]
+#![warn(unreachable_pub)]
+
+mod private_mod {
+ // non-leaked `pub` items in private module should be linted
+ pub use std::fmt;
+
+ pub struct Hydrogen {
+ // `pub` struct fields, too
+ pub neutrons: usize,
+ // (... but not more-restricted fields)
+ pub(crate) electrons: usize
+ }
+ impl Hydrogen {
+ // impls, too
+ pub fn count_neutrons(&self) -> usize { self.neutrons }
+ pub(crate) fn count_electrons(&self) -> usize { self.electrons }
+ }
+
+ pub enum Helium {}
+ pub union Lithium { c1: usize, c2: u8 }
+ pub fn beryllium() {}
+ pub trait Boron {}
+ pub const CARBON: usize = 1;
+ pub static NITROGEN: usize = 2;
+ pub type Oxygen = bool;
+
+ macro_rules! define_empty_struct_with_visibility {
+ ($visibility: vis, $name: ident) => { $visibility struct $name {} }
+ }
+ define_empty_struct_with_visibility!(pub, Fluorine);
+
+ extern {
+ pub fn catalyze() -> bool;
+ }
+
+ // items leaked through signatures (see `get_neon` below) are OK
+ pub struct Neon {}
+
+ // crate-visible items are OK
+ pub(crate) struct Sodium {}
+}
+
+pub mod public_mod {
+ // module is public: these are OK, too
+ pub struct Magnesium {}
+ pub(crate) struct Aluminum {}
+}
+
+pub fn get_neon() -> private_mod::Neon {
+ private_mod::Neon {}
+}
+
+fn main() {
+ let _ = get_neon();
+}
--- /dev/null
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:24:5
+ |
+24 | pub use std::fmt;
+ | ---^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+note: lint level defined here
+ --> $DIR/unreachable_pub-pub_crate.rs:20:9
+ |
+20 | #![warn(unreachable_pub)]
+ | ^^^^^^^^^^^^^^^
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:26:5
+ |
+26 | pub struct Hydrogen {
+ | ---^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` field
+ --> $DIR/unreachable_pub-pub_crate.rs:28:9
+ |
+28 | pub neutrons: usize,
+ | ---^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:34:9
+ |
+34 | pub fn count_neutrons(&self) -> usize { self.neutrons }
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:38:5
+ |
+38 | pub enum Helium {}
+ | ---^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:39:5
+ |
+39 | pub union Lithium { c1: usize, c2: u8 }
+ | ---^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:40:5
+ |
+40 | pub fn beryllium() {}
+ | ---^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:41:5
+ |
+41 | pub trait Boron {}
+ | ---^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:42:5
+ |
+42 | pub const CARBON: usize = 1;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:43:5
+ |
+43 | pub static NITROGEN: usize = 2;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:44:5
+ |
+44 | pub type Oxygen = bool;
+ | ---^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:47:47
+ |
+47 | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
+ | -----------^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+48 | }
+49 | define_empty_struct_with_visibility!(pub, Fluorine);
+ | ---------------------------------------------------- in this macro invocation
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:52:9
+ |
+52 | pub fn catalyze() -> bool;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(crate_visibility_modifier)]
+#![feature(macro_vis_matcher)]
+
+#![allow(unused)]
+#![warn(unreachable_pub)]
+
+mod private_mod {
+ // non-leaked `pub` items in private module should be linted
+ pub use std::fmt;
+
+ pub struct Hydrogen {
+ // `pub` struct fields, too
+ pub neutrons: usize,
+ // (... but not more-restricted fields)
+ crate electrons: usize
+ }
+ impl Hydrogen {
+ // impls, too
+ pub fn count_neutrons(&self) -> usize { self.neutrons }
+ crate fn count_electrons(&self) -> usize { self.electrons }
+ }
+
+ pub enum Helium {}
+ pub union Lithium { c1: usize, c2: u8 }
+ pub fn beryllium() {}
+ pub trait Boron {}
+ pub const CARBON: usize = 1;
+ pub static NITROGEN: usize = 2;
+ pub type Oxygen = bool;
+
+ macro_rules! define_empty_struct_with_visibility {
+ ($visibility: vis, $name: ident) => { $visibility struct $name {} }
+ }
+ define_empty_struct_with_visibility!(pub, Fluorine);
+
+ extern {
+ pub fn catalyze() -> bool;
+ }
+
+ // items leaked through signatures (see `get_neon` below) are OK
+ pub struct Neon {}
+
+ // crate-visible items are OK
+ crate struct Sodium {}
+}
+
+pub mod public_mod {
+ // module is public: these are OK, too
+ pub struct Magnesium {}
+ crate struct Aluminum {}
+}
+
+pub fn get_neon() -> private_mod::Neon {
+ private_mod::Neon {}
+}
+
+fn main() {
+ let _ = get_neon();
+}
--- /dev/null
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:19:5
+ |
+19 | pub use std::fmt;
+ | ---^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+note: lint level defined here
+ --> $DIR/unreachable_pub.rs:15:9
+ |
+15 | #![warn(unreachable_pub)]
+ | ^^^^^^^^^^^^^^^
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:21:5
+ |
+21 | pub struct Hydrogen {
+ | ---^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` field
+ --> $DIR/unreachable_pub.rs:23:9
+ |
+23 | pub neutrons: usize,
+ | ---^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:29:9
+ |
+29 | pub fn count_neutrons(&self) -> usize { self.neutrons }
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:33:5
+ |
+33 | pub enum Helium {}
+ | ---^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:34:5
+ |
+34 | pub union Lithium { c1: usize, c2: u8 }
+ | ---^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:35:5
+ |
+35 | pub fn beryllium() {}
+ | ---^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:36:5
+ |
+36 | pub trait Boron {}
+ | ---^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:37:5
+ |
+37 | pub const CARBON: usize = 1;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:38:5
+ |
+38 | pub static NITROGEN: usize = 2;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:39:5
+ |
+39 | pub type Oxygen = bool;
+ | ---^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:42:47
+ |
+42 | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
+ | -----------^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+43 | }
+44 | define_empty_struct_with_visibility!(pub, Fluorine);
+ | ---------------------------------------------------- in this macro invocation
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:47:9
+ |
+47 | pub fn catalyze() -> bool;
+ | ---^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --error-format json
+// compile-flags: --error-format pretty-json -Zunstable-options
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
-{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1001,"byte_end":1014,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"lint level defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":847,"byte_end":860,"line_start":19,"line_end":19,"column_start":9,"column_end":22,"is_primary":true,"text":[{"text":"#![warn(unused_parens)]","highlight_start":9,"highlight_end":22}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1001,"byte_end":1014,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":null}],"rendered":null}
+{
+ "message": "unnecessary parentheses around assigned value",
+ "code": {
+ "code": "unused_parens",
+ "explanation": null
+ },
+ "level": "warning",
+ "spans": [
+ {
+ "file_name": "$DIR/unused_parens_json_suggestion.rs",
+ "byte_start": 1027,
+ "byte_end": 1040,
+ "line_start": 24,
+ "line_end": 24,
+ "column_start": 14,
+ "column_end": 27,
+ "is_primary": true,
+ "text": [
+ {
+ "text": " let _a = (1 / (2 + 3));",
+ "highlight_start": 14,
+ "highlight_end": 27
+ }
+ ],
+ "label": null,
+ "suggested_replacement": null,
+ "expansion": null
+ }
+ ],
+ "children": [
+ {
+ "message": "lint level defined here",
+ "code": null,
+ "level": "note",
+ "spans": [
+ {
+ "file_name": "$DIR/unused_parens_json_suggestion.rs",
+ "byte_start": 873,
+ "byte_end": 886,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 9,
+ "column_end": 22,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "#![warn(unused_parens)]",
+ "highlight_start": 9,
+ "highlight_end": 22
+ }
+ ],
+ "label": null,
+ "suggested_replacement": null,
+ "expansion": null
+ }
+ ],
+ "children": [],
+ "rendered": null
+ },
+ {
+ "message": "remove these parentheses",
+ "code": null,
+ "level": "help",
+ "spans": [
+ {
+ "file_name": "$DIR/unused_parens_json_suggestion.rs",
+ "byte_start": 1027,
+ "byte_end": 1040,
+ "line_start": 24,
+ "line_end": 24,
+ "column_start": 14,
+ "column_end": 27,
+ "is_primary": true,
+ "text": [
+ {
+ "text": " let _a = (1 / (2 + 3));",
+ "highlight_start": 14,
+ "highlight_end": 27
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "1 / (2 + 3)",
+ "expansion": null
+ }
+ ],
+ "children": [],
+ "rendered": null
+ }
+ ],
+ "rendered": null
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --error-format json
+// compile-flags: --error-format pretty-json -Zunstable-options
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
-{"message":"cannot find type `Iter` in this scope","code":{"code":"E0412","explanation":"/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"},"level":"error","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":862,"byte_end":866,"line_start":20,"line_end":20,"column_start":12,"column_end":16,"is_primary":true,"text":[{"text":" let x: Iter;","highlight_start":12,"highlight_end":16}],"label":"not found in this scope","suggested_replacement":null,"expansion":null}],"children":[{"message":"possible candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::binary_heap::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::linked_list::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::vec_deque::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::option::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::path::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::result::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::slice::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::sync::mpsc::Iter;/n/n","expansion":null}],"children":[],"rendered":null}],"rendered":null}
-{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":null}
+{
+ "message": "cannot find type `Iter` in this scope",
+ "code": {
+ "code": "E0412",
+ "explanation": "/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n type N;/n/n fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n // either/n use super::File;/n // or/n // use std::fs::File;/n fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"
+ },
+ "level": "error",
+ "spans": [
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 888,
+ "byte_end": 892,
+ "line_start": 20,
+ "line_end": 20,
+ "column_start": 12,
+ "column_end": 16,
+ "is_primary": true,
+ "text": [
+ {
+ "text": " let x: Iter;",
+ "highlight_start": 12,
+ "highlight_end": 16
+ }
+ ],
+ "label": "not found in this scope",
+ "suggested_replacement": null,
+ "expansion": null
+ }
+ ],
+ "children": [
+ {
+ "message": "possible candidates are found in other modules, you can import them into scope",
+ "code": null,
+ "level": "help",
+ "spans": [
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::binary_heap::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::btree_map::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::btree_set::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::hash_map::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::hash_set::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::linked_list::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::collections::vec_deque::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::option::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::path::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::result::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::slice::Iter;/n/n",
+ "expansion": null
+ },
+ {
+ "file_name": "$DIR/use_suggestion_json.rs",
+ "byte_start": 865,
+ "byte_end": 865,
+ "line_start": 19,
+ "line_end": 19,
+ "column_start": 1,
+ "column_end": 1,
+ "is_primary": true,
+ "text": [
+ {
+ "text": "fn main() {",
+ "highlight_start": 1,
+ "highlight_end": 1
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "use std::sync::mpsc::Iter;/n/n",
+ "expansion": null
+ }
+ ],
+ "children": [],
+ "rendered": null
+ }
+ ],
+ "rendered": null
+}
+{
+ "message": "aborting due to previous error",
+ "code": null,
+ "level": "error",
+ "spans": [],
+ "children": [],
+ "rendered": null
+}
| |
| expected closure that takes 2 arguments
-error[E0308]: mismatched types
- --> $DIR/closure-arg-count.rs:17:24
- |
-17 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
- | ^^^^^^^^^^^^^^^ expected &{integer}, found tuple
- |
- = note: expected type `&{integer}`
- found type `(_, _)`
-
error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument
--> $DIR/closure-arg-count.rs:17:15
|
| |
| expected closure that takes a single 2-tuple as argument
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ if let Some(y) = &Some(22) {
+ println!("{}", y);
+ }
+}
--- /dev/null
+error: non-reference pattern used to match a reference (see issue #42640)
+ --> $DIR/suggestion.rs:12:12
+ |
+12 | if let Some(y) = &Some(22) {
+ | ^^^^^^^ help: consider using: `&Some(y)`
+ |
+ = help: add #![feature(match_default_bindings)] to the crate attributes to enable
+
+error: aborting due to previous error
+
-Subproject commit 859c2305b5d7ff820d7f7af158bbca999cbd8bf3
+Subproject commit b83550edc300e3d80dd16d0440123ffc1ad77bb9
let status = command
// Disable rust-lang/cargo's cross-compile tests
.env("CFG_DISABLE_CROSS_TESTS", "1")
+ // Relax #![deny(warnings)] in some crates
+ .env("RUSTFLAGS", "--cap-lints warn")
.current_dir(crate_path)
.status()
.expect("");
MirOpt,
}
+impl Mode {
+ pub fn disambiguator(self) -> &'static str {
+ // Run-pass and pretty run-pass tests could run concurrently, and if they do,
+ // they need to keep their output segregated. Same is true for debuginfo tests that
+ // can be run both on gdb and lldb.
+ match self {
+ Pretty => ".pretty",
+ DebugInfoGdb => ".gdb",
+ DebugInfoLldb => ".lldb",
+ _ => "",
+ }
+ }
+}
+
impl FromStr for Mode {
type Err = ();
fn from_str(s: &str) -> Result<Mode, ()> {
fn aux_output_dir_name(&self) -> PathBuf {
let f = self.output_base_name();
let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(&format!(".{}.libaux", self.config.mode));
+ fname.push(&format!("{}.aux", self.config.mode.disambiguator()));
f.with_file_name(&fname)
}
output_file.push(test_name);
debug!("comparing the contests of: {:?}", output_file);
debug!("with: {:?}", expected_content);
+ if !output_file.exists() {
+ panic!("Output file `{}` from test does not exist",
+ output_file.into_os_string().to_string_lossy());
+ }
self.check_mir_test_timestamp(test_name, &output_file);
let mut dumped_file = fs::File::open(output_file.clone()).unwrap();
// We expect each non-empty line to appear consecutively, non-consecutive lines
// must be separated by at least one Elision
+ let mut start_block_line = None;
while let Some(dumped_line) = dumped_lines.next() {
match expected_lines.next() {
- Some(&ExpectedLine::Text(expected_line)) =>
+ Some(&ExpectedLine::Text(expected_line)) => {
+ let normalized_expected_line = normalize_mir_line(expected_line);
+ if normalized_expected_line.contains(":{") {
+ start_block_line = Some(expected_line);
+ }
+
if !compare(expected_line, dumped_line) {
+ error!("{:?}", start_block_line);
error(expected_line,
- format!("Mismatch in lines\nExpected Line: {:?}", dumped_line));
- },
+ format!("Mismatch in lines\nCurrnt block: {}\nExpected Line: {:?}",
+ start_block_line.unwrap_or("None"), dumped_line));
+ }
+ },
Some(&ExpectedLine::Elision) => {
// skip any number of elisions in a row.
while let Some(&&ExpectedLine::Elision) = expected_lines.peek() {
fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
let parent_dir = self.testpaths.file.parent().unwrap();
let cflags = self.props.compile_flags.join(" ");
- let parent_dir_str = if cflags.contains("--error-format json") {
+ let parent_dir_str = if cflags.contains("--error-format json")
+ || cflags.contains("--error-format pretty-json") {
parent_dir.display().to_string().replace("\\", "\\\\")
} else {
parent_dir.display().to_string()
-Subproject commit 48fd42fe92175ce93a5b67f78c195254ee94493d
+Subproject commit 9ad92e134ff56df52481cf19dc3da14b9e735061
-Subproject commit cf0d494dda7447bacaab743a70c47e28bea55c6f
+Subproject commit 51b03c3aaf5e69afbb7508e566c5da2bf0bc3662